[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 6/7] net: Add support for capturing VLANs
From: |
Jan Kiszka |
Subject: |
[Qemu-devel] [PATCH 6/7] net: Add support for capturing VLANs |
Date: |
Tue, 14 Apr 2009 19:29:55 +0200 |
User-agent: |
StGIT/0.14.2 |
This patch is derived from Tristan Gingold's patch. It adds a new VLAN
client type that writes all traffic on the VLAN it is attached to into a
pcap file. Such a file can then be analyzed offline with Wireshark or
tcpdump.
Besides rebasing and some minor cleanups, the major differences to the
original version are:
- support for enabling/disabling via the monitor (host_net_add/remove)
- always register dump client at the head of a VLAN queue
(instead of special handling for slirp)
- 64k default capturing limit (I hate tcpdump's default)
Signed-off-by: Jan Kiszka <address@hidden>
---
monitor.c | 2 -
net.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
net.h | 7 ++
qemu-options.hx | 7 ++
4 files changed, 168 insertions(+), 11 deletions(-)
diff --git a/monitor.c b/monitor.c
index d9f84a7..dc2008a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1731,7 +1731,7 @@ static const mon_cmd_t mon_cmds[] = {
{ "pci_add", "sss", pci_device_hot_add,
"pci_addr=auto|[[<domain>:]<bus>:]<slot> nic|storage
[[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]...",
"hot-add PCI device" },
{ "pci_del", "s", pci_device_hot_remove,
"pci_addr=[[<domain>:]<bus>:]<slot>", "hot remove PCI device" },
{ "host_net_add", "ss?", net_host_device_add,
- "tap|user|socket|vde [options]", "add host VLAN client" },
+ "tap|user|socket|vde|dump [options]", "add host VLAN client" },
{ "host_net_remove", "is", net_host_device_remove,
"vlan_id name", "remove host VLAN client" },
#endif
diff --git a/net.c b/net.c
index e812eb8..d9e986e 100644
--- a/net.c
+++ b/net.c
@@ -118,6 +118,7 @@
#include "qemu-char.h"
#include "audio/audio.h"
#include "qemu_socket.h"
+#include "qemu-log.h"
#if defined(CONFIG_SLIRP)
#include "libslirp.h"
@@ -328,15 +329,16 @@ static char *assign_name(VLANClientState *vc1, const char
*model)
return strdup(buf);
}
-VLANClientState *qemu_new_vlan_client(VLANState *vlan,
- const char *model,
- const char *name,
- IOReadHandler *fd_read,
- IOCanRWHandler *fd_can_read,
- VLANClientCleanupHandler *cleanup,
- void *opaque)
+static VLANClientState *new_vlan_client(VLANState *vlan,
+ const char *model,
+ const char *name,
+ IOReadHandler *fd_read,
+ IOCanRWHandler *fd_can_read,
+ VLANClientCleanupHandler *cleanup,
+ void *opaque)
{
- VLANClientState *vc, **pvc;
+ VLANClientState *vc;
+
vc = qemu_mallocz(sizeof(VLANClientState));
vc->model = strdup(model);
if (name)
@@ -348,6 +350,20 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan,
vc->cleanup = cleanup;
vc->opaque = opaque;
vc->vlan = vlan;
+ return vc;
+}
+
+VLANClientState *qemu_new_vlan_client(VLANState *vlan,
+ const char *model,
+ const char *name,
+ IOReadHandler *fd_read,
+ IOCanRWHandler *fd_can_read,
+ VLANClientCleanupHandler *cleanup,
+ void *opaque)
+{
+ VLANClientState *vc, **pvc;
+ vc = new_vlan_client(vlan, model, name, fd_read, fd_can_read, cleanup,
+ opaque);
vc->next = NULL;
pvc = &vlan->first_client;
@@ -357,6 +373,23 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan,
return vc;
}
+VLANClientState *qemu_new_vlan_head_client(VLANState *vlan,
+ const char *model,
+ const char *name,
+ IOReadHandler *fd_read,
+ IOCanRWHandler *fd_can_read,
+ VLANClientCleanupHandler *cleanup,
+ void *opaque)
+{
+ VLANClientState *vc;
+ vc = new_vlan_client(vlan, model, name, fd_read, fd_can_read, cleanup,
+ opaque);
+
+ vc->next = vlan->first_client;
+ vlan->first_client = vc;
+ return vc;
+}
+
void qemu_del_vlan_client(VLANClientState *vc)
{
VLANClientState **pvc = &vc->vlan->first_client;
@@ -1571,6 +1604,106 @@ static int net_socket_mcast_init(VLANState *vlan,
}
+typedef struct DumpState {
+ VLANClientState *pcap_vc;
+ int fd;
+ int pcap_caplen;
+} DumpState;
+
+#define PCAP_MAGIC 0xa1b2c3d4
+
+struct pcap_file_hdr {
+ uint32_t magic;
+ uint16_t version_major;
+ uint16_t version_minor;
+ int32_t thiszone;
+ uint32_t sigfigs;
+ uint32_t snaplen;
+ uint32_t linktype;
+};
+
+struct pcap_sf_pkthdr {
+ struct {
+ int32_t tv_sec;
+ int32_t tv_usec;
+ } ts;
+ uint32_t caplen;
+ uint32_t len;
+};
+
+static void dump_receive(void *opaque, const uint8_t *buf, int size)
+{
+ DumpState *s = opaque;
+ struct pcap_sf_pkthdr hdr;
+ int64_t ts;
+ int caplen;
+
+ /* Early return in case of previous error. */
+ if (s->fd < 0) {
+ return;
+ }
+
+ ts = muldiv64 (qemu_get_clock(vm_clock),1000000, ticks_per_sec);
+ caplen = size > s->pcap_caplen ? s->pcap_caplen : size;
+
+ hdr.ts.tv_sec = ts / 1000000000LL;
+ hdr.ts.tv_usec = ts % 1000000;
+ hdr.caplen = caplen;
+ hdr.len = size;
+ if (write(s->fd, &hdr, sizeof(hdr)) != sizeof(hdr) ||
+ write(s->fd, buf, caplen) != caplen) {
+ qemu_log("-net dump write error - stop dump\n");
+ close(s->fd);
+ s->fd = -1;
+ }
+}
+
+static void net_dump_cleanup(void *opaque)
+{
+ DumpState *s = opaque;
+
+ close(s->fd);
+ qemu_free(s);
+}
+
+static int net_dump_init(VLANState *vlan, const char *device,
+ const char *name, const char *filename, int len)
+{
+ struct pcap_file_hdr hdr;
+ DumpState *s;
+
+ s = qemu_malloc(sizeof(DumpState));
+
+ s->fd = open(filename, O_CREAT | O_WRONLY, 0644);
+ if (s->fd < 0) {
+ fprintf(stderr, "-net dump: can't open %s\n", filename);
+ return -1;
+ }
+
+ s->pcap_caplen = len;
+
+ hdr.magic = PCAP_MAGIC;
+ hdr.version_major = 2;
+ hdr.version_minor = 4;
+ hdr.thiszone = 0;
+ hdr.sigfigs = 0;
+ hdr.snaplen = s->pcap_caplen;
+ hdr.linktype = 1;
+
+ if (write(s->fd, &hdr, sizeof(hdr)) < sizeof(hdr)) {
+ perror("-net dump write error");
+ close(s->fd);
+ qemu_free(s);
+ return -1;
+ }
+
+ s->pcap_vc = qemu_new_vlan_head_client(vlan, device, name, dump_receive,
+ NULL, net_dump_cleanup, s);
+ snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str),
+ "dump to %s (len=%d)", filename, len);
+ return 0;
+}
+
/* find or alloc a new VLAN */
VLANState *qemu_find_vlan(int id)
{
@@ -1811,7 +1944,17 @@ int net_client_init(const char *device, const char *p)
ret = net_vde_init(vlan, device, name, vde_sock, vde_port, vde_group,
vde_mode);
} else
#endif
- {
+ if (!strcmp(device, "dump")) {
+ int len = 65536;
+
+ if (get_param_value(buf, sizeof(buf), "len", p) > 0) {
+ len = strtol(buf, NULL, 0);
+ }
+ if (!get_param_value(buf, sizeof(buf), "file", p)) {
+ snprintf(buf, sizeof(buf), "qemu-vlan%d.pcap", vlan_id);
+ }
+ ret = net_dump_init(vlan, device, name, buf, len);
+ } else {
fprintf(stderr, "Unknown network device: %s\n", device);
if (name)
free(name);
@@ -1836,7 +1979,7 @@ void net_client_uninit(NICInfo *nd)
static int net_host_check_device(const char *device)
{
int i;
- const char *valid_param_list[] = { "tap", "socket"
+ const char *valid_param_list[] = { "tap", "socket", "dump"
#ifdef CONFIG_SLIRP
,"user"
#endif
diff --git a/net.h b/net.h
index 571305b..6560d0d 100644
--- a/net.h
+++ b/net.h
@@ -45,6 +45,13 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan,
IOCanRWHandler *fd_can_read,
VLANClientCleanupHandler *cleanup,
void *opaque);
+VLANClientState *qemu_new_vlan_head_client(VLANState *vlan,
+ const char *model,
+ const char *name,
+ IOReadHandler *fd_read,
+ IOCanRWHandler *fd_can_read,
+ VLANClientCleanupHandler *cleanup,
+ void *opaque);
void qemu_del_vlan_client(VLANClientState *vc);
VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque);
int qemu_can_send_packet(VLANClientState *vc);
diff --git a/qemu-options.hx b/qemu-options.hx
index f551775..ab19bd3 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -724,6 +724,8 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, \
" Use group 'groupname' and mode 'octalmode' to change
default\n"
" ownership and permissions for communication port.\n"
#endif
+ "-net dump[,vlan=n][,file=f][,len=n]\n"
+ " dump traffic on vlan 'n' to file 'f' (max n bytes per
packet)\n"
"-net none use it alone to have zero network devices; if no -net
option\n"
" is provided, the default is '-net nic -net user'\n")
STEXI
@@ -844,6 +846,11 @@ vde_switch -F -sock /tmp/myswitch
qemu linux.img -net nic -net vde,sock=/tmp/myswitch
@end example
address@hidden -net dump[,address@hidden,address@hidden,address@hidden
+Dump network traffic on VLAN @var{n} to file @var{file}
(@file{qemu-vlan0.pcap} by default).
+At most @var{len} bytes (64k by default) per packet are stored. The file
format is
+libpcap, so it can be analyzed with tools such as tcpdump or Wireshark.
+
@item -net none
Indicate that no network devices should be configured. It is used to
override the default configuration (@option{-net nic -net user}) which
- [Qemu-devel] Re: [PATCH 2/7] net: Add VLAN client cleanup handler, (continued)
[Qemu-devel] [PATCH 3/7] net: Check device passed to host_net_remove, Jan Kiszka, 2009/04/14
[Qemu-devel] [PATCH 7/7] slirp: Handle DHCP requests for specific IP, Jan Kiszka, 2009/04/14
[Qemu-devel] [PATCH 5/7] monitor: Improve host_net_add, Jan Kiszka, 2009/04/14
[Qemu-devel] [PATCH 6/7] net: Add support for capturing VLANs,
Jan Kiszka <=