qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [7200] net: Add support for capturing VLANs (Jan Kiszka)


From: Anthony Liguori
Subject: [Qemu-devel] [7200] net: Add support for capturing VLANs (Jan Kiszka)
Date: Tue, 21 Apr 2009 19:56:29 +0000

Revision: 7200
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=7200
Author:   aliguori
Date:     2009-04-21 19:56:28 +0000 (Tue, 21 Apr 2009)
Log Message:
-----------
net: Add support for capturing VLANs (Jan Kiszka)

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)
 - no special ordering of VLAN client list, qemu_send_packet now takes
   care of properly ordered packets
 - 64k default capturing limit (I hate tcpdump's default)

Signed-off-by: Jan Kiszka <address@hidden>
Signed-off-by: Anthony Liguori <address@hidden>

Modified Paths:
--------------
    trunk/monitor.c
    trunk/net.c
    trunk/qemu-options.hx

Modified: trunk/monitor.c
===================================================================
--- trunk/monitor.c     2009-04-21 19:56:23 UTC (rev 7199)
+++ trunk/monitor.c     2009-04-21 19:56:28 UTC (rev 7200)
@@ -1731,7 +1731,7 @@
     { "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

Modified: trunk/net.c
===================================================================
--- trunk/net.c 2009-04-21 19:56:23 UTC (rev 7199)
+++ trunk/net.c 2009-04-21 19:56:28 UTC (rev 7200)
@@ -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"
@@ -1558,6 +1559,106 @@
 
 }
 
+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(VLANClientState *vc)
+{
+    DumpState *s = vc->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_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)
 {
@@ -1883,7 +1984,17 @@
        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);
         ret = -1;
         goto out;
@@ -1908,7 +2019,7 @@
 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

Modified: trunk/qemu-options.hx
===================================================================
--- trunk/qemu-options.hx       2009-04-21 19:56:23 UTC (rev 7199)
+++ trunk/qemu-options.hx       2009-04-21 19:56:28 UTC (rev 7200)
@@ -745,6 +745,8 @@
     "                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
@@ -865,6 +867,11 @@
 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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]