From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LvTzr-0006I3-KE for qemu-devel@nongnu.org; Sun, 19 Apr 2009 06:11:35 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LvTzp-0006Gj-Oe for qemu-devel@nongnu.org; Sun, 19 Apr 2009 06:11:35 -0400 Received: from [199.232.76.173] (port=36643 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LvTzp-0006GP-FE for qemu-devel@nongnu.org; Sun, 19 Apr 2009 06:11:33 -0400 Received: from mx20.gnu.org ([199.232.41.8]:3767) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1LvTzo-0001pU-Gn for qemu-devel@nongnu.org; Sun, 19 Apr 2009 06:11:33 -0400 Received: from fmmailgate01.web.de ([217.72.192.221]) by mx20.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LvTzn-0007di-HC for qemu-devel@nongnu.org; Sun, 19 Apr 2009 06:11:32 -0400 Resent-To: qemu-devel Resent-Message-Id: <49EAF8D1.30809@web.de> From: Jan Kiszka Date: Sun, 19 Apr 2009 12:04:26 +0200 Message-ID: <20090419100426.24240.73822.stgit@mchn012c.ww002.siemens.net> In-Reply-To: <20090419100424.24240.51439.stgit@mchn012c.ww002.siemens.net> References: <20090419100424.24240.51439.stgit@mchn012c.ww002.siemens.net> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Sender: jan.kiszka@web.de Subject: [Qemu-devel] [PATCH v2 09/11] net: Add support for capturing VLANs Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Mark McLoughlin 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 --- monitor.c | 2 - net.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- qemu-options.hx | 7 +++ 3 files changed, 121 insertions(+), 3 deletions(-) diff --git a/monitor.c b/monitor.c index e5991ff..0accded 100644 --- a/monitor.c +++ b/monitor.c @@ -1732,7 +1732,7 @@ static const mon_cmd_t mon_cmds[] = { { "pci_del", "s", pci_device_hot_remove, "pci_addr=[[:]:]", "hot remove PCI device" }, #endif { "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" }, { "balloon", "i", do_balloon, diff --git a/net.c b/net.c index 5156cc1..8d688a0 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" @@ -1594,6 +1595,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(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) { @@ -1919,7 +2020,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); ret = -1; goto out; @@ -1944,7 +2055,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/qemu-options.hx b/qemu-options.hx index 4d15f9b..a29d1da 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -745,6 +745,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 @@ -865,6 +867,11 @@ vde_switch -F -sock /tmp/myswitch qemu linux.img -net nic -net vde,sock=/tmp/myswitch @end example +@item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}] +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