diff mbox

[RFC,2/4] net: Introduce NetClientDump and auxiliary functions

Message ID 1279225380-28790-3-git-send-email-miguel.filho@gmail.com
State New
Headers show

Commit Message

Miguel Di Ciurcio Filho July 15, 2010, 8:22 p.m. UTC
Signed-off-by: Miguel Di Ciurcio Filho <miguel.filho@gmail.com>
---
 net.c         |   90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 net.h         |    8 +++++
 qemu-common.h |    1 +
 3 files changed, 99 insertions(+), 0 deletions(-)
diff mbox

Patch

diff --git a/net.c b/net.c
index 8ddf872..6f125f8 100644
--- a/net.c
+++ b/net.c
@@ -42,6 +42,36 @@  static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
 
 int default_net = 1;
 
+static void pcap_dump(NetClientDump *net_client_dump, const uint8_t *buf, size_t size)
+{
+    struct pcap_sf_pkthdr hdr;
+    int64_t ts;
+    int caplen;
+
+    if (!net_client_dump) {
+        return;
+    }
+
+    /* Early return in case of previous error. */
+    if (net_client_dump->fd < 0) {
+        return;
+    }
+
+    ts = muldiv64(qemu_get_clock(vm_clock), 1000000, get_ticks_per_sec());
+    caplen = size > net_client_dump->pcap_caplen ? net_client_dump->pcap_caplen : size;
+
+    hdr.ts.tv_sec = ts / 1000000;
+    hdr.ts.tv_usec = ts % 1000000;
+    hdr.caplen = caplen;
+    hdr.len = size;
+    if (write(net_client_dump->fd, &hdr, sizeof(hdr)) != sizeof(hdr) ||
+        write(net_client_dump->fd, buf, caplen) != caplen) {
+        error_report("Error writing pcap dump, closing descriptor.");
+        close(net_client_dump->fd);
+        net_client_dump->fd = -1;
+    }
+}
+
 /***********************************************************/
 /* network device redirectors */
 
@@ -495,6 +525,7 @@  static ssize_t qemu_send_packet_async_with_flags(VLANClientState *sender,
                                                  NetPacketSent *sent_cb)
 {
     NetQueue *queue;
+    NetClientDump *dump;
 
 #ifdef DEBUG_NET
     printf("qemu_send_packet_async:\n");
@@ -507,6 +538,14 @@  static ssize_t qemu_send_packet_async_with_flags(VLANClientState *sender,
 
     if (sender->peer) {
         queue = sender->peer->send_queue;
+        if (sender->dump || sender->peer->dump) {
+            if (sender->dump) {
+                dump = sender->dump;
+            } else {
+                dump = sender->peer->dump;
+            }
+            pcap_dump(dump, buf, size);
+        }
     } else {
         queue = sender->vlan->send_queue;
     }
@@ -621,6 +660,8 @@  ssize_t qemu_sendv_packet_async(VLANClientState *sender,
                                 NetPacketSent *sent_cb)
 {
     NetQueue *queue;
+    NetClientDump *dump;
+    int i;
 
     if (sender->link_down || (!sender->peer && !sender->vlan)) {
         return calc_iov_length(iov, iovcnt);
@@ -628,6 +669,17 @@  ssize_t qemu_sendv_packet_async(VLANClientState *sender,
 
     if (sender->peer) {
         queue = sender->peer->send_queue;
+        if (sender->dump || sender->peer->dump) {
+            if (sender->dump) {
+                dump = sender->dump;
+            } else {
+                dump = sender->peer->dump;
+            }
+            /* XXX handle vnet_hdr headers or dump will be corrupt */
+            for (i = 0; i < iovcnt; i++) {
+                pcap_dump(dump, (const uint8_t*)iov[i].iov_base, iov[i].iov_len);
+            }
+        }
     } else {
         queue = sender->vlan->send_queue;
     }
@@ -1347,6 +1399,44 @@  static int net_init_netdev(QemuOpts *opts, void *dummy)
     return net_client_init(NULL, opts, 1);
 }
 
+NetClientDump *net_client_create_dump(const char *filename, int len) {
+    NetClientDump *net_client_dump;
+    struct pcap_file_hdr hdr;
+    int fd;
+
+    fd = open(filename, O_CREAT | O_WRONLY | O_BINARY, 0644);
+    if (fd < 0) {
+        error_report("Cannot create dump file: %s", filename);
+        return NULL;
+    }
+
+    if (!len) {
+        len = 65536;
+    }
+
+    hdr.magic = PCAP_MAGIC;
+    hdr.version_major = 2;
+    hdr.version_minor = 4;
+    hdr.thiszone = 0;
+    hdr.sigfigs = 0;
+    hdr.snaplen = len;
+    hdr.linktype = 1;
+
+    if (write(fd, &hdr, sizeof(hdr)) < sizeof(hdr)) {
+        error_report("Error writing dump file error: %s", strerror(errno));
+        close(fd);
+        return NULL;
+    }
+
+    net_client_dump = qemu_malloc(sizeof(NetClientDump));
+    net_client_dump->fd = fd;
+    net_client_dump->pcap_caplen = len;
+    pstrcpy(net_client_dump->filename, sizeof(char[128]), filename);
+
+    return net_client_dump;
+
+}
+
 int net_init_clients(void)
 {
     if (default_net) {
diff --git a/net.h b/net.h
index 518cf9c..9a95db5 100644
--- a/net.h
+++ b/net.h
@@ -55,6 +55,12 @@  typedef struct NetClientInfo {
     NetPoll *poll;
 } NetClientInfo;
 
+struct NetClientDump {
+    int fd;
+    int pcap_caplen;
+    char filename[128];
+};
+
 struct VLANClientState {
     NetClientInfo *info;
     int link_down;
@@ -66,6 +72,7 @@  struct VLANClientState {
     char *name;
     char info_str[256];
     unsigned receive_disabled : 1;
+    NetClientDump *dump;
 };
 
 typedef struct NICState {
@@ -81,6 +88,7 @@  struct VLANState {
     NetQueue *send_queue;
 };
 
+NetClientDump *net_client_create_dump(const char *filename, int len);
 VLANState *qemu_find_vlan(int id, int allocate);
 VLANClientState *qemu_find_netdev(const char *id);
 VLANClientState *qemu_new_net_client(NetClientInfo *info,
diff --git a/qemu-common.h b/qemu-common.h
index 3fb2f0b..7354775 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -212,6 +212,7 @@  typedef struct CharDriverState CharDriverState;
 typedef struct MACAddr MACAddr;
 typedef struct VLANState VLANState;
 typedef struct VLANClientState VLANClientState;
+typedef struct NetClientDump NetClientDump;
 typedef struct i2c_bus i2c_bus;
 typedef struct i2c_slave i2c_slave;
 typedef struct SMBusDevice SMBusDevice;