Signed-off-by: Miguel Di Ciurcio Filho <miguel.fi...@gmail.com> --- net.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ net.h | 8 +++++ qemu-common.h | 1 + 3 files changed, 99 insertions(+), 0 deletions(-)
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; -- 1.7.1