* [Qemu-devel] [PATCH 0/5] Network traffic dumping via netfilter @ 2015-09-24 7:22 Thomas Huth 2015-09-24 7:22 ` [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function Thomas Huth ` (4 more replies) 0 siblings, 5 replies; 12+ messages in thread From: Thomas Huth @ 2015-09-24 7:22 UTC (permalink / raw) To: qemu-devel, jasowang; +Cc: yanghy, armbru, stefanha, mst The "-net dump" option only works with the "-net" option. So far, it is not possible to dump network traffic with the "-netdev" option yet. This patch series now fixes this ugliness by enabling dumping for the netdev devices via the new netfilter infrastructure from Yang Hongyang (integration into that infrastructure was pretty easy, so thanks for this great work!) The dumping filter can be used like this for example: ppc64-softmmu/qemu-system-ppc64 -device virtio-net,netdev=mynet \ -netdev user,id=mynet,tftp=/tmp/tftp,bootfile=zImage \ -object filter-dump,id=f0,netdev=mynet,file=/tmp/dumpfile.dat The patches have to be applied on top of the Jason's net branch (since the netfilter patches have not been pulled into master yet). Thomas Huth (5): net/dump: Add support for receive_iov function net/dump: Rework net-dump init functions net/dump: Separate the NetClientState from the DumpState net/dump: Provide the dumping facility as a net filter net/dump: Add documentation net/dump.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++-------- qemu-options.hx | 8 ++ vl.c | 8 +- 3 files changed, 212 insertions(+), 32 deletions(-) -- 1.8.3.1 ^ permalink raw reply [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function 2015-09-24 7:22 [Qemu-devel] [PATCH 0/5] Network traffic dumping via netfilter Thomas Huth @ 2015-09-24 7:22 ` Thomas Huth 2015-09-24 7:22 ` [Qemu-devel] [PATCH 2/5] net/dump: Rework net-dump init functions Thomas Huth ` (3 subsequent siblings) 4 siblings, 0 replies; 12+ messages in thread From: Thomas Huth @ 2015-09-24 7:22 UTC (permalink / raw) To: qemu-devel, jasowang; +Cc: yanghy, armbru, stefanha, mst Adding a proper receive_iov function to the net dump module. This will make it easier to support the dump filter feature for the -netdev option in later patches. Signed-off-by: Thomas Huth <thuth@redhat.com> --- net/dump.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/net/dump.c b/net/dump.c index 02c8064..f8afb83 100644 --- a/net/dump.c +++ b/net/dump.c @@ -25,6 +25,7 @@ #include "clients.h" #include "qemu-common.h" #include "qemu/error-report.h" +#include "qemu/iov.h" #include "qemu/log.h" #include "qemu/timer.h" #include "hub.h" @@ -57,12 +58,15 @@ struct pcap_sf_pkthdr { uint32_t len; }; -static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) +static ssize_t dump_receive_iov(NetClientState *nc, const struct iovec *iov, + int cnt) { DumpState *s = DO_UPCAST(DumpState, nc, nc); struct pcap_sf_pkthdr hdr; int64_t ts; int caplen; + size_t size = iov_size(iov, cnt); + struct iovec dumpiov[cnt + 1]; /* Early return in case of previous error. */ if (s->fd < 0) { @@ -76,8 +80,12 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) 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) { + + dumpiov[0].iov_base = &hdr; + dumpiov[0].iov_len = sizeof(hdr); + cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, 0, caplen); + + if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) { qemu_log("-net dump write error - stop dump\n"); close(s->fd); s->fd = -1; @@ -86,6 +94,15 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) return size; } +static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) +{ + struct iovec iov = { + .iov_base = (void *)buf, + .iov_len = size + }; + return dump_receive_iov(nc, &iov, 1); +} + static void dump_cleanup(NetClientState *nc) { DumpState *s = DO_UPCAST(DumpState, nc, nc); @@ -97,6 +114,7 @@ static NetClientInfo net_dump_info = { .type = NET_CLIENT_OPTIONS_KIND_DUMP, .size = sizeof(DumpState), .receive = dump_receive, + .receive_iov = dump_receive_iov, .cleanup = dump_cleanup, }; -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH 2/5] net/dump: Rework net-dump init functions 2015-09-24 7:22 [Qemu-devel] [PATCH 0/5] Network traffic dumping via netfilter Thomas Huth 2015-09-24 7:22 ` [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function Thomas Huth @ 2015-09-24 7:22 ` Thomas Huth 2015-09-24 7:22 ` [Qemu-devel] [PATCH 3/5] net/dump: Separate the NetClientState from the DumpState Thomas Huth ` (2 subsequent siblings) 4 siblings, 0 replies; 12+ messages in thread From: Thomas Huth @ 2015-09-24 7:22 UTC (permalink / raw) To: qemu-devel, jasowang; +Cc: yanghy, armbru, stefanha, mst Move the creation of the dump client from net_dump_init() into net_init_dump(), so we can later use the former function for dump via netfilter, too. Also rename net_dump_init() to net_dump_state_init() to make it easier distinguishable from net_init_dump(). Signed-off-by: Thomas Huth <thuth@redhat.com> --- net/dump.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/net/dump.c b/net/dump.c index f8afb83..27083d4 100644 --- a/net/dump.c +++ b/net/dump.c @@ -118,13 +118,10 @@ static NetClientInfo net_dump_info = { .cleanup = dump_cleanup, }; -static int net_dump_init(NetClientState *peer, const char *device, - const char *name, const char *filename, int len, - Error **errp) +static int net_dump_state_init(DumpState *s, const char *filename, + int len, Error **errp) { struct pcap_file_hdr hdr; - NetClientState *nc; - DumpState *s; struct tm tm; int fd; @@ -148,13 +145,6 @@ static int net_dump_init(NetClientState *peer, const char *device, return -1; } - nc = qemu_new_net_client(&net_dump_info, peer, device, name); - - snprintf(nc->info_str, sizeof(nc->info_str), - "dump to %s (len=%d)", filename, len); - - s = DO_UPCAST(DumpState, nc, nc); - s->fd = fd; s->pcap_caplen = len; @@ -167,10 +157,11 @@ static int net_dump_init(NetClientState *peer, const char *device, int net_init_dump(const NetClientOptions *opts, const char *name, NetClientState *peer, Error **errp) { - int len; + int len, rc; const char *file; char def_file[128]; const NetdevDumpOptions *dump; + NetClientState *nc; assert(opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP); dump = opts->dump; @@ -200,5 +191,13 @@ int net_init_dump(const NetClientOptions *opts, const char *name, len = 65536; } - return net_dump_init(peer, "dump", name, file, len, errp); + nc = qemu_new_net_client(&net_dump_info, peer, "dump", name); + snprintf(nc->info_str, sizeof(nc->info_str), + "dump to %s (len=%d)", file, len); + + rc = net_dump_state_init(DO_UPCAST(DumpState, nc, nc), file, len, errp); + if (rc) { + qemu_del_net_client(nc); + } + return rc; } -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH 3/5] net/dump: Separate the NetClientState from the DumpState 2015-09-24 7:22 [Qemu-devel] [PATCH 0/5] Network traffic dumping via netfilter Thomas Huth 2015-09-24 7:22 ` [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function Thomas Huth 2015-09-24 7:22 ` [Qemu-devel] [PATCH 2/5] net/dump: Rework net-dump init functions Thomas Huth @ 2015-09-24 7:22 ` Thomas Huth 2015-09-24 7:22 ` [Qemu-devel] [PATCH 4/5] net/dump: Provide the dumping facility as a net filter Thomas Huth 2015-09-24 7:22 ` [Qemu-devel] [PATCH 5/5] net/dump: Add documentation Thomas Huth 4 siblings, 0 replies; 12+ messages in thread From: Thomas Huth @ 2015-09-24 7:22 UTC (permalink / raw) To: qemu-devel, jasowang; +Cc: yanghy, armbru, stefanha, mst With the upcoming dumping-via-netfilter patch, the DumpState should not be related to NetClientState anymore, so move the related information to a new struct called DumpNetClient. Signed-off-by: Thomas Huth <thuth@redhat.com> --- net/dump.c | 74 +++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/net/dump.c b/net/dump.c index 27083d4..afff78e 100644 --- a/net/dump.c +++ b/net/dump.c @@ -31,7 +31,6 @@ #include "hub.h" typedef struct DumpState { - NetClientState nc; int64_t start_ts; int fd; int pcap_caplen; @@ -58,10 +57,8 @@ struct pcap_sf_pkthdr { uint32_t len; }; -static ssize_t dump_receive_iov(NetClientState *nc, const struct iovec *iov, - int cnt) +static ssize_t dump_receive_iov(DumpState *s, const struct iovec *iov, int cnt) { - DumpState *s = DO_UPCAST(DumpState, nc, nc); struct pcap_sf_pkthdr hdr; int64_t ts; int caplen; @@ -94,30 +91,12 @@ static ssize_t dump_receive_iov(NetClientState *nc, const struct iovec *iov, return size; } -static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) -{ - struct iovec iov = { - .iov_base = (void *)buf, - .iov_len = size - }; - return dump_receive_iov(nc, &iov, 1); -} - -static void dump_cleanup(NetClientState *nc) +static void dump_cleanup(DumpState *s) { - DumpState *s = DO_UPCAST(DumpState, nc, nc); - close(s->fd); + s->fd = -1; } -static NetClientInfo net_dump_info = { - .type = NET_CLIENT_OPTIONS_KIND_DUMP, - .size = sizeof(DumpState), - .receive = dump_receive, - .receive_iov = dump_receive_iov, - .cleanup = dump_cleanup, -}; - static int net_dump_state_init(DumpState *s, const char *filename, int len, Error **errp) { @@ -154,6 +133,49 @@ static int net_dump_state_init(DumpState *s, const char *filename, return 0; } +/* Dumping via VLAN netclient */ + +struct DumpNetClient { + NetClientState nc; + DumpState ds; +}; +typedef struct DumpNetClient DumpNetClient; + +static ssize_t dumpclient_receive(NetClientState *nc, const uint8_t *buf, + size_t size) +{ + DumpNetClient *dc = DO_UPCAST(DumpNetClient, nc, nc); + struct iovec iov = { + .iov_base = (void *)buf, + .iov_len = size + }; + + return dump_receive_iov(&dc->ds, &iov, 1); +} + +static ssize_t dumpclient_receive_iov(NetClientState *nc, + const struct iovec *iov, int cnt) +{ + DumpNetClient *dc = DO_UPCAST(DumpNetClient, nc, nc); + + return dump_receive_iov(&dc->ds, iov, cnt); +} + +static void dumpclient_cleanup(NetClientState *nc) +{ + DumpNetClient *dc = DO_UPCAST(DumpNetClient, nc, nc); + + dump_cleanup(&dc->ds); +} + +static NetClientInfo net_dump_info = { + .type = NET_CLIENT_OPTIONS_KIND_DUMP, + .size = sizeof(DumpNetClient), + .receive = dumpclient_receive, + .receive_iov = dumpclient_receive_iov, + .cleanup = dumpclient_cleanup, +}; + int net_init_dump(const NetClientOptions *opts, const char *name, NetClientState *peer, Error **errp) { @@ -162,6 +184,7 @@ int net_init_dump(const NetClientOptions *opts, const char *name, char def_file[128]; const NetdevDumpOptions *dump; NetClientState *nc; + DumpNetClient *dnc; assert(opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP); dump = opts->dump; @@ -195,7 +218,8 @@ int net_init_dump(const NetClientOptions *opts, const char *name, snprintf(nc->info_str, sizeof(nc->info_str), "dump to %s (len=%d)", file, len); - rc = net_dump_state_init(DO_UPCAST(DumpState, nc, nc), file, len, errp); + dnc = DO_UPCAST(DumpNetClient, nc, nc); + rc = net_dump_state_init(&dnc->ds, file, len, errp); if (rc) { qemu_del_net_client(nc); } -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH 4/5] net/dump: Provide the dumping facility as a net filter 2015-09-24 7:22 [Qemu-devel] [PATCH 0/5] Network traffic dumping via netfilter Thomas Huth ` (2 preceding siblings ...) 2015-09-24 7:22 ` [Qemu-devel] [PATCH 3/5] net/dump: Separate the NetClientState from the DumpState Thomas Huth @ 2015-09-24 7:22 ` Thomas Huth 2015-09-24 8:20 ` Yang Hongyang 2015-09-24 7:22 ` [Qemu-devel] [PATCH 5/5] net/dump: Add documentation Thomas Huth 4 siblings, 1 reply; 12+ messages in thread From: Thomas Huth @ 2015-09-24 7:22 UTC (permalink / raw) To: qemu-devel, jasowang; +Cc: yanghy, armbru, stefanha, mst Use the net filter infrastructure to provide the dumping functions for netdev devices, too. Signed-off-by: Thomas Huth <thuth@redhat.com> --- net/dump.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- vl.c | 8 +++- 2 files changed, 134 insertions(+), 3 deletions(-) diff --git a/net/dump.c b/net/dump.c index afff78e..5904f58 100644 --- a/net/dump.c +++ b/net/dump.c @@ -28,7 +28,8 @@ #include "qemu/iov.h" #include "qemu/log.h" #include "qemu/timer.h" -#include "hub.h" +#include "qapi/visitor.h" +#include "net/filter.h" typedef struct DumpState { int64_t start_ts; @@ -225,3 +226,129 @@ int net_init_dump(const NetClientOptions *opts, const char *name, } return rc; } + +/* Dumping via filter */ + +#define TYPE_FILTER_DUMP "filter-dump" + +#define FILTER_DUMP(obj) \ + OBJECT_CHECK(NetFilterDumpState, (obj), TYPE_FILTER_DUMP) + +struct NetFilterDumpState { + NetFilterState nfs; + DumpState ds; + char *filename; + uint32_t maxlen; +}; +typedef struct NetFilterDumpState NetFilterDumpState; + +static ssize_t filter_dump_receive_iov(NetFilterState *nf, NetClientState *sndr, + unsigned flags, const struct iovec *iov, + int iovcnt, NetPacketSent *sent_cb) +{ + NetFilterDumpState *nfds = FILTER_DUMP(nf); + + dump_receive_iov(&nfds->ds, iov, iovcnt); + return 0; +} + +static void filter_dump_cleanup(NetFilterState *nf) +{ + NetFilterDumpState *nfds = FILTER_DUMP(nf); + + dump_cleanup(&nfds->ds); +} + +static void filter_dump_setup(NetFilterState *nf, Error **errp) +{ + NetFilterDumpState *nfds = FILTER_DUMP(nf); + + if (!nfds->filename) { + error_setg(errp, "dump filter needs 'file' property set!"); + return; + } + + net_dump_state_init(&nfds->ds, nfds->filename, nfds->maxlen, errp); +} + +static void filter_dump_get_maxlen(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + NetFilterDumpState *nfds = FILTER_DUMP(obj); + uint32_t value = nfds->maxlen; + + visit_type_uint32(v, &value, name, errp); +} + +static void filter_dump_set_maxlen(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + NetFilterDumpState *nfds = FILTER_DUMP(obj); + Error *local_err = NULL; + uint32_t value; + + visit_type_uint32(v, &value, name, &local_err); + if (local_err) { + goto out; + } + if (value == 0) { + error_setg(&local_err, "Property '%s.%s' doesn't take value '%u'", + object_get_typename(obj), name, value); + goto out; + } + nfds->maxlen = value; + +out: + error_propagate(errp, local_err); +} + +static char *file_dump_get_filename(Object *obj, Error **errp) +{ + NetFilterDumpState *nfds = FILTER_DUMP(obj); + + return g_strdup(nfds->filename); +} + +static void file_dump_set_filename(Object *obj, const char *value, Error **errp) +{ + NetFilterDumpState *nfds = FILTER_DUMP(obj); + + g_free(nfds->filename); + nfds->filename = g_strdup(value); +} + +static void filter_dump_instance_init(Object *obj) +{ + NetFilterDumpState *nfds = FILTER_DUMP(obj); + + nfds->maxlen = 65536; + + object_property_add(obj, "maxlen", "int", filter_dump_get_maxlen, + filter_dump_set_maxlen, NULL, NULL, NULL); + object_property_add_str(obj, "file", file_dump_get_filename, + file_dump_set_filename, NULL); +} + +static void filter_dump_class_init(ObjectClass *oc, void *data) +{ + NetFilterClass *nfc = NETFILTER_CLASS(oc); + + nfc->setup = filter_dump_setup; + nfc->cleanup = filter_dump_cleanup; + nfc->receive_iov = filter_dump_receive_iov; +} + +static const TypeInfo filter_dump_info = { + .name = TYPE_FILTER_DUMP, + .parent = TYPE_NETFILTER, + .class_init = filter_dump_class_init, + .instance_init = filter_dump_instance_init, + .instance_size = sizeof(NetFilterDumpState), +}; + +static void filter_dump_register_types(void) +{ + type_register_static(&filter_dump_info); +} + +type_init(filter_dump_register_types); diff --git a/vl.c b/vl.c index 9be4d22..aa99ef3 100644 --- a/vl.c +++ b/vl.c @@ -2761,8 +2761,12 @@ static bool object_create_initial(const char *type) return false; } - /* return false for concrete netfilters */ - if (g_str_equal(type, "filter-buffer")) { + /* + * return false for concrete netfilters since + * they depend on netdevs already existing + */ + if (g_str_equal(type, "filter-buffer") || + g_str_equal(type, "filter-dump")) { return false; } -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH 4/5] net/dump: Provide the dumping facility as a net filter 2015-09-24 7:22 ` [Qemu-devel] [PATCH 4/5] net/dump: Provide the dumping facility as a net filter Thomas Huth @ 2015-09-24 8:20 ` Yang Hongyang 0 siblings, 0 replies; 12+ messages in thread From: Yang Hongyang @ 2015-09-24 8:20 UTC (permalink / raw) To: Thomas Huth, qemu-devel, jasowang; +Cc: armbru, stefanha, mst The filter interface part looks good to me, thanks! On 09/24/2015 03:22 PM, Thomas Huth wrote: > Use the net filter infrastructure to provide the dumping > functions for netdev devices, too. > > Signed-off-by: Thomas Huth <thuth@redhat.com> > --- > net/dump.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- > vl.c | 8 +++- > 2 files changed, 134 insertions(+), 3 deletions(-) > > diff --git a/net/dump.c b/net/dump.c > index afff78e..5904f58 100644 > --- a/net/dump.c > +++ b/net/dump.c > @@ -28,7 +28,8 @@ > #include "qemu/iov.h" > #include "qemu/log.h" > #include "qemu/timer.h" > -#include "hub.h" > +#include "qapi/visitor.h" > +#include "net/filter.h" > > typedef struct DumpState { > int64_t start_ts; > @@ -225,3 +226,129 @@ int net_init_dump(const NetClientOptions *opts, const char *name, > } > return rc; > } > + > +/* Dumping via filter */ > + > +#define TYPE_FILTER_DUMP "filter-dump" > + > +#define FILTER_DUMP(obj) \ > + OBJECT_CHECK(NetFilterDumpState, (obj), TYPE_FILTER_DUMP) > + > +struct NetFilterDumpState { > + NetFilterState nfs; > + DumpState ds; > + char *filename; > + uint32_t maxlen; > +}; > +typedef struct NetFilterDumpState NetFilterDumpState; > + > +static ssize_t filter_dump_receive_iov(NetFilterState *nf, NetClientState *sndr, > + unsigned flags, const struct iovec *iov, > + int iovcnt, NetPacketSent *sent_cb) > +{ > + NetFilterDumpState *nfds = FILTER_DUMP(nf); > + > + dump_receive_iov(&nfds->ds, iov, iovcnt); > + return 0; > +} > + > +static void filter_dump_cleanup(NetFilterState *nf) > +{ > + NetFilterDumpState *nfds = FILTER_DUMP(nf); > + > + dump_cleanup(&nfds->ds); > +} > + > +static void filter_dump_setup(NetFilterState *nf, Error **errp) > +{ > + NetFilterDumpState *nfds = FILTER_DUMP(nf); > + > + if (!nfds->filename) { > + error_setg(errp, "dump filter needs 'file' property set!"); > + return; > + } > + > + net_dump_state_init(&nfds->ds, nfds->filename, nfds->maxlen, errp); > +} > + > +static void filter_dump_get_maxlen(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + NetFilterDumpState *nfds = FILTER_DUMP(obj); > + uint32_t value = nfds->maxlen; > + > + visit_type_uint32(v, &value, name, errp); > +} > + > +static void filter_dump_set_maxlen(Object *obj, Visitor *v, void *opaque, > + const char *name, Error **errp) > +{ > + NetFilterDumpState *nfds = FILTER_DUMP(obj); > + Error *local_err = NULL; > + uint32_t value; > + > + visit_type_uint32(v, &value, name, &local_err); > + if (local_err) { > + goto out; > + } > + if (value == 0) { > + error_setg(&local_err, "Property '%s.%s' doesn't take value '%u'", > + object_get_typename(obj), name, value); > + goto out; > + } > + nfds->maxlen = value; > + > +out: > + error_propagate(errp, local_err); > +} > + > +static char *file_dump_get_filename(Object *obj, Error **errp) > +{ > + NetFilterDumpState *nfds = FILTER_DUMP(obj); > + > + return g_strdup(nfds->filename); > +} > + > +static void file_dump_set_filename(Object *obj, const char *value, Error **errp) > +{ > + NetFilterDumpState *nfds = FILTER_DUMP(obj); > + > + g_free(nfds->filename); > + nfds->filename = g_strdup(value); > +} > + > +static void filter_dump_instance_init(Object *obj) > +{ > + NetFilterDumpState *nfds = FILTER_DUMP(obj); > + > + nfds->maxlen = 65536; > + > + object_property_add(obj, "maxlen", "int", filter_dump_get_maxlen, > + filter_dump_set_maxlen, NULL, NULL, NULL); > + object_property_add_str(obj, "file", file_dump_get_filename, > + file_dump_set_filename, NULL); > +} > + > +static void filter_dump_class_init(ObjectClass *oc, void *data) > +{ > + NetFilterClass *nfc = NETFILTER_CLASS(oc); > + > + nfc->setup = filter_dump_setup; > + nfc->cleanup = filter_dump_cleanup; > + nfc->receive_iov = filter_dump_receive_iov; > +} > + > +static const TypeInfo filter_dump_info = { > + .name = TYPE_FILTER_DUMP, > + .parent = TYPE_NETFILTER, > + .class_init = filter_dump_class_init, > + .instance_init = filter_dump_instance_init, > + .instance_size = sizeof(NetFilterDumpState), > +}; > + > +static void filter_dump_register_types(void) > +{ > + type_register_static(&filter_dump_info); > +} > + > +type_init(filter_dump_register_types); > diff --git a/vl.c b/vl.c > index 9be4d22..aa99ef3 100644 > --- a/vl.c > +++ b/vl.c > @@ -2761,8 +2761,12 @@ static bool object_create_initial(const char *type) > return false; > } > > - /* return false for concrete netfilters */ > - if (g_str_equal(type, "filter-buffer")) { > + /* > + * return false for concrete netfilters since > + * they depend on netdevs already existing > + */ > + if (g_str_equal(type, "filter-buffer") || > + g_str_equal(type, "filter-dump")) { > return false; > } > > -- Thanks, Yang. ^ permalink raw reply [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH 5/5] net/dump: Add documentation 2015-09-24 7:22 [Qemu-devel] [PATCH 0/5] Network traffic dumping via netfilter Thomas Huth ` (3 preceding siblings ...) 2015-09-24 7:22 ` [Qemu-devel] [PATCH 4/5] net/dump: Provide the dumping facility as a net filter Thomas Huth @ 2015-09-24 7:22 ` Thomas Huth 4 siblings, 0 replies; 12+ messages in thread From: Thomas Huth @ 2015-09-24 7:22 UTC (permalink / raw) To: qemu-devel, jasowang; +Cc: yanghy, armbru, stefanha, mst Add a short description for the filter-dump command line options. Signed-off-by: Thomas Huth <thuth@redhat.com> --- qemu-options.hx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/qemu-options.hx b/qemu-options.hx index b09f97f..347ee28 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2011,6 +2011,7 @@ qemu -m 512 -object memory-backend-file,id=mem,size=512M,mem-path=/hugetlbfs,sha 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. +Note: For devices created with '-netdev', use '-object filter-dump,...' instead. @item -net none Indicate that no network devices should be configured. It is used to @@ -3660,6 +3661,13 @@ chain @var{all|in|out} is an option that can be applied to any netfilter, defaul @option{out} means this filter will receive packets sent from the netdev +@item -object filter-dump,id=@var{id},netdev=@var{dev},file=@var{filename}][,maxlen=@var{len}] + +Dump the network traffic on netdev @var{dev} to the file specified by +@var{filename}. 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. + @end table ETEXI -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH 0/5] Network traffic dumping for -netdev, second try @ 2015-06-24 15:56 Thomas Huth 2015-06-24 15:56 ` [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function Thomas Huth 0 siblings, 1 reply; 12+ messages in thread From: Thomas Huth @ 2015-06-24 15:56 UTC (permalink / raw) To: qemu-devel, Stefan Hajnoczi, Jason Wang; +Cc: Markus Armbruster The "-net dump" option only works with the "-net" option. So far, it is not possible to dump network traffic with the "-netdev" option yet. This patch series now fixes this ugliness by enabling dumping for the "-netdev" option, too. Unlike with my first attempt a couple of weeks ago ("net: Enable vlans and dump for -netdev, too"), this patch series now does not "abuse" the disliked internal vlan hub infrastructure anymore but introduces a new, clean "dumpfile=xxx" option for the -netdev parameters instead. It's likely too late for version 2.4 for this patch series, but it would be great to get some review feedback for this anyway. Thomas Huth (5): net/dump: Add support for receive_iov function net/dump: Move DumpState into NetClientState net/dump: Rework net-dump init functions net/dump: Add dump option for netdev devices qemu options: Add information about dumpfile to help text include/net/net.h | 8 +++++ net/clients.h | 5 ++++ net/dump.c | 89 ++++++++++++++++++++++++++++++++++++------------------- net/net.c | 48 ++++++++++++++++++++++++++++++ qapi-schema.json | 12 ++++++-- qemu-options.hx | 26 +++++++++++----- 6 files changed, 147 insertions(+), 41 deletions(-) -- 1.8.3.1 ^ permalink raw reply [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function 2015-06-24 15:56 [Qemu-devel] [PATCH 0/5] Network traffic dumping for -netdev, second try Thomas Huth @ 2015-06-24 15:56 ` Thomas Huth 2015-06-26 6:38 ` Jason Wang 2015-07-03 11:06 ` Markus Armbruster 0 siblings, 2 replies; 12+ messages in thread From: Thomas Huth @ 2015-06-24 15:56 UTC (permalink / raw) To: qemu-devel, Stefan Hajnoczi, Jason Wang; +Cc: Markus Armbruster Adding a proper receive_iov function to the net dump module. This will make it easier to support the dump feature for the -netdev option in later patches. Also make the receive functions available to the other parts of the source code so we can later use them for dumping from net.c, too. Signed-off-by: Thomas Huth <thuth@redhat.com> --- net/clients.h | 3 +++ net/dump.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/net/clients.h b/net/clients.h index d47530e..5092f3d 100644 --- a/net/clients.h +++ b/net/clients.h @@ -29,6 +29,9 @@ int net_init_dump(const NetClientOptions *opts, const char *name, NetClientState *peer, Error **errp); +ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size); +ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov, + int cnt); #ifdef CONFIG_SLIRP int net_init_slirp(const NetClientOptions *opts, const char *name, diff --git a/net/dump.c b/net/dump.c index 02c8064..383718a 100644 --- a/net/dump.c +++ b/net/dump.c @@ -57,27 +57,49 @@ struct pcap_sf_pkthdr { uint32_t len; }; -static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) +ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov, + int cnt) { DumpState *s = DO_UPCAST(DumpState, nc, nc); struct pcap_sf_pkthdr hdr; int64_t ts; - int caplen; + int caplen, i; + size_t size = 0; + struct iovec dumpiov[cnt + 1]; /* Early return in case of previous error. */ if (s->fd < 0) { return size; } + dumpiov[0].iov_base = &hdr; + dumpiov[0].iov_len = sizeof(hdr); + caplen = s->pcap_caplen; + + /* Copy iov, limit maximum size to caplen, and count total input size */ + for (i = 0; i < cnt; i++) { + dumpiov[i + 1].iov_base = iov[i].iov_base; + if (size + iov[i].iov_len <= caplen) { + dumpiov[i + 1].iov_len = iov[i].iov_len; + } else if (size < caplen) { + dumpiov[i + 1].iov_len = caplen - size; + } else { + dumpiov[i + 1].iov_len = 0; + } + size += iov[i].iov_len; + } + ts = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 1000000, get_ticks_per_sec()); - caplen = size > s->pcap_caplen ? s->pcap_caplen : size; + if (size < caplen) { + caplen = size; + } hdr.ts.tv_sec = ts / 1000000 + s->start_ts; 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) { + + if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) { qemu_log("-net dump write error - stop dump\n"); close(s->fd); s->fd = -1; @@ -86,7 +108,16 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) return size; } -static void dump_cleanup(NetClientState *nc) +ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) +{ + struct iovec iov = { + .iov_base = (void *)buf, + .iov_len = size + }; + return net_dump_receive_iov(nc, &iov, 1); +} + +static void net_dump_cleanup(NetClientState *nc) { DumpState *s = DO_UPCAST(DumpState, nc, nc); @@ -96,8 +127,9 @@ static void dump_cleanup(NetClientState *nc) static NetClientInfo net_dump_info = { .type = NET_CLIENT_OPTIONS_KIND_DUMP, .size = sizeof(DumpState), - .receive = dump_receive, - .cleanup = dump_cleanup, + .receive = net_dump_receive, + .receive_iov = net_dump_receive_iov, + .cleanup = net_dump_cleanup, }; static int net_dump_init(NetClientState *peer, const char *device, -- 1.8.3.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function 2015-06-24 15:56 ` [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function Thomas Huth @ 2015-06-26 6:38 ` Jason Wang 2015-06-26 7:06 ` Thomas Huth 2015-07-03 11:06 ` Markus Armbruster 1 sibling, 1 reply; 12+ messages in thread From: Jason Wang @ 2015-06-26 6:38 UTC (permalink / raw) To: Thomas Huth, qemu-devel, Stefan Hajnoczi; +Cc: Markus Armbruster On 06/24/2015 11:56 PM, Thomas Huth wrote: > Adding a proper receive_iov function to the net dump module. This > will make it easier to support the dump feature for the -netdev > option in later patches. > Also make the receive functions available to the other parts of the > source code so we can later use them for dumping from net.c, too. > > Signed-off-by: Thomas Huth <thuth@redhat.com> > --- > net/clients.h | 3 +++ > net/dump.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- > 2 files changed, 43 insertions(+), 8 deletions(-) > > diff --git a/net/clients.h b/net/clients.h > index d47530e..5092f3d 100644 > --- a/net/clients.h > +++ b/net/clients.h > @@ -29,6 +29,9 @@ > > int net_init_dump(const NetClientOptions *opts, const char *name, > NetClientState *peer, Error **errp); > +ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size); > +ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov, > + int cnt); > > #ifdef CONFIG_SLIRP > int net_init_slirp(const NetClientOptions *opts, const char *name, > diff --git a/net/dump.c b/net/dump.c > index 02c8064..383718a 100644 > --- a/net/dump.c > +++ b/net/dump.c > @@ -57,27 +57,49 @@ struct pcap_sf_pkthdr { > uint32_t len; > }; > > -static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) > +ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov, > + int cnt) > { > DumpState *s = DO_UPCAST(DumpState, nc, nc); > struct pcap_sf_pkthdr hdr; > int64_t ts; > - int caplen; > + int caplen, i; > + size_t size = 0; > + struct iovec dumpiov[cnt + 1]; > > /* Early return in case of previous error. */ > if (s->fd < 0) { > return size; > } > > + dumpiov[0].iov_base = &hdr; > + dumpiov[0].iov_len = sizeof(hdr); > + caplen = s->pcap_caplen; > + > + /* Copy iov, limit maximum size to caplen, and count total input size */ > + for (i = 0; i < cnt; i++) { > + dumpiov[i + 1].iov_base = iov[i].iov_base; > + if (size + iov[i].iov_len <= caplen) { > + dumpiov[i + 1].iov_len = iov[i].iov_len; > + } else if (size < caplen) { > + dumpiov[i + 1].iov_len = caplen - size; > + } else { > + dumpiov[i + 1].iov_len = 0; > + } > + size += iov[i].iov_len; > + } I believe we could use iov_copy() here. > + > ts = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 1000000, get_ticks_per_sec()); > - caplen = size > s->pcap_caplen ? s->pcap_caplen : size; > + if (size < caplen) { > + caplen = size; > + } > > hdr.ts.tv_sec = ts / 1000000 + s->start_ts; > 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) { > + > + if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) { > qemu_log("-net dump write error - stop dump\n"); > close(s->fd); > s->fd = -1; > @@ -86,7 +108,16 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) > return size; > } > > -static void dump_cleanup(NetClientState *nc) > +ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) > +{ > + struct iovec iov = { > + .iov_base = (void *)buf, > + .iov_len = size > + }; > + return net_dump_receive_iov(nc, &iov, 1); > +} > + > +static void net_dump_cleanup(NetClientState *nc) > { > DumpState *s = DO_UPCAST(DumpState, nc, nc); > > @@ -96,8 +127,9 @@ static void dump_cleanup(NetClientState *nc) > static NetClientInfo net_dump_info = { > .type = NET_CLIENT_OPTIONS_KIND_DUMP, > .size = sizeof(DumpState), > - .receive = dump_receive, > - .cleanup = dump_cleanup, > + .receive = net_dump_receive, > + .receive_iov = net_dump_receive_iov, > + .cleanup = net_dump_cleanup, > }; > > static int net_dump_init(NetClientState *peer, const char *device, ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function 2015-06-26 6:38 ` Jason Wang @ 2015-06-26 7:06 ` Thomas Huth 0 siblings, 0 replies; 12+ messages in thread From: Thomas Huth @ 2015-06-26 7:06 UTC (permalink / raw) To: Jason Wang; +Cc: qemu-devel, Stefan Hajnoczi, Markus Armbruster On Fri, 26 Jun 2015 14:38:42 +0800 Jason Wang <jasowang@redhat.com> wrote: > > > On 06/24/2015 11:56 PM, Thomas Huth wrote: > > Adding a proper receive_iov function to the net dump module. This > > will make it easier to support the dump feature for the -netdev > > option in later patches. > > Also make the receive functions available to the other parts of the > > source code so we can later use them for dumping from net.c, too. > > > > Signed-off-by: Thomas Huth <thuth@redhat.com> > > --- > > net/clients.h | 3 +++ > > net/dump.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- > > 2 files changed, 43 insertions(+), 8 deletions(-) > > > > diff --git a/net/clients.h b/net/clients.h > > index d47530e..5092f3d 100644 > > --- a/net/clients.h > > +++ b/net/clients.h > > @@ -29,6 +29,9 @@ > > > > int net_init_dump(const NetClientOptions *opts, const char *name, > > NetClientState *peer, Error **errp); > > +ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size); > > +ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov, > > + int cnt); > > > > #ifdef CONFIG_SLIRP > > int net_init_slirp(const NetClientOptions *opts, const char *name, > > diff --git a/net/dump.c b/net/dump.c > > index 02c8064..383718a 100644 > > --- a/net/dump.c > > +++ b/net/dump.c > > @@ -57,27 +57,49 @@ struct pcap_sf_pkthdr { > > uint32_t len; > > }; > > > > -static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) > > +ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov, > > + int cnt) > > { > > DumpState *s = DO_UPCAST(DumpState, nc, nc); > > struct pcap_sf_pkthdr hdr; > > int64_t ts; > > - int caplen; > > + int caplen, i; > > + size_t size = 0; > > + struct iovec dumpiov[cnt + 1]; > > > > /* Early return in case of previous error. */ > > if (s->fd < 0) { > > return size; > > } > > > > + dumpiov[0].iov_base = &hdr; > > + dumpiov[0].iov_len = sizeof(hdr); > > + caplen = s->pcap_caplen; > > + > > + /* Copy iov, limit maximum size to caplen, and count total input size */ > > + for (i = 0; i < cnt; i++) { > > + dumpiov[i + 1].iov_base = iov[i].iov_base; > > + if (size + iov[i].iov_len <= caplen) { > > + dumpiov[i + 1].iov_len = iov[i].iov_len; > > + } else if (size < caplen) { > > + dumpiov[i + 1].iov_len = caplen - size; > > + } else { > > + dumpiov[i + 1].iov_len = 0; > > + } > > + size += iov[i].iov_len; > > + } > > I believe we could use iov_copy() here. Looks like that could do the job, too, thanks for the hint! However, I also need the total size of bytes in the source iov, so I'd then need to call iov_size() here, too - but I guess it's ok to loop through the iov twice since dumping is not really time critical. Thomas ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function 2015-06-24 15:56 ` [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function Thomas Huth 2015-06-26 6:38 ` Jason Wang @ 2015-07-03 11:06 ` Markus Armbruster 2015-07-10 18:09 ` Thomas Huth 1 sibling, 1 reply; 12+ messages in thread From: Markus Armbruster @ 2015-07-03 11:06 UTC (permalink / raw) To: Thomas Huth; +Cc: Jason Wang, qemu-devel, Stefan Hajnoczi Thomas Huth <thuth@redhat.com> writes: > Adding a proper receive_iov function to the net dump module. This > will make it easier to support the dump feature for the -netdev > option in later patches. > Also make the receive functions available to the other parts of the > source code so we can later use them for dumping from net.c, too. > > Signed-off-by: Thomas Huth <thuth@redhat.com> > --- > net/clients.h | 3 +++ > net/dump.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- > 2 files changed, 43 insertions(+), 8 deletions(-) > > diff --git a/net/clients.h b/net/clients.h > index d47530e..5092f3d 100644 > --- a/net/clients.h > +++ b/net/clients.h > @@ -29,6 +29,9 @@ > > int net_init_dump(const NetClientOptions *opts, const char *name, > NetClientState *peer, Error **errp); > +ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size); > +ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov, > + int cnt); > > #ifdef CONFIG_SLIRP > int net_init_slirp(const NetClientOptions *opts, const char *name, > diff --git a/net/dump.c b/net/dump.c > index 02c8064..383718a 100644 > --- a/net/dump.c > +++ b/net/dump.c > @@ -57,27 +57,49 @@ struct pcap_sf_pkthdr { > uint32_t len; > }; > > -static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) > +ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov, > + int cnt) > { > DumpState *s = DO_UPCAST(DumpState, nc, nc); > struct pcap_sf_pkthdr hdr; > int64_t ts; > - int caplen; > + int caplen, i; > + size_t size = 0; > + struct iovec dumpiov[cnt + 1]; Variable length array. Ignorant question: okay to use VLAs in QEMU? > > /* Early return in case of previous error. */ > if (s->fd < 0) { > return size; Before your patch: return the size argument. Afterwards: return zero. Sure that's what you want? > } > > + dumpiov[0].iov_base = &hdr; > + dumpiov[0].iov_len = sizeof(hdr); > + caplen = s->pcap_caplen; > + > + /* Copy iov, limit maximum size to caplen, and count total input size */ > + for (i = 0; i < cnt; i++) { > + dumpiov[i + 1].iov_base = iov[i].iov_base; > + if (size + iov[i].iov_len <= caplen) { > + dumpiov[i + 1].iov_len = iov[i].iov_len; > + } else if (size < caplen) { > + dumpiov[i + 1].iov_len = caplen - size; > + } else { > + dumpiov[i + 1].iov_len = 0; When you hit caplen before the last iovec, this produces trailing iovec[] with zero iov_len instead of shortening the array. Okay. > + } > + size += iov[i].iov_len; > + } > + > ts = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 1000000, get_ticks_per_sec()); > - caplen = size > s->pcap_caplen ? s->pcap_caplen : size; > + if (size < caplen) { > + caplen = size; > + } > > hdr.ts.tv_sec = ts / 1000000 + s->start_ts; > 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) { > + > + if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) { Bonus: saves a system call :) > qemu_log("-net dump write error - stop dump\n"); > close(s->fd); > s->fd = -1; > @@ -86,7 +108,16 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) > return size; > } > > -static void dump_cleanup(NetClientState *nc) > +ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) > +{ > + struct iovec iov = { > + .iov_base = (void *)buf, > + .iov_len = size > + }; > + return net_dump_receive_iov(nc, &iov, 1); > +} > + > +static void net_dump_cleanup(NetClientState *nc) > { > DumpState *s = DO_UPCAST(DumpState, nc, nc); > > @@ -96,8 +127,9 @@ static void dump_cleanup(NetClientState *nc) > static NetClientInfo net_dump_info = { > .type = NET_CLIENT_OPTIONS_KIND_DUMP, > .size = sizeof(DumpState), > - .receive = dump_receive, > - .cleanup = dump_cleanup, > + .receive = net_dump_receive, > + .receive_iov = net_dump_receive_iov, > + .cleanup = net_dump_cleanup, > }; > > static int net_dump_init(NetClientState *peer, const char *device, Any particular reason to rename dump_cleanup()? Not that I mind... ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function 2015-07-03 11:06 ` Markus Armbruster @ 2015-07-10 18:09 ` Thomas Huth 0 siblings, 0 replies; 12+ messages in thread From: Thomas Huth @ 2015-07-10 18:09 UTC (permalink / raw) To: Markus Armbruster; +Cc: Jason Wang, qemu-devel, Stefan Hajnoczi On Fri, 03 Jul 2015 13:06:55 +0200 Markus Armbruster <armbru@redhat.com> wrote: > Thomas Huth <thuth@redhat.com> writes: > > > Adding a proper receive_iov function to the net dump module. This > > will make it easier to support the dump feature for the -netdev > > option in later patches. > > Also make the receive functions available to the other parts of the > > source code so we can later use them for dumping from net.c, too. > > > > Signed-off-by: Thomas Huth <thuth@redhat.com> > > --- > > net/clients.h | 3 +++ > > net/dump.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- > > 2 files changed, 43 insertions(+), 8 deletions(-) > > > > diff --git a/net/clients.h b/net/clients.h > > index d47530e..5092f3d 100644 > > --- a/net/clients.h > > +++ b/net/clients.h > > @@ -29,6 +29,9 @@ > > > > int net_init_dump(const NetClientOptions *opts, const char *name, > > NetClientState *peer, Error **errp); > > +ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size); > > +ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov, > > + int cnt); > > > > #ifdef CONFIG_SLIRP > > int net_init_slirp(const NetClientOptions *opts, const char *name, > > diff --git a/net/dump.c b/net/dump.c > > index 02c8064..383718a 100644 > > --- a/net/dump.c > > +++ b/net/dump.c > > @@ -57,27 +57,49 @@ struct pcap_sf_pkthdr { > > uint32_t len; > > }; > > > > -static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) > > +ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov, > > + int cnt) > > { > > DumpState *s = DO_UPCAST(DumpState, nc, nc); > > struct pcap_sf_pkthdr hdr; > > int64_t ts; > > - int caplen; > > + int caplen, i; > > + size_t size = 0; > > + struct iovec dumpiov[cnt + 1]; > > Variable length array. Ignorant question: okay to use VLAs in QEMU? I guess so - at least there are already some other spots that use VLAs, e.g. in tap_receive_iov() > > > > /* Early return in case of previous error. */ > > if (s->fd < 0) { > > return size; > > Before your patch: return the size argument. > > Afterwards: return zero. Sure that's what you want? That was of course a stupid bug. Thanks for pointing it out, it will be fixed in v2! > > } > > > > + dumpiov[0].iov_base = &hdr; > > + dumpiov[0].iov_len = sizeof(hdr); > > + caplen = s->pcap_caplen; > > + > > + /* Copy iov, limit maximum size to caplen, and count total input size */ > > + for (i = 0; i < cnt; i++) { > > + dumpiov[i + 1].iov_base = iov[i].iov_base; > > + if (size + iov[i].iov_len <= caplen) { > > + dumpiov[i + 1].iov_len = iov[i].iov_len; > > + } else if (size < caplen) { > > + dumpiov[i + 1].iov_len = caplen - size; > > + } else { > > + dumpiov[i + 1].iov_len = 0; > > When you hit caplen before the last iovec, this produces trailing > iovec[] with zero iov_len instead of shortening the array. Okay. I'll use iov_copy in the next version, as suggested by Jason - and that returns the shortened count if necessary. > > + } > > + size += iov[i].iov_len; > > + } > > + > > ts = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 1000000, get_ticks_per_sec()); > > - caplen = size > s->pcap_caplen ? s->pcap_caplen : size; > > + if (size < caplen) { > > + caplen = size; > > + } > > > > hdr.ts.tv_sec = ts / 1000000 + s->start_ts; > > 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) { > > + > > + if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) { > > Bonus: saves a system call :) > > > qemu_log("-net dump write error - stop dump\n"); > > close(s->fd); > > s->fd = -1; > > @@ -86,7 +108,16 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) > > return size; > > } > > > > -static void dump_cleanup(NetClientState *nc) > > +ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size) > > +{ > > + struct iovec iov = { > > + .iov_base = (void *)buf, > > + .iov_len = size > > + }; > > + return net_dump_receive_iov(nc, &iov, 1); > > +} > > + > > +static void net_dump_cleanup(NetClientState *nc) > > { > > DumpState *s = DO_UPCAST(DumpState, nc, nc); > > > > @@ -96,8 +127,9 @@ static void dump_cleanup(NetClientState *nc) > > static NetClientInfo net_dump_info = { > > .type = NET_CLIENT_OPTIONS_KIND_DUMP, > > .size = sizeof(DumpState), > > - .receive = dump_receive, > > - .cleanup = dump_cleanup, > > + .receive = net_dump_receive, > > + .receive_iov = net_dump_receive_iov, > > + .cleanup = net_dump_cleanup, > > }; > > > > static int net_dump_init(NetClientState *peer, const char *device, > > Any particular reason to rename dump_cleanup()? Not that I mind... It's more consistent ... and in v2 I'll also need this function exported (to make sure that the fd gets closed for -netdev, too), so I then should rename it anyway. Thomas ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2015-09-24 8:21 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-09-24 7:22 [Qemu-devel] [PATCH 0/5] Network traffic dumping via netfilter Thomas Huth 2015-09-24 7:22 ` [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function Thomas Huth 2015-09-24 7:22 ` [Qemu-devel] [PATCH 2/5] net/dump: Rework net-dump init functions Thomas Huth 2015-09-24 7:22 ` [Qemu-devel] [PATCH 3/5] net/dump: Separate the NetClientState from the DumpState Thomas Huth 2015-09-24 7:22 ` [Qemu-devel] [PATCH 4/5] net/dump: Provide the dumping facility as a net filter Thomas Huth 2015-09-24 8:20 ` Yang Hongyang 2015-09-24 7:22 ` [Qemu-devel] [PATCH 5/5] net/dump: Add documentation Thomas Huth -- strict thread matches above, loose matches on Subject: below -- 2015-06-24 15:56 [Qemu-devel] [PATCH 0/5] Network traffic dumping for -netdev, second try Thomas Huth 2015-06-24 15:56 ` [Qemu-devel] [PATCH 1/5] net/dump: Add support for receive_iov function Thomas Huth 2015-06-26 6:38 ` Jason Wang 2015-06-26 7:06 ` Thomas Huth 2015-07-03 11:06 ` Markus Armbruster 2015-07-10 18:09 ` Thomas Huth
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).