Message ID | 1453798787-7453-1-git-send-email-zhangchen.fnst@cn.fujitsu.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 01/26/2016 04:59 PM, Zhang Chen wrote: > From: ZhangChen <zhangchen.fnst@cn.fujitsu.com> > > Traffic-mirrorer is a plugin of netfilter. netfilter plugin > It make qemu has ability to copy and mirror guest's s/make/makes/ has the ability > net packet. we output packet to chardev. there seems no 'mirrorer' in english, I think the plugin name 'traffic-mirror' is enough. > > usage: > > -netdev tap,id=hn0 > -chardev socket,id=mirrorer0,host=ip_primary,port=X,server,nowait > -traffic-mirrorer,id=m0,netdev=hn0,queue=tx,outdev=mirrorer0 > > Signed-off-by: ZhangChen <zhangchen.fnst@cn.fujitsu.com> > Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> The code looks good overall, so: Reviewed-by: Yang Hongyang <hongyang.yang@easystack.cn> > --- > net/Makefile.objs | 1 + > net/traffic-mirrorer.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ > qemu-options.hx | 5 ++ > vl.c | 3 +- > 4 files changed, 181 insertions(+), 1 deletion(-) > create mode 100644 net/traffic-mirrorer.c > > diff --git a/net/Makefile.objs b/net/Makefile.objs > index 5fa2f97..6466764 100644 > --- a/net/Makefile.objs > +++ b/net/Makefile.objs > @@ -15,3 +15,4 @@ common-obj-$(CONFIG_VDE) += vde.o > common-obj-$(CONFIG_NETMAP) += netmap.o > common-obj-y += filter.o > common-obj-y += filter-buffer.o > +common-obj-y += traffic-mirrorer.o > diff --git a/net/traffic-mirrorer.c b/net/traffic-mirrorer.c > new file mode 100644 > index 0000000..3b0da82 > --- /dev/null > +++ b/net/traffic-mirrorer.c > @@ -0,0 +1,173 @@ > +/* > + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. > + * Copyright (c) 2016 FUJITSU LIMITED > + * Copyright (c) 2016 Intel Corporation > + * > + * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or > + * later. See the COPYING file in the top-level directory. > + */ > + > +#include "net/filter.h" > +#include "net/net.h" > +#include "qemu-common.h" > +#include "qapi/qmp/qerror.h" > +#include "qapi-visit.h" > +#include "qom/object.h" > +#include "qemu/main-loop.h" > +#include "qemu/error-report.h" > +#include "trace.h" > +#include "sysemu/char.h" > +#include "qemu/iov.h" > + > +#define FILTER_TRAFFIC_MIRRORER(obj) \ > + OBJECT_CHECK(MirrorerState, (obj), TYPE_FILTER_TRAFFIC_MIRRORER) > + > +#define TYPE_FILTER_TRAFFIC_MIRRORER "traffic-mirrorer" > + > +typedef struct MirrorerState { > + NetFilterState parent_obj; > + char *outdev; > + CharDriverState *chr_out; > + > +} MirrorerState; > + > +static ssize_t traffic_mirrorer_send(NetFilterState *nf, > + const struct iovec *iov, > + int iovcnt) > +{ > + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); > + ssize_t ret = 0; > + ssize_t size = 0; > + char *buf; > + > + size = iov_size(iov, iovcnt); > + if (!size) { > + return 0; > + } > + > + buf = g_malloc0(size); > + iov_to_buf(iov, iovcnt, 0, buf, size); > + ret = qemu_chr_fe_write(s->chr_out, (uint8_t *)&size, sizeof(size)); > + if (ret < 0) { > + g_free(buf); > + return ret; > + } > + > + ret = qemu_chr_fe_write(s->chr_out, (uint8_t *)buf, size); > + g_free(buf); > + return ret; > +} > + > +static ssize_t traffic_mirrorer_receive_iov(NetFilterState *nf, > + NetClientState *sender, > + unsigned flags, > + const struct iovec *iov, > + int iovcnt, > + NetPacketSent *sent_cb) > +{ > + /* > + * We copy and mirror packet to outdev, > + * then put back the packet. > + */ > + ssize_t ret = 0; > + > + ret = traffic_mirrorer_send(nf, iov, iovcnt); > + if (ret < 0) { > + error_report("traffic_mirrorer_send failed"); > + } > + > + return 0; > +} > + > +static void traffic_mirrorer_cleanup(NetFilterState *nf) > +{ > + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); > + > + if (s->chr_out) { > + qemu_chr_fe_release(s->chr_out); > + } > +} > + > +static void traffic_mirrorer_setup(NetFilterState *nf, Error **errp) > +{ > + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); > + > + if (!s->outdev) { > + error_setg(errp, "filter traffic mirrorer needs 'outdev' property set!" > + "property set!"); > + return; > + } > + > + s->chr_out = qemu_chr_find(s->outdev); > + if (s->chr_out == NULL) { > + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, > + "Device '%s' not found", s->outdev); > + return; > + } > + > + if (qemu_chr_fe_claim(s->chr_out) != 0) { > + error_setg(errp, QERR_DEVICE_IN_USE, s->outdev); > + return; > + } > +} > + > +static void traffic_mirrorer_class_init(ObjectClass *oc, void *data) > +{ > + NetFilterClass *nfc = NETFILTER_CLASS(oc); > + > + nfc->setup = traffic_mirrorer_setup; > + nfc->cleanup = traffic_mirrorer_cleanup; > + nfc->receive_iov = traffic_mirrorer_receive_iov; > +} > + > +static char *traffic_mirrorer_get_outdev(Object *obj, Error **errp) > +{ > + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); > + > + return g_strdup(s->outdev); > +} > + > +static void > +traffic_mirrorer_set_outdev(Object *obj, const char *value, Error **errp) > +{ > + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); > + > + g_free(s->outdev); > + s->outdev = g_strdup(value); > + if (!s->outdev) { > + error_setg(errp, "filter traffic mirrorer needs 'outdev' " > + "property set!"); > + return; > + } > +} > + > +static void traffic_mirrorer_init(Object *obj) > +{ > + object_property_add_str(obj, "outdev", traffic_mirrorer_get_outdev, > + traffic_mirrorer_set_outdev, NULL); > +} > + > +static void traffic_mirrorer_fini(Object *obj) > +{ > + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); > + > + g_free(s->outdev); > +} > + > +static const TypeInfo traffic_mirrorer_info = { > + .name = TYPE_FILTER_TRAFFIC_MIRRORER, > + .parent = TYPE_NETFILTER, > + .class_init = traffic_mirrorer_class_init, > + .instance_init = traffic_mirrorer_init, > + .instance_finalize = traffic_mirrorer_fini, > + .instance_size = sizeof(MirrorerState), > +}; > + > +static void register_types(void) > +{ > + type_register_static(&traffic_mirrorer_info); > +} > + > +type_init(register_types); > diff --git a/qemu-options.hx b/qemu-options.hx > index 0eea4ee..ecfa297 100644 > --- a/qemu-options.hx > +++ b/qemu-options.hx > @@ -3670,6 +3670,11 @@ queue @var{all|rx|tx} is an option that can be applied to any netfilter. > @option{tx}: the filter is attached to the transmit queue of the netdev, > where it will receive packets sent by the netdev. > > +@item -object traffic-mirrorer,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid}[,queue=@var{all|rx|tx}] > + > +traffic-mirrorer on netdev @var{netdevid},mirror net packet to outdev. > +queue @var{all|rx|tx} is an option that can be applied to traffic-mirrorer. > + > @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 > diff --git a/vl.c b/vl.c > index 8dc34ce..4fe01bc 100644 > --- a/vl.c > +++ b/vl.c > @@ -2838,7 +2838,8 @@ static bool object_create_initial(const char *type) > * they depend on netdevs already existing > */ > if (g_str_equal(type, "filter-buffer") || > - g_str_equal(type, "filter-dump")) { > + g_str_equal(type, "filter-dump") || > + g_str_equal(type, "traffic-mirrorer")) { > return false; > } > >
* Yang Hongyang (hongyang.yang@easystack.cn) wrote: > > > On 01/26/2016 04:59 PM, Zhang Chen wrote: > >From: ZhangChen <zhangchen.fnst@cn.fujitsu.com> > > > >Traffic-mirrorer is a plugin of netfilter. > > netfilter plugin > > >It make qemu has ability to copy and mirror guest's > > s/make/makes/ has the ability Not quite. 'It gives qemu the ability to...' (Sorry, I can't explain why!). > >net packet. we output packet to chardev. > > there seems no 'mirrorer' in english, I think the plugin name > 'traffic-mirror' is enough. Agreed. Dave > > > > >usage: > > > >-netdev tap,id=hn0 > >-chardev socket,id=mirrorer0,host=ip_primary,port=X,server,nowait > >-traffic-mirrorer,id=m0,netdev=hn0,queue=tx,outdev=mirrorer0 > > > >Signed-off-by: ZhangChen <zhangchen.fnst@cn.fujitsu.com> > >Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> > > The code looks good overall, so: > Reviewed-by: Yang Hongyang <hongyang.yang@easystack.cn> > > >--- > > net/Makefile.objs | 1 + > > net/traffic-mirrorer.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ > > qemu-options.hx | 5 ++ > > vl.c | 3 +- > > 4 files changed, 181 insertions(+), 1 deletion(-) > > create mode 100644 net/traffic-mirrorer.c > > > >diff --git a/net/Makefile.objs b/net/Makefile.objs > >index 5fa2f97..6466764 100644 > >--- a/net/Makefile.objs > >+++ b/net/Makefile.objs > >@@ -15,3 +15,4 @@ common-obj-$(CONFIG_VDE) += vde.o > > common-obj-$(CONFIG_NETMAP) += netmap.o > > common-obj-y += filter.o > > common-obj-y += filter-buffer.o > >+common-obj-y += traffic-mirrorer.o > >diff --git a/net/traffic-mirrorer.c b/net/traffic-mirrorer.c > >new file mode 100644 > >index 0000000..3b0da82 > >--- /dev/null > >+++ b/net/traffic-mirrorer.c > >@@ -0,0 +1,173 @@ > >+/* > >+ * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. > >+ * Copyright (c) 2016 FUJITSU LIMITED > >+ * Copyright (c) 2016 Intel Corporation > >+ * > >+ * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> > >+ * > >+ * This work is licensed under the terms of the GNU GPL, version 2 or > >+ * later. See the COPYING file in the top-level directory. > >+ */ > >+ > >+#include "net/filter.h" > >+#include "net/net.h" > >+#include "qemu-common.h" > >+#include "qapi/qmp/qerror.h" > >+#include "qapi-visit.h" > >+#include "qom/object.h" > >+#include "qemu/main-loop.h" > >+#include "qemu/error-report.h" > >+#include "trace.h" > >+#include "sysemu/char.h" > >+#include "qemu/iov.h" > >+ > >+#define FILTER_TRAFFIC_MIRRORER(obj) \ > >+ OBJECT_CHECK(MirrorerState, (obj), TYPE_FILTER_TRAFFIC_MIRRORER) > >+ > >+#define TYPE_FILTER_TRAFFIC_MIRRORER "traffic-mirrorer" > >+ > >+typedef struct MirrorerState { > >+ NetFilterState parent_obj; > >+ char *outdev; > >+ CharDriverState *chr_out; > >+ > >+} MirrorerState; > >+ > >+static ssize_t traffic_mirrorer_send(NetFilterState *nf, > >+ const struct iovec *iov, > >+ int iovcnt) > >+{ > >+ MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); > >+ ssize_t ret = 0; > >+ ssize_t size = 0; > >+ char *buf; > >+ > >+ size = iov_size(iov, iovcnt); > >+ if (!size) { > >+ return 0; > >+ } > >+ > >+ buf = g_malloc0(size); > >+ iov_to_buf(iov, iovcnt, 0, buf, size); > >+ ret = qemu_chr_fe_write(s->chr_out, (uint8_t *)&size, sizeof(size)); > >+ if (ret < 0) { > >+ g_free(buf); > >+ return ret; > >+ } > >+ > >+ ret = qemu_chr_fe_write(s->chr_out, (uint8_t *)buf, size); > >+ g_free(buf); > >+ return ret; > >+} > >+ > >+static ssize_t traffic_mirrorer_receive_iov(NetFilterState *nf, > >+ NetClientState *sender, > >+ unsigned flags, > >+ const struct iovec *iov, > >+ int iovcnt, > >+ NetPacketSent *sent_cb) > >+{ > >+ /* > >+ * We copy and mirror packet to outdev, > >+ * then put back the packet. > >+ */ > >+ ssize_t ret = 0; > >+ > >+ ret = traffic_mirrorer_send(nf, iov, iovcnt); > >+ if (ret < 0) { > >+ error_report("traffic_mirrorer_send failed"); > >+ } > >+ > >+ return 0; > >+} > >+ > >+static void traffic_mirrorer_cleanup(NetFilterState *nf) > >+{ > >+ MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); > >+ > >+ if (s->chr_out) { > >+ qemu_chr_fe_release(s->chr_out); > >+ } > >+} > >+ > >+static void traffic_mirrorer_setup(NetFilterState *nf, Error **errp) > >+{ > >+ MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); > >+ > >+ if (!s->outdev) { > >+ error_setg(errp, "filter traffic mirrorer needs 'outdev' property set!" > >+ "property set!"); > >+ return; > >+ } > >+ > >+ s->chr_out = qemu_chr_find(s->outdev); > >+ if (s->chr_out == NULL) { > >+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, > >+ "Device '%s' not found", s->outdev); > >+ return; > >+ } > >+ > >+ if (qemu_chr_fe_claim(s->chr_out) != 0) { > >+ error_setg(errp, QERR_DEVICE_IN_USE, s->outdev); > >+ return; > >+ } > >+} > >+ > >+static void traffic_mirrorer_class_init(ObjectClass *oc, void *data) > >+{ > >+ NetFilterClass *nfc = NETFILTER_CLASS(oc); > >+ > >+ nfc->setup = traffic_mirrorer_setup; > >+ nfc->cleanup = traffic_mirrorer_cleanup; > >+ nfc->receive_iov = traffic_mirrorer_receive_iov; > >+} > >+ > >+static char *traffic_mirrorer_get_outdev(Object *obj, Error **errp) > >+{ > >+ MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); > >+ > >+ return g_strdup(s->outdev); > >+} > >+ > >+static void > >+traffic_mirrorer_set_outdev(Object *obj, const char *value, Error **errp) > >+{ > >+ MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); > >+ > >+ g_free(s->outdev); > >+ s->outdev = g_strdup(value); > >+ if (!s->outdev) { > >+ error_setg(errp, "filter traffic mirrorer needs 'outdev' " > >+ "property set!"); > >+ return; > >+ } > >+} > >+ > >+static void traffic_mirrorer_init(Object *obj) > >+{ > >+ object_property_add_str(obj, "outdev", traffic_mirrorer_get_outdev, > >+ traffic_mirrorer_set_outdev, NULL); > >+} > >+ > >+static void traffic_mirrorer_fini(Object *obj) > >+{ > >+ MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); > >+ > >+ g_free(s->outdev); > >+} > >+ > >+static const TypeInfo traffic_mirrorer_info = { > >+ .name = TYPE_FILTER_TRAFFIC_MIRRORER, > >+ .parent = TYPE_NETFILTER, > >+ .class_init = traffic_mirrorer_class_init, > >+ .instance_init = traffic_mirrorer_init, > >+ .instance_finalize = traffic_mirrorer_fini, > >+ .instance_size = sizeof(MirrorerState), > >+}; > >+ > >+static void register_types(void) > >+{ > >+ type_register_static(&traffic_mirrorer_info); > >+} > >+ > >+type_init(register_types); > >diff --git a/qemu-options.hx b/qemu-options.hx > >index 0eea4ee..ecfa297 100644 > >--- a/qemu-options.hx > >+++ b/qemu-options.hx > >@@ -3670,6 +3670,11 @@ queue @var{all|rx|tx} is an option that can be applied to any netfilter. > > @option{tx}: the filter is attached to the transmit queue of the netdev, > > where it will receive packets sent by the netdev. > > > >+@item -object traffic-mirrorer,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid}[,queue=@var{all|rx|tx}] > >+ > >+traffic-mirrorer on netdev @var{netdevid},mirror net packet to outdev. > >+queue @var{all|rx|tx} is an option that can be applied to traffic-mirrorer. > >+ > > @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 > >diff --git a/vl.c b/vl.c > >index 8dc34ce..4fe01bc 100644 > >--- a/vl.c > >+++ b/vl.c > >@@ -2838,7 +2838,8 @@ static bool object_create_initial(const char *type) > > * they depend on netdevs already existing > > */ > > if (g_str_equal(type, "filter-buffer") || > >- g_str_equal(type, "filter-dump")) { > >+ g_str_equal(type, "filter-dump") || > >+ g_str_equal(type, "traffic-mirrorer")) { > > return false; > > } > > > > > > -- > Thanks, > Yang -- Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
On 2016/1/26 16:59, Zhang Chen wrote: > From: ZhangChen <zhangchen.fnst@cn.fujitsu.com> > > Traffic-mirrorer is a plugin of netfilter. > It make qemu has ability to copy and mirror guest's > net packet. we output packet to chardev. > > usage: > > -netdev tap,id=hn0 > -chardev socket,id=mirrorer0,host=ip_primary,port=X,server,nowait > -traffic-mirrorer,id=m0,netdev=hn0,queue=tx,outdev=mirrorer0 > > Signed-off-by: ZhangChen <zhangchen.fnst@cn.fujitsu.com> > Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> > --- > net/Makefile.objs | 1 + > net/traffic-mirrorer.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ > qemu-options.hx | 5 ++ > vl.c | 3 +- > 4 files changed, 181 insertions(+), 1 deletion(-) > create mode 100644 net/traffic-mirrorer.c > > diff --git a/net/Makefile.objs b/net/Makefile.objs > index 5fa2f97..6466764 100644 > --- a/net/Makefile.objs > +++ b/net/Makefile.objs > @@ -15,3 +15,4 @@ common-obj-$(CONFIG_VDE) += vde.o > common-obj-$(CONFIG_NETMAP) += netmap.o > common-obj-y += filter.o > common-obj-y += filter-buffer.o > +common-obj-y += traffic-mirrorer.o > diff --git a/net/traffic-mirrorer.c b/net/traffic-mirrorer.c > new file mode 100644 > index 0000000..3b0da82 > --- /dev/null > +++ b/net/traffic-mirrorer.c > @@ -0,0 +1,173 @@ > +/* > + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. > + * Copyright (c) 2016 FUJITSU LIMITED > + * Copyright (c) 2016 Intel Corporation > + * > + * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or > + * later. See the COPYING file in the top-level directory. > + */ > + > +#include "net/filter.h" > +#include "net/net.h" > +#include "qemu-common.h" > +#include "qapi/qmp/qerror.h" > +#include "qapi-visit.h" > +#include "qom/object.h" > +#include "qemu/main-loop.h" > +#include "qemu/error-report.h" > +#include "trace.h" > +#include "sysemu/char.h" > +#include "qemu/iov.h" > + > +#define FILTER_TRAFFIC_MIRRORER(obj) \ > + OBJECT_CHECK(MirrorerState, (obj), TYPE_FILTER_TRAFFIC_MIRRORER) > + > +#define TYPE_FILTER_TRAFFIC_MIRRORER "traffic-mirrorer" > + > +typedef struct MirrorerState { > + NetFilterState parent_obj; > + char *outdev; > + CharDriverState *chr_out; > + > +} MirrorerState; > + > +static ssize_t traffic_mirrorer_send(NetFilterState *nf, > + const struct iovec *iov, > + int iovcnt) The indent of parameters. > +{ > + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); > + ssize_t ret = 0; > + ssize_t size = 0; > + char *buf; > + > + size = iov_size(iov, iovcnt); > + if (!size) { > + return 0; > + } > + > + buf = g_malloc0(size); > + iov_to_buf(iov, iovcnt, 0, buf, size); > + ret = qemu_chr_fe_write(s->chr_out, (uint8_t *)&size, sizeof(size)); > + if (ret < 0) { > + g_free(buf); > + return ret; > + } > + > + ret = qemu_chr_fe_write(s->chr_out, (uint8_t *)buf, size); > + g_free(buf); > + return ret; > +} > + > +static ssize_t traffic_mirrorer_receive_iov(NetFilterState *nf, > + NetClientState *sender, > + unsigned flags, > + const struct iovec *iov, > + int iovcnt, > + NetPacketSent *sent_cb) > +{ > + /* > + * We copy and mirror packet to outdev, > + * then put back the packet. > + */ > + ssize_t ret = 0; > + > + ret = traffic_mirrorer_send(nf, iov, iovcnt); > + if (ret < 0) { > + error_report("traffic_mirrorer_send failed"); > + } > + > + return 0; > +} > + > +static void traffic_mirrorer_cleanup(NetFilterState *nf) > +{ > + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); > + > + if (s->chr_out) { > + qemu_chr_fe_release(s->chr_out); > + } > +} > + > +static void traffic_mirrorer_setup(NetFilterState *nf, Error **errp) > +{ > + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); > + > + if (!s->outdev) { > + error_setg(errp, "filter traffic mirrorer needs 'outdev' property set!" > + "property set!"); Duplicate 'property set!'. > + return; > + } > + > + s->chr_out = qemu_chr_find(s->outdev); > + if (s->chr_out == NULL) { > + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, > + "Device '%s' not found", s->outdev); > + return; > + } > + > + if (qemu_chr_fe_claim(s->chr_out) != 0) { > + error_setg(errp, QERR_DEVICE_IN_USE, s->outdev); > + return; > + } > +} > + > +static void traffic_mirrorer_class_init(ObjectClass *oc, void *data) > +{ > + NetFilterClass *nfc = NETFILTER_CLASS(oc); > + > + nfc->setup = traffic_mirrorer_setup; > + nfc->cleanup = traffic_mirrorer_cleanup; > + nfc->receive_iov = traffic_mirrorer_receive_iov; > +} > + > +static char *traffic_mirrorer_get_outdev(Object *obj, Error **errp) > +{ > + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); > + > + return g_strdup(s->outdev); > +} > + > +static void > +traffic_mirrorer_set_outdev(Object *obj, const char *value, Error **errp) > +{ > + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); > + > + g_free(s->outdev); > + s->outdev = g_strdup(value); > + if (!s->outdev) { > + error_setg(errp, "filter traffic mirrorer needs 'outdev' " > + "property set!"); > + return; > + } > +} > + > +static void traffic_mirrorer_init(Object *obj) > +{ > + object_property_add_str(obj, "outdev", traffic_mirrorer_get_outdev, > + traffic_mirrorer_set_outdev, NULL); > +} > + > +static void traffic_mirrorer_fini(Object *obj) > +{ > + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); > + > + g_free(s->outdev); > +} > + > +static const TypeInfo traffic_mirrorer_info = { > + .name = TYPE_FILTER_TRAFFIC_MIRRORER, > + .parent = TYPE_NETFILTER, > + .class_init = traffic_mirrorer_class_init, > + .instance_init = traffic_mirrorer_init, > + .instance_finalize = traffic_mirrorer_fini, > + .instance_size = sizeof(MirrorerState), > +}; > + > +static void register_types(void) > +{ > + type_register_static(&traffic_mirrorer_info); > +} > + > +type_init(register_types); > diff --git a/qemu-options.hx b/qemu-options.hx > index 0eea4ee..ecfa297 100644 > --- a/qemu-options.hx > +++ b/qemu-options.hx > @@ -3670,6 +3670,11 @@ queue @var{all|rx|tx} is an option that can be applied to any netfilter. > @option{tx}: the filter is attached to the transmit queue of the netdev, > where it will receive packets sent by the netdev. > > +@item -object traffic-mirrorer,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid}[,queue=@var{all|rx|tx}] > + > +traffic-mirrorer on netdev @var{netdevid},mirror net packet to outdev. > +queue @var{all|rx|tx} is an option that can be applied to traffic-mirrorer. > + > @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 > diff --git a/vl.c b/vl.c > index 8dc34ce..4fe01bc 100644 > --- a/vl.c > +++ b/vl.c > @@ -2838,7 +2838,8 @@ static bool object_create_initial(const char *type) > * they depend on netdevs already existing > */ > if (g_str_equal(type, "filter-buffer") || > - g_str_equal(type, "filter-dump")) { > + g_str_equal(type, "filter-dump") || > + g_str_equal(type, "traffic-mirrorer")) { > return false; > } > >
On 01/27/2016 08:44 AM, Hailiang Zhang wrote: > On 2016/1/26 16:59, Zhang Chen wrote: >> From: ZhangChen <zhangchen.fnst@cn.fujitsu.com> >> >> Traffic-mirrorer is a plugin of netfilter. >> It make qemu has ability to copy and mirror guest's >> net packet. we output packet to chardev. >> >> usage: >> >> -netdev tap,id=hn0 >> -chardev socket,id=mirrorer0,host=ip_primary,port=X,server,nowait >> -traffic-mirrorer,id=m0,netdev=hn0,queue=tx,outdev=mirrorer0 >> >> Signed-off-by: ZhangChen <zhangchen.fnst@cn.fujitsu.com> >> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> >> --- >> net/Makefile.objs | 1 + >> net/traffic-mirrorer.c | 173 >> +++++++++++++++++++++++++++++++++++++++++++++++++ >> qemu-options.hx | 5 ++ >> vl.c | 3 +- >> 4 files changed, 181 insertions(+), 1 deletion(-) >> create mode 100644 net/traffic-mirrorer.c >> >> diff --git a/net/Makefile.objs b/net/Makefile.objs >> index 5fa2f97..6466764 100644 >> --- a/net/Makefile.objs >> +++ b/net/Makefile.objs >> @@ -15,3 +15,4 @@ common-obj-$(CONFIG_VDE) += vde.o >> common-obj-$(CONFIG_NETMAP) += netmap.o >> common-obj-y += filter.o >> common-obj-y += filter-buffer.o >> +common-obj-y += traffic-mirrorer.o >> diff --git a/net/traffic-mirrorer.c b/net/traffic-mirrorer.c >> new file mode 100644 >> index 0000000..3b0da82 >> --- /dev/null >> +++ b/net/traffic-mirrorer.c >> @@ -0,0 +1,173 @@ >> +/* >> + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. >> + * Copyright (c) 2016 FUJITSU LIMITED >> + * Copyright (c) 2016 Intel Corporation >> + * >> + * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> >> + * >> + * This work is licensed under the terms of the GNU GPL, version 2 or >> + * later. See the COPYING file in the top-level directory. >> + */ >> + >> +#include "net/filter.h" >> +#include "net/net.h" >> +#include "qemu-common.h" >> +#include "qapi/qmp/qerror.h" >> +#include "qapi-visit.h" >> +#include "qom/object.h" >> +#include "qemu/main-loop.h" >> +#include "qemu/error-report.h" >> +#include "trace.h" >> +#include "sysemu/char.h" >> +#include "qemu/iov.h" >> + >> +#define FILTER_TRAFFIC_MIRRORER(obj) \ >> + OBJECT_CHECK(MirrorerState, (obj), TYPE_FILTER_TRAFFIC_MIRRORER) >> + >> +#define TYPE_FILTER_TRAFFIC_MIRRORER "traffic-mirrorer" >> + >> +typedef struct MirrorerState { >> + NetFilterState parent_obj; >> + char *outdev; >> + CharDriverState *chr_out; >> + >> +} MirrorerState; >> + >> +static ssize_t traffic_mirrorer_send(NetFilterState *nf, >> + const struct iovec *iov, >> + int iovcnt) > > The indent of parameters. > I will fix it in next version. >> +{ >> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); >> + ssize_t ret = 0; >> + ssize_t size = 0; >> + char *buf; >> + >> + size = iov_size(iov, iovcnt); >> + if (!size) { >> + return 0; >> + } >> + >> + buf = g_malloc0(size); >> + iov_to_buf(iov, iovcnt, 0, buf, size); >> + ret = qemu_chr_fe_write(s->chr_out, (uint8_t *)&size, >> sizeof(size)); >> + if (ret < 0) { >> + g_free(buf); >> + return ret; >> + } >> + >> + ret = qemu_chr_fe_write(s->chr_out, (uint8_t *)buf, size); >> + g_free(buf); >> + return ret; >> +} >> + >> +static ssize_t traffic_mirrorer_receive_iov(NetFilterState *nf, >> + NetClientState *sender, >> + unsigned flags, >> + const struct iovec *iov, >> + int iovcnt, >> + NetPacketSent *sent_cb) >> +{ >> + /* >> + * We copy and mirror packet to outdev, >> + * then put back the packet. >> + */ >> + ssize_t ret = 0; >> + >> + ret = traffic_mirrorer_send(nf, iov, iovcnt); >> + if (ret < 0) { >> + error_report("traffic_mirrorer_send failed"); >> + } >> + >> + return 0; >> +} >> + >> +static void traffic_mirrorer_cleanup(NetFilterState *nf) >> +{ >> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); >> + >> + if (s->chr_out) { >> + qemu_chr_fe_release(s->chr_out); >> + } >> +} >> + >> +static void traffic_mirrorer_setup(NetFilterState *nf, Error **errp) >> +{ >> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); >> + >> + if (!s->outdev) { >> + error_setg(errp, "filter traffic mirrorer needs 'outdev' >> property set!" >> + "property set!"); > > Duplicate 'property set!'. > Thanks zhangchen >> + return; >> + } >> + >> + s->chr_out = qemu_chr_find(s->outdev); >> + if (s->chr_out == NULL) { >> + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, >> + "Device '%s' not found", s->outdev); >> + return; >> + } >> + >> + if (qemu_chr_fe_claim(s->chr_out) != 0) { >> + error_setg(errp, QERR_DEVICE_IN_USE, s->outdev); >> + return; >> + } >> +} >> + >> +static void traffic_mirrorer_class_init(ObjectClass *oc, void *data) >> +{ >> + NetFilterClass *nfc = NETFILTER_CLASS(oc); >> + >> + nfc->setup = traffic_mirrorer_setup; >> + nfc->cleanup = traffic_mirrorer_cleanup; >> + nfc->receive_iov = traffic_mirrorer_receive_iov; >> +} >> + >> +static char *traffic_mirrorer_get_outdev(Object *obj, Error **errp) >> +{ >> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); >> + >> + return g_strdup(s->outdev); >> +} >> + >> +static void >> +traffic_mirrorer_set_outdev(Object *obj, const char *value, Error >> **errp) >> +{ >> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); >> + >> + g_free(s->outdev); >> + s->outdev = g_strdup(value); >> + if (!s->outdev) { >> + error_setg(errp, "filter traffic mirrorer needs 'outdev' " >> + "property set!"); >> + return; >> + } >> +} >> + >> +static void traffic_mirrorer_init(Object *obj) >> +{ >> + object_property_add_str(obj, "outdev", traffic_mirrorer_get_outdev, >> + traffic_mirrorer_set_outdev, NULL); >> +} >> + >> +static void traffic_mirrorer_fini(Object *obj) >> +{ >> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); >> + >> + g_free(s->outdev); >> +} >> + >> +static const TypeInfo traffic_mirrorer_info = { >> + .name = TYPE_FILTER_TRAFFIC_MIRRORER, >> + .parent = TYPE_NETFILTER, >> + .class_init = traffic_mirrorer_class_init, >> + .instance_init = traffic_mirrorer_init, >> + .instance_finalize = traffic_mirrorer_fini, >> + .instance_size = sizeof(MirrorerState), >> +}; >> + >> +static void register_types(void) >> +{ >> + type_register_static(&traffic_mirrorer_info); >> +} >> + >> +type_init(register_types); >> diff --git a/qemu-options.hx b/qemu-options.hx >> index 0eea4ee..ecfa297 100644 >> --- a/qemu-options.hx >> +++ b/qemu-options.hx >> @@ -3670,6 +3670,11 @@ queue @var{all|rx|tx} is an option that can be >> applied to any netfilter. >> @option{tx}: the filter is attached to the transmit queue of the >> netdev, >> where it will receive packets sent by the netdev. >> >> +@item -object >> traffic-mirrorer,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid}[,queue=@var{all|rx|tx}] >> + >> +traffic-mirrorer on netdev @var{netdevid},mirror net packet to outdev. >> +queue @var{all|rx|tx} is an option that can be applied to >> traffic-mirrorer. >> + >> @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 >> diff --git a/vl.c b/vl.c >> index 8dc34ce..4fe01bc 100644 >> --- a/vl.c >> +++ b/vl.c >> @@ -2838,7 +2838,8 @@ static bool object_create_initial(const char >> *type) >> * they depend on netdevs already existing >> */ >> if (g_str_equal(type, "filter-buffer") || >> - g_str_equal(type, "filter-dump")) { >> + g_str_equal(type, "filter-dump") || >> + g_str_equal(type, "traffic-mirrorer")) { >> return false; >> } >> >> > > > > > . >
On 01/27/2016 03:46 AM, Dr. David Alan Gilbert wrote: > * Yang Hongyang (hongyang.yang@easystack.cn) wrote: >> >> On 01/26/2016 04:59 PM, Zhang Chen wrote: >>> From: ZhangChen <zhangchen.fnst@cn.fujitsu.com> >>> >>> Traffic-mirrorer is a plugin of netfilter. >> netfilter plugin fix >>> It make qemu has ability to copy and mirror guest's >> s/make/makes/ has the ability > Not quite. > 'It gives qemu the ability to...' > > (Sorry, I can't explain why!). I will fix it in next version. >>> net packet. we output packet to chardev. >> there seems no 'mirrorer' in english, I think the plugin name >> 'traffic-mirror' is enough. > Agreed. I will fix it in next version. Thanks for review~~ zhangchen > Dave > >>> usage: >>> >>> -netdev tap,id=hn0 >>> -chardev socket,id=mirrorer0,host=ip_primary,port=X,server,nowait >>> -traffic-mirrorer,id=m0,netdev=hn0,queue=tx,outdev=mirrorer0 >>> >>> Signed-off-by: ZhangChen <zhangchen.fnst@cn.fujitsu.com> >>> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> >> The code looks good overall, so: >> Reviewed-by: Yang Hongyang <hongyang.yang@easystack.cn> Thank you Yang~~~ >>> --- >>> net/Makefile.objs | 1 + >>> net/traffic-mirrorer.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ >>> qemu-options.hx | 5 ++ >>> vl.c | 3 +- >>> 4 files changed, 181 insertions(+), 1 deletion(-) >>> create mode 100644 net/traffic-mirrorer.c >>> >>> diff --git a/net/Makefile.objs b/net/Makefile.objs >>> index 5fa2f97..6466764 100644 >>> --- a/net/Makefile.objs >>> +++ b/net/Makefile.objs >>> @@ -15,3 +15,4 @@ common-obj-$(CONFIG_VDE) += vde.o >>> common-obj-$(CONFIG_NETMAP) += netmap.o >>> common-obj-y += filter.o >>> common-obj-y += filter-buffer.o >>> +common-obj-y += traffic-mirrorer.o >>> diff --git a/net/traffic-mirrorer.c b/net/traffic-mirrorer.c >>> new file mode 100644 >>> index 0000000..3b0da82 >>> --- /dev/null >>> +++ b/net/traffic-mirrorer.c >>> @@ -0,0 +1,173 @@ >>> +/* >>> + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. >>> + * Copyright (c) 2016 FUJITSU LIMITED >>> + * Copyright (c) 2016 Intel Corporation >>> + * >>> + * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> >>> + * >>> + * This work is licensed under the terms of the GNU GPL, version 2 or >>> + * later. See the COPYING file in the top-level directory. >>> + */ >>> + >>> +#include "net/filter.h" >>> +#include "net/net.h" >>> +#include "qemu-common.h" >>> +#include "qapi/qmp/qerror.h" >>> +#include "qapi-visit.h" >>> +#include "qom/object.h" >>> +#include "qemu/main-loop.h" >>> +#include "qemu/error-report.h" >>> +#include "trace.h" >>> +#include "sysemu/char.h" >>> +#include "qemu/iov.h" >>> + >>> +#define FILTER_TRAFFIC_MIRRORER(obj) \ >>> + OBJECT_CHECK(MirrorerState, (obj), TYPE_FILTER_TRAFFIC_MIRRORER) >>> + >>> +#define TYPE_FILTER_TRAFFIC_MIRRORER "traffic-mirrorer" >>> + >>> +typedef struct MirrorerState { >>> + NetFilterState parent_obj; >>> + char *outdev; >>> + CharDriverState *chr_out; >>> + >>> +} MirrorerState; >>> + >>> +static ssize_t traffic_mirrorer_send(NetFilterState *nf, >>> + const struct iovec *iov, >>> + int iovcnt) >>> +{ >>> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); >>> + ssize_t ret = 0; >>> + ssize_t size = 0; >>> + char *buf; >>> + >>> + size = iov_size(iov, iovcnt); >>> + if (!size) { >>> + return 0; >>> + } >>> + >>> + buf = g_malloc0(size); >>> + iov_to_buf(iov, iovcnt, 0, buf, size); >>> + ret = qemu_chr_fe_write(s->chr_out, (uint8_t *)&size, sizeof(size)); >>> + if (ret < 0) { >>> + g_free(buf); >>> + return ret; >>> + } >>> + >>> + ret = qemu_chr_fe_write(s->chr_out, (uint8_t *)buf, size); >>> + g_free(buf); >>> + return ret; >>> +} >>> + >>> +static ssize_t traffic_mirrorer_receive_iov(NetFilterState *nf, >>> + NetClientState *sender, >>> + unsigned flags, >>> + const struct iovec *iov, >>> + int iovcnt, >>> + NetPacketSent *sent_cb) >>> +{ >>> + /* >>> + * We copy and mirror packet to outdev, >>> + * then put back the packet. >>> + */ >>> + ssize_t ret = 0; >>> + >>> + ret = traffic_mirrorer_send(nf, iov, iovcnt); >>> + if (ret < 0) { >>> + error_report("traffic_mirrorer_send failed"); >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static void traffic_mirrorer_cleanup(NetFilterState *nf) >>> +{ >>> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); >>> + >>> + if (s->chr_out) { >>> + qemu_chr_fe_release(s->chr_out); >>> + } >>> +} >>> + >>> +static void traffic_mirrorer_setup(NetFilterState *nf, Error **errp) >>> +{ >>> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); >>> + >>> + if (!s->outdev) { >>> + error_setg(errp, "filter traffic mirrorer needs 'outdev' property set!" >>> + "property set!"); >>> + return; >>> + } >>> + >>> + s->chr_out = qemu_chr_find(s->outdev); >>> + if (s->chr_out == NULL) { >>> + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, >>> + "Device '%s' not found", s->outdev); >>> + return; >>> + } >>> + >>> + if (qemu_chr_fe_claim(s->chr_out) != 0) { >>> + error_setg(errp, QERR_DEVICE_IN_USE, s->outdev); >>> + return; >>> + } >>> +} >>> + >>> +static void traffic_mirrorer_class_init(ObjectClass *oc, void *data) >>> +{ >>> + NetFilterClass *nfc = NETFILTER_CLASS(oc); >>> + >>> + nfc->setup = traffic_mirrorer_setup; >>> + nfc->cleanup = traffic_mirrorer_cleanup; >>> + nfc->receive_iov = traffic_mirrorer_receive_iov; >>> +} >>> + >>> +static char *traffic_mirrorer_get_outdev(Object *obj, Error **errp) >>> +{ >>> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); >>> + >>> + return g_strdup(s->outdev); >>> +} >>> + >>> +static void >>> +traffic_mirrorer_set_outdev(Object *obj, const char *value, Error **errp) >>> +{ >>> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); >>> + >>> + g_free(s->outdev); >>> + s->outdev = g_strdup(value); >>> + if (!s->outdev) { >>> + error_setg(errp, "filter traffic mirrorer needs 'outdev' " >>> + "property set!"); >>> + return; >>> + } >>> +} >>> + >>> +static void traffic_mirrorer_init(Object *obj) >>> +{ >>> + object_property_add_str(obj, "outdev", traffic_mirrorer_get_outdev, >>> + traffic_mirrorer_set_outdev, NULL); >>> +} >>> + >>> +static void traffic_mirrorer_fini(Object *obj) >>> +{ >>> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); >>> + >>> + g_free(s->outdev); >>> +} >>> + >>> +static const TypeInfo traffic_mirrorer_info = { >>> + .name = TYPE_FILTER_TRAFFIC_MIRRORER, >>> + .parent = TYPE_NETFILTER, >>> + .class_init = traffic_mirrorer_class_init, >>> + .instance_init = traffic_mirrorer_init, >>> + .instance_finalize = traffic_mirrorer_fini, >>> + .instance_size = sizeof(MirrorerState), >>> +}; >>> + >>> +static void register_types(void) >>> +{ >>> + type_register_static(&traffic_mirrorer_info); >>> +} >>> + >>> +type_init(register_types); >>> diff --git a/qemu-options.hx b/qemu-options.hx >>> index 0eea4ee..ecfa297 100644 >>> --- a/qemu-options.hx >>> +++ b/qemu-options.hx >>> @@ -3670,6 +3670,11 @@ queue @var{all|rx|tx} is an option that can be applied to any netfilter. >>> @option{tx}: the filter is attached to the transmit queue of the netdev, >>> where it will receive packets sent by the netdev. >>> >>> +@item -object traffic-mirrorer,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid}[,queue=@var{all|rx|tx}] >>> + >>> +traffic-mirrorer on netdev @var{netdevid},mirror net packet to outdev. >>> +queue @var{all|rx|tx} is an option that can be applied to traffic-mirrorer. >>> + >>> @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 >>> diff --git a/vl.c b/vl.c >>> index 8dc34ce..4fe01bc 100644 >>> --- a/vl.c >>> +++ b/vl.c >>> @@ -2838,7 +2838,8 @@ static bool object_create_initial(const char *type) >>> * they depend on netdevs already existing >>> */ >>> if (g_str_equal(type, "filter-buffer") || >>> - g_str_equal(type, "filter-dump")) { >>> + g_str_equal(type, "filter-dump") || >>> + g_str_equal(type, "traffic-mirrorer")) { >>> return false; >>> } >>> >>> >> -- >> Thanks, >> Yang > -- > Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK > > > . >
On 01/26/2016 05:44 PM, Hailiang Zhang wrote: > On 2016/1/26 16:59, Zhang Chen wrote: >> From: ZhangChen <zhangchen.fnst@cn.fujitsu.com> >> >> Traffic-mirrorer is a plugin of netfilter. >> It make qemu has ability to copy and mirror guest's >> net packet. we output packet to chardev. >> >> +static void traffic_mirrorer_setup(NetFilterState *nf, Error **errp) >> +{ >> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); >> + >> + if (!s->outdev) { >> + error_setg(errp, "filter traffic mirrorer needs 'outdev' >> property set!" >> + "property set!"); > > Duplicate 'property set!'. For that matter, error_setg() messages should never end in '!'.
On 01/28/2016 12:10 AM, Eric Blake wrote: > On 01/26/2016 05:44 PM, Hailiang Zhang wrote: >> On 2016/1/26 16:59, Zhang Chen wrote: >>> From: ZhangChen <zhangchen.fnst@cn.fujitsu.com> >>> >>> Traffic-mirrorer is a plugin of netfilter. >>> It make qemu has ability to copy and mirror guest's >>> net packet. we output packet to chardev. >>> >>> +static void traffic_mirrorer_setup(NetFilterState *nf, Error **errp) >>> +{ >>> + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); >>> + >>> + if (!s->outdev) { >>> + error_setg(errp, "filter traffic mirrorer needs 'outdev' >>> property set!" >>> + "property set!"); >> Duplicate 'property set!'. > For that matter, error_setg() messages should never end in '!'. > Thanks, I will fix it in V3 zhangchen
diff --git a/net/Makefile.objs b/net/Makefile.objs index 5fa2f97..6466764 100644 --- a/net/Makefile.objs +++ b/net/Makefile.objs @@ -15,3 +15,4 @@ common-obj-$(CONFIG_VDE) += vde.o common-obj-$(CONFIG_NETMAP) += netmap.o common-obj-y += filter.o common-obj-y += filter-buffer.o +common-obj-y += traffic-mirrorer.o diff --git a/net/traffic-mirrorer.c b/net/traffic-mirrorer.c new file mode 100644 index 0000000..3b0da82 --- /dev/null +++ b/net/traffic-mirrorer.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * Copyright (c) 2016 FUJITSU LIMITED + * Copyright (c) 2016 Intel Corporation + * + * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "net/filter.h" +#include "net/net.h" +#include "qemu-common.h" +#include "qapi/qmp/qerror.h" +#include "qapi-visit.h" +#include "qom/object.h" +#include "qemu/main-loop.h" +#include "qemu/error-report.h" +#include "trace.h" +#include "sysemu/char.h" +#include "qemu/iov.h" + +#define FILTER_TRAFFIC_MIRRORER(obj) \ + OBJECT_CHECK(MirrorerState, (obj), TYPE_FILTER_TRAFFIC_MIRRORER) + +#define TYPE_FILTER_TRAFFIC_MIRRORER "traffic-mirrorer" + +typedef struct MirrorerState { + NetFilterState parent_obj; + char *outdev; + CharDriverState *chr_out; + +} MirrorerState; + +static ssize_t traffic_mirrorer_send(NetFilterState *nf, + const struct iovec *iov, + int iovcnt) +{ + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); + ssize_t ret = 0; + ssize_t size = 0; + char *buf; + + size = iov_size(iov, iovcnt); + if (!size) { + return 0; + } + + buf = g_malloc0(size); + iov_to_buf(iov, iovcnt, 0, buf, size); + ret = qemu_chr_fe_write(s->chr_out, (uint8_t *)&size, sizeof(size)); + if (ret < 0) { + g_free(buf); + return ret; + } + + ret = qemu_chr_fe_write(s->chr_out, (uint8_t *)buf, size); + g_free(buf); + return ret; +} + +static ssize_t traffic_mirrorer_receive_iov(NetFilterState *nf, + NetClientState *sender, + unsigned flags, + const struct iovec *iov, + int iovcnt, + NetPacketSent *sent_cb) +{ + /* + * We copy and mirror packet to outdev, + * then put back the packet. + */ + ssize_t ret = 0; + + ret = traffic_mirrorer_send(nf, iov, iovcnt); + if (ret < 0) { + error_report("traffic_mirrorer_send failed"); + } + + return 0; +} + +static void traffic_mirrorer_cleanup(NetFilterState *nf) +{ + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); + + if (s->chr_out) { + qemu_chr_fe_release(s->chr_out); + } +} + +static void traffic_mirrorer_setup(NetFilterState *nf, Error **errp) +{ + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(nf); + + if (!s->outdev) { + error_setg(errp, "filter traffic mirrorer needs 'outdev' property set!" + "property set!"); + return; + } + + s->chr_out = qemu_chr_find(s->outdev); + if (s->chr_out == NULL) { + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", s->outdev); + return; + } + + if (qemu_chr_fe_claim(s->chr_out) != 0) { + error_setg(errp, QERR_DEVICE_IN_USE, s->outdev); + return; + } +} + +static void traffic_mirrorer_class_init(ObjectClass *oc, void *data) +{ + NetFilterClass *nfc = NETFILTER_CLASS(oc); + + nfc->setup = traffic_mirrorer_setup; + nfc->cleanup = traffic_mirrorer_cleanup; + nfc->receive_iov = traffic_mirrorer_receive_iov; +} + +static char *traffic_mirrorer_get_outdev(Object *obj, Error **errp) +{ + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); + + return g_strdup(s->outdev); +} + +static void +traffic_mirrorer_set_outdev(Object *obj, const char *value, Error **errp) +{ + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); + + g_free(s->outdev); + s->outdev = g_strdup(value); + if (!s->outdev) { + error_setg(errp, "filter traffic mirrorer needs 'outdev' " + "property set!"); + return; + } +} + +static void traffic_mirrorer_init(Object *obj) +{ + object_property_add_str(obj, "outdev", traffic_mirrorer_get_outdev, + traffic_mirrorer_set_outdev, NULL); +} + +static void traffic_mirrorer_fini(Object *obj) +{ + MirrorerState *s = FILTER_TRAFFIC_MIRRORER(obj); + + g_free(s->outdev); +} + +static const TypeInfo traffic_mirrorer_info = { + .name = TYPE_FILTER_TRAFFIC_MIRRORER, + .parent = TYPE_NETFILTER, + .class_init = traffic_mirrorer_class_init, + .instance_init = traffic_mirrorer_init, + .instance_finalize = traffic_mirrorer_fini, + .instance_size = sizeof(MirrorerState), +}; + +static void register_types(void) +{ + type_register_static(&traffic_mirrorer_info); +} + +type_init(register_types); diff --git a/qemu-options.hx b/qemu-options.hx index 0eea4ee..ecfa297 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3670,6 +3670,11 @@ queue @var{all|rx|tx} is an option that can be applied to any netfilter. @option{tx}: the filter is attached to the transmit queue of the netdev, where it will receive packets sent by the netdev. +@item -object traffic-mirrorer,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid}[,queue=@var{all|rx|tx}] + +traffic-mirrorer on netdev @var{netdevid},mirror net packet to outdev. +queue @var{all|rx|tx} is an option that can be applied to traffic-mirrorer. + @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 diff --git a/vl.c b/vl.c index 8dc34ce..4fe01bc 100644 --- a/vl.c +++ b/vl.c @@ -2838,7 +2838,8 @@ static bool object_create_initial(const char *type) * they depend on netdevs already existing */ if (g_str_equal(type, "filter-buffer") || - g_str_equal(type, "filter-dump")) { + g_str_equal(type, "filter-dump") || + g_str_equal(type, "traffic-mirrorer")) { return false; }