Message ID | 1466681677-30487-2-git-send-email-zhangchen.fnst@cn.fujitsu.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 2016年06月23日 19:34, Zhang Chen wrote: > Packets coming from the primary char indev will be sent to outdev > Packets coming from the secondary char dev will be dropped > > usage: > > primary: > -netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown > -device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66 > -chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait > -chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait > -chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait > -chardev socket,id=compare0-0,host=3.3.3.3,port=9001 > -chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait > -chardev socket,id=compare_out0,host=3.3.3.3,port=9005 > -object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 > -object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out > -object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 > -object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0 > > secondary: > -netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown > -device e1000,netdev=hn0,mac=52:a4:00:12:78:66 > -chardev socket,id=red0,host=3.3.3.3,port=9003 > -chardev socket,id=red1,host=3.3.3.3,port=9004 > -object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 > -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 Consider we finally want a non-rfc patch, it's better to have a some explanations on the above configurations since it was not easy to for starters at first glance.Maybe you can use either a ascii figure or a paragraph. Also need to explain the parameter of colo-compare in detail. > > Signed-off-by: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> > Signed-off-by: Li Zhijian <lizhijian@cn.fujitsu.com> > Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> > --- > net/Makefile.objs | 1 + > net/colo-compare.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > qemu-options.hx | 34 ++++++++ > vl.c | 3 +- > 4 files changed, 268 insertions(+), 1 deletion(-) > create mode 100644 net/colo-compare.c > > diff --git a/net/Makefile.objs b/net/Makefile.objs > index b7c22fd..ba92f73 100644 > --- a/net/Makefile.objs > +++ b/net/Makefile.objs > @@ -16,3 +16,4 @@ common-obj-$(CONFIG_NETMAP) += netmap.o > common-obj-y += filter.o > common-obj-y += filter-buffer.o > common-obj-y += filter-mirror.o > +common-obj-y += colo-compare.o > diff --git a/net/colo-compare.c b/net/colo-compare.c > new file mode 100644 > index 0000000..a3e1456 > --- /dev/null > +++ b/net/colo-compare.c > @@ -0,0 +1,231 @@ > +/* > + * COarse-grain LOck-stepping Virtual Machines for Non-stop Service (COLO) > + * (a.k.a. Fault Tolerance or Continuous Replication) > + * > + * 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 "qemu/osdep.h" > +#include "qemu/error-report.h" > +#include "qemu-common.h" > +#include "qapi/qmp/qerror.h" > +#include "qapi/error.h" > +#include "net/net.h" > +#include "net/vhost_net.h" > +#include "qom/object_interfaces.h" > +#include "qemu/iov.h" > +#include "qom/object.h" > +#include "qemu/typedefs.h" > +#include "net/queue.h" > +#include "sysemu/char.h" > +#include "qemu/sockets.h" > +#include "qapi-visit.h" > +#include "trace.h" Looks like trace were not really used in the patch, you can delay the inclusion until is was really used. > + > +#define TYPE_COLO_COMPARE "colo-compare" > +#define COLO_COMPARE(obj) \ > + OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE) > + > +#define COMPARE_READ_LEN_MAX NET_BUFSIZE > + > +static QTAILQ_HEAD(, CompareState) net_compares = > + QTAILQ_HEAD_INITIALIZER(net_compares); What's the usage of this? A comment would be better. > + > +typedef struct CompareState { > + Object parent; > + > + char *pri_indev; > + char *sec_indev; > + char *outdev; > + CharDriverState *chr_pri_in; > + CharDriverState *chr_sec_in; > + CharDriverState *chr_out; > + QTAILQ_ENTRY(CompareState) next; > + SocketReadState pri_rs; > + SocketReadState sec_rs; > +} CompareState; > + > +typedef struct CompareClass { > + ObjectClass parent_class; > +} CompareClass; > + > +static char *compare_get_pri_indev(Object *obj, Error **errp) > +{ > + CompareState *s = COLO_COMPARE(obj); > + > + return g_strdup(s->pri_indev); > +} > + > +static void compare_set_pri_indev(Object *obj, const char *value, Error **errp) > +{ > + CompareState *s = COLO_COMPARE(obj); > + > + g_free(s->pri_indev); > + s->pri_indev = g_strdup(value); I think we need do something more than this, e.g release the orig dev and get the new one? Or just forbid setting this property. And looks like we have similar issues for sec_indev and outdev. > +} > + > +static char *compare_get_sec_indev(Object *obj, Error **errp) > +{ > + CompareState *s = COLO_COMPARE(obj); > + > + return g_strdup(s->sec_indev); > +} > + > +static void compare_set_sec_indev(Object *obj, const char *value, Error **errp) > +{ > + CompareState *s = COLO_COMPARE(obj); > + > + g_free(s->sec_indev); > + s->sec_indev = g_strdup(value); > +} > + > +static char *compare_get_outdev(Object *obj, Error **errp) > +{ > + CompareState *s = COLO_COMPARE(obj); > + > + return g_strdup(s->outdev); > +} > + > +static void compare_set_outdev(Object *obj, const char *value, Error **errp) > +{ > + CompareState *s = COLO_COMPARE(obj); > + > + g_free(s->outdev); > + s->outdev = g_strdup(value); > +} > + > +static void compare_pri_rs_finalize(SocketReadState *pri_rs) > +{ > + /* if packet_enqueue pri pkt failed we will send unsupported packet */ > +} > + > +static void compare_sec_rs_finalize(SocketReadState *sec_rs) > +{ > + /* if packet_enqueue sec pkt failed we will notify trace */ > +} > + > +/* > + * called from the main thread on the primary > + * to setup colo-compare. > + */ > +static void colo_compare_complete(UserCreatable *uc, Error **errp) > +{ > + CompareState *s = COLO_COMPARE(uc); > + > + if (!s->pri_indev || !s->sec_indev || !s->outdev) { > + error_setg(errp, "colo compare needs 'primary_in' ," > + "'secondary_in','outdev' property set"); > + return; > + } else if (!strcmp(s->pri_indev, s->outdev) || > + !strcmp(s->sec_indev, s->outdev) || > + !strcmp(s->pri_indev, s->sec_indev)) { > + error_setg(errp, "'indev' and 'outdev' could not be same " > + "for compare module"); > + return; > + } > + > + s->chr_pri_in = qemu_chr_find(s->pri_indev); > + if (s->chr_pri_in == NULL) { > + error_setg(errp, "Primary IN Device '%s' not found", > + s->pri_indev); > + return; > + } > + > + s->chr_sec_in = qemu_chr_find(s->sec_indev); > + if (s->chr_sec_in == NULL) { > + error_setg(errp, "Secondary IN Device '%s' not found", > + s->sec_indev); > + return; > + } > + > + s->chr_out = qemu_chr_find(s->outdev); > + if (s->chr_out == NULL) { > + error_setg(errp, "OUT Device '%s' not found", s->outdev); > + return; > + } > + > + qemu_chr_fe_claim_no_fail(s->chr_pri_in); > + > + qemu_chr_fe_claim_no_fail(s->chr_sec_in); > + > + qemu_chr_fe_claim_no_fail(s->chr_out); > + QTAILQ_INSERT_TAIL(&net_compares, s, next); > + > + net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize); > + net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize); > + > + return; > +} > + > +static void colo_compare_class_init(ObjectClass *oc, void *data) > +{ > + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); > + > + ucc->complete = colo_compare_complete; > +} > + > +static void colo_compare_init(Object *obj) > +{ > + object_property_add_str(obj, "primary_in", > + compare_get_pri_indev, compare_set_pri_indev, > + NULL); > + object_property_add_str(obj, "secondary_in", > + compare_get_sec_indev, compare_set_sec_indev, > + NULL); > + object_property_add_str(obj, "outdev", > + compare_get_outdev, compare_set_outdev, > + NULL); > +} > + > +static void colo_compare_finalize(Object *obj) > +{ > + CompareState *s = COLO_COMPARE(obj); > + > + if (s->chr_pri_in) { > + qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL); Why need do this? > + qemu_chr_fe_release(s->chr_pri_in); > + } > + if (s->chr_sec_in) { > + qemu_chr_add_handlers(s->chr_sec_in, NULL, NULL, NULL, NULL); > + qemu_chr_fe_release(s->chr_sec_in); > + } > + if (s->chr_out) { > + qemu_chr_fe_release(s->chr_out); > + } > + > + if (!QTAILQ_EMPTY(&net_compares)) { > + QTAILQ_REMOVE(&net_compares, s, next); > + } > + > + g_free(s->pri_indev); > + g_free(s->sec_indev); > + g_free(s->outdev); > +} > + > +static const TypeInfo colo_compare_info = { > + .name = TYPE_COLO_COMPARE, > + .parent = TYPE_OBJECT, > + .instance_size = sizeof(CompareState), > + .instance_init = colo_compare_init, > + .instance_finalize = colo_compare_finalize, > + .class_size = sizeof(CompareClass), > + .class_init = colo_compare_class_init, > + .interfaces = (InterfaceInfo[]) { > + { TYPE_USER_CREATABLE }, > + { } > + } > +}; > + > +static void register_types(void) > +{ > + type_register_static(&colo_compare_info); > +} > + > +type_init(register_types); > diff --git a/qemu-options.hx b/qemu-options.hx > index 587de8f..14bade5 100644 > --- a/qemu-options.hx > +++ b/qemu-options.hx > @@ -3866,6 +3866,40 @@ Dump the network traffic on netdev @var{dev} to the file specified by > The file format is libpcap, so it can be analyzed with tools such as tcpdump > or Wireshark. > > +@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid}, > +outdev=@var{chardevid} > + > +Colo-compare gets packet from primary_in@var{chardevid} and secondary_in@var{chardevid}, > +and outputs to outdev@var{chardevid}, we can use it with the help of filter-mirror and filter-redirector. Need a better organization of the above description. E.g it does not even mention any comparing. > + > +The simple usage: > + > +@example > + > +primary: > +-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown > +-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66 > +-chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait > +-chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait > +-chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait > +-chardev socket,id=compare0-0,host=3.3.3.3,port=9001 > +-chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait > +-chardev socket,id=compare_out0,host=3.3.3.3,port=9005 > +-object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 > +-object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out > +-object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 > +-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0 > + > +secondary: > +-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown > +-device e1000,netdev=hn0,mac=52:a4:00:12:78:66 > +-chardev socket,id=red0,host=3.3.3.3,port=9003 > +-chardev socket,id=red1,host=3.3.3.3,port=9004 > +-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 > +-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 > + > +@end example > + > @item -object secret,id=@var{id},data=@var{string},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}] > @item -object secret,id=@var{id},file=@var{filename},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}] > > diff --git a/vl.c b/vl.c > index cbe51ac..c6b9a6f 100644 > --- a/vl.c > +++ b/vl.c > @@ -2865,7 +2865,8 @@ static bool object_create_initial(const char *type) > if (g_str_equal(type, "filter-buffer") || > g_str_equal(type, "filter-dump") || > g_str_equal(type, "filter-mirror") || > - g_str_equal(type, "filter-redirector")) { > + g_str_equal(type, "filter-redirector") || > + g_str_equal(type, "colo-compare")) { > return false; > } >
On 07/08/2016 11:40 AM, Jason Wang wrote: > > > On 2016年06月23日 19:34, Zhang Chen wrote: >> Packets coming from the primary char indev will be sent to outdev >> Packets coming from the secondary char dev will be dropped >> >> usage: >> >> primary: >> -netdev >> tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown >> -device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66 >> -chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait >> -chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait >> -chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait >> -chardev socket,id=compare0-0,host=3.3.3.3,port=9001 >> -chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait >> -chardev socket,id=compare_out0,host=3.3.3.3,port=9005 >> -object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 >> -object >> filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out >> -object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 >> -object >> colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0 >> >> secondary: >> -netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down >> script=/etc/qemu-ifdown >> -device e1000,netdev=hn0,mac=52:a4:00:12:78:66 >> -chardev socket,id=red0,host=3.3.3.3,port=9003 >> -chardev socket,id=red1,host=3.3.3.3,port=9004 >> -object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 >> -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 > > Consider we finally want a non-rfc patch, it's better to have a some > explanations on the above configurations since it was not easy to for > starters at first glance.Maybe you can use either a ascii figure or a > paragraph. Also need to explain the parameter of colo-compare in detail. Make sense,I will add a ascii figure and some comments to explain it. > >> >> Signed-off-by: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> >> Signed-off-by: Li Zhijian <lizhijian@cn.fujitsu.com> >> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> >> --- >> net/Makefile.objs | 1 + >> net/colo-compare.c | 231 >> +++++++++++++++++++++++++++++++++++++++++++++++++++++ >> qemu-options.hx | 34 ++++++++ >> vl.c | 3 +- >> 4 files changed, 268 insertions(+), 1 deletion(-) >> create mode 100644 net/colo-compare.c >> >> diff --git a/net/Makefile.objs b/net/Makefile.objs >> index b7c22fd..ba92f73 100644 >> --- a/net/Makefile.objs >> +++ b/net/Makefile.objs >> @@ -16,3 +16,4 @@ common-obj-$(CONFIG_NETMAP) += netmap.o >> common-obj-y += filter.o >> common-obj-y += filter-buffer.o >> common-obj-y += filter-mirror.o >> +common-obj-y += colo-compare.o >> diff --git a/net/colo-compare.c b/net/colo-compare.c >> new file mode 100644 >> index 0000000..a3e1456 >> --- /dev/null >> +++ b/net/colo-compare.c >> @@ -0,0 +1,231 @@ >> +/* >> + * COarse-grain LOck-stepping Virtual Machines for Non-stop Service >> (COLO) >> + * (a.k.a. Fault Tolerance or Continuous Replication) >> + * >> + * 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 "qemu/osdep.h" >> +#include "qemu/error-report.h" >> +#include "qemu-common.h" >> +#include "qapi/qmp/qerror.h" >> +#include "qapi/error.h" >> +#include "net/net.h" >> +#include "net/vhost_net.h" >> +#include "qom/object_interfaces.h" >> +#include "qemu/iov.h" >> +#include "qom/object.h" >> +#include "qemu/typedefs.h" >> +#include "net/queue.h" >> +#include "sysemu/char.h" >> +#include "qemu/sockets.h" >> +#include "qapi-visit.h" >> +#include "trace.h" > > Looks like trace were not really used in the patch, you can delay the > inclusion until is was really used. OK~~~ > >> + >> +#define TYPE_COLO_COMPARE "colo-compare" >> +#define COLO_COMPARE(obj) \ >> + OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE) >> + >> +#define COMPARE_READ_LEN_MAX NET_BUFSIZE >> + >> +static QTAILQ_HEAD(, CompareState) net_compares = >> + QTAILQ_HEAD_INITIALIZER(net_compares); > > What's the usage of this? A comment would be better. If we need compare more than one netdev,we should use more than one colo-compare. we do checkpoint should flush all enqueued packet in colo-compare when work with colo-frame. we use this queue to find all colo-compare. So, look like no need here, I will move it to after patch. > >> + >> +typedef struct CompareState { >> + Object parent; >> + >> + char *pri_indev; >> + char *sec_indev; >> + char *outdev; >> + CharDriverState *chr_pri_in; >> + CharDriverState *chr_sec_in; >> + CharDriverState *chr_out; >> + QTAILQ_ENTRY(CompareState) next; >> + SocketReadState pri_rs; >> + SocketReadState sec_rs; >> +} CompareState; >> + >> +typedef struct CompareClass { >> + ObjectClass parent_class; >> +} CompareClass; >> + >> +static char *compare_get_pri_indev(Object *obj, Error **errp) >> +{ >> + CompareState *s = COLO_COMPARE(obj); >> + >> + return g_strdup(s->pri_indev); >> +} >> + >> +static void compare_set_pri_indev(Object *obj, const char *value, >> Error **errp) >> +{ >> + CompareState *s = COLO_COMPARE(obj); >> + >> + g_free(s->pri_indev); >> + s->pri_indev = g_strdup(value); > > I think we need do something more than this, e.g release the orig dev > and get the new one? Or just forbid setting this property. > Do you means that: qemu_chr_fe_release(s->chr_pri_in); If yes,in here we just get/set char* pri_indev(chardev's name). We don't get or set CharDriverState, so I think we needn't do more. > And looks like we have similar issues for sec_indev and outdev. > >> +} >> + >> +static char *compare_get_sec_indev(Object *obj, Error **errp) >> +{ >> + CompareState *s = COLO_COMPARE(obj); >> + >> + return g_strdup(s->sec_indev); >> +} >> + >> +static void compare_set_sec_indev(Object *obj, const char *value, >> Error **errp) >> +{ >> + CompareState *s = COLO_COMPARE(obj); >> + >> + g_free(s->sec_indev); >> + s->sec_indev = g_strdup(value); >> +} >> + >> +static char *compare_get_outdev(Object *obj, Error **errp) >> +{ >> + CompareState *s = COLO_COMPARE(obj); >> + >> + return g_strdup(s->outdev); >> +} >> + >> +static void compare_set_outdev(Object *obj, const char *value, Error >> **errp) >> +{ >> + CompareState *s = COLO_COMPARE(obj); >> + >> + g_free(s->outdev); >> + s->outdev = g_strdup(value); >> +} >> + >> +static void compare_pri_rs_finalize(SocketReadState *pri_rs) >> +{ >> + /* if packet_enqueue pri pkt failed we will send unsupported >> packet */ >> +} >> + >> +static void compare_sec_rs_finalize(SocketReadState *sec_rs) >> +{ >> + /* if packet_enqueue sec pkt failed we will notify trace */ >> +} >> + >> +/* >> + * called from the main thread on the primary >> + * to setup colo-compare. >> + */ >> +static void colo_compare_complete(UserCreatable *uc, Error **errp) >> +{ >> + CompareState *s = COLO_COMPARE(uc); >> + >> + if (!s->pri_indev || !s->sec_indev || !s->outdev) { >> + error_setg(errp, "colo compare needs 'primary_in' ," >> + "'secondary_in','outdev' property set"); >> + return; >> + } else if (!strcmp(s->pri_indev, s->outdev) || >> + !strcmp(s->sec_indev, s->outdev) || >> + !strcmp(s->pri_indev, s->sec_indev)) { >> + error_setg(errp, "'indev' and 'outdev' could not be same " >> + "for compare module"); >> + return; >> + } >> + >> + s->chr_pri_in = qemu_chr_find(s->pri_indev); >> + if (s->chr_pri_in == NULL) { >> + error_setg(errp, "Primary IN Device '%s' not found", >> + s->pri_indev); >> + return; >> + } >> + >> + s->chr_sec_in = qemu_chr_find(s->sec_indev); >> + if (s->chr_sec_in == NULL) { >> + error_setg(errp, "Secondary IN Device '%s' not found", >> + s->sec_indev); >> + return; >> + } >> + >> + s->chr_out = qemu_chr_find(s->outdev); >> + if (s->chr_out == NULL) { >> + error_setg(errp, "OUT Device '%s' not found", s->outdev); >> + return; >> + } >> + >> + qemu_chr_fe_claim_no_fail(s->chr_pri_in); >> + >> + qemu_chr_fe_claim_no_fail(s->chr_sec_in); >> + >> + qemu_chr_fe_claim_no_fail(s->chr_out); >> + QTAILQ_INSERT_TAIL(&net_compares, s, next); >> + >> + net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize); >> + net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize); >> + >> + return; >> +} >> + >> +static void colo_compare_class_init(ObjectClass *oc, void *data) >> +{ >> + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); >> + >> + ucc->complete = colo_compare_complete; >> +} >> + >> +static void colo_compare_init(Object *obj) >> +{ >> + object_property_add_str(obj, "primary_in", >> + compare_get_pri_indev, >> compare_set_pri_indev, >> + NULL); >> + object_property_add_str(obj, "secondary_in", >> + compare_get_sec_indev, >> compare_set_sec_indev, >> + NULL); >> + object_property_add_str(obj, "outdev", >> + compare_get_outdev, compare_set_outdev, >> + NULL); >> +} >> + >> +static void colo_compare_finalize(Object *obj) >> +{ >> + CompareState *s = COLO_COMPARE(obj); >> + >> + if (s->chr_pri_in) { >> + qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL); > > Why need do this? more safty before do qemu_chr_fe_release() for chardev like backends/rng-egd.c > >> + qemu_chr_fe_release(s->chr_pri_in); >> + } >> + if (s->chr_sec_in) { >> + qemu_chr_add_handlers(s->chr_sec_in, NULL, NULL, NULL, NULL); >> + qemu_chr_fe_release(s->chr_sec_in); >> + } >> + if (s->chr_out) { >> + qemu_chr_fe_release(s->chr_out); >> + } >> + >> + if (!QTAILQ_EMPTY(&net_compares)) { >> + QTAILQ_REMOVE(&net_compares, s, next); >> + } >> + >> + g_free(s->pri_indev); >> + g_free(s->sec_indev); >> + g_free(s->outdev); >> +} >> + >> +static const TypeInfo colo_compare_info = { >> + .name = TYPE_COLO_COMPARE, >> + .parent = TYPE_OBJECT, >> + .instance_size = sizeof(CompareState), >> + .instance_init = colo_compare_init, >> + .instance_finalize = colo_compare_finalize, >> + .class_size = sizeof(CompareClass), >> + .class_init = colo_compare_class_init, >> + .interfaces = (InterfaceInfo[]) { >> + { TYPE_USER_CREATABLE }, >> + { } >> + } >> +}; >> + >> +static void register_types(void) >> +{ >> + type_register_static(&colo_compare_info); >> +} >> + >> +type_init(register_types); >> diff --git a/qemu-options.hx b/qemu-options.hx >> index 587de8f..14bade5 100644 >> --- a/qemu-options.hx >> +++ b/qemu-options.hx >> @@ -3866,6 +3866,40 @@ Dump the network traffic on netdev @var{dev} >> to the file specified by >> The file format is libpcap, so it can be analyzed with tools such >> as tcpdump >> or Wireshark. >> +@item -object >> colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid}, >> +outdev=@var{chardevid} >> + >> +Colo-compare gets packet from primary_in@var{chardevid} and >> secondary_in@var{chardevid}, >> +and outputs to outdev@var{chardevid}, we can use it with the help of >> filter-mirror and filter-redirector. > > Need a better organization of the above description. E.g it does not > even mention any comparing. OK~ I will fix this in next version. Thanks Zhang Chen > >> + >> +The simple usage: >> + >> +@example >> + >> +primary: >> +-netdev >> tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown >> +-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66 >> +-chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait >> +-chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait >> +-chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait >> +-chardev socket,id=compare0-0,host=3.3.3.3,port=9001 >> +-chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait >> +-chardev socket,id=compare_out0,host=3.3.3.3,port=9005 >> +-object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 >> +-object >> filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out >> +-object >> filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 >> +-object >> colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0 >> + >> +secondary: >> +-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down >> script=/etc/qemu-ifdown >> +-device e1000,netdev=hn0,mac=52:a4:00:12:78:66 >> +-chardev socket,id=red0,host=3.3.3.3,port=9003 >> +-chardev socket,id=red1,host=3.3.3.3,port=9004 >> +-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 >> +-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 >> + >> +@end example >> + >> @item -object >> secret,id=@var{id},data=@var{string},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}] >> @item -object >> secret,id=@var{id},file=@var{filename},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}] >> diff --git a/vl.c b/vl.c >> index cbe51ac..c6b9a6f 100644 >> --- a/vl.c >> +++ b/vl.c >> @@ -2865,7 +2865,8 @@ static bool object_create_initial(const char >> *type) >> if (g_str_equal(type, "filter-buffer") || >> g_str_equal(type, "filter-dump") || >> g_str_equal(type, "filter-mirror") || >> - g_str_equal(type, "filter-redirector")) { >> + g_str_equal(type, "filter-redirector") || >> + g_str_equal(type, "colo-compare")) { >> return false; >> } > > > > . >
On 2016年07月08日 16:21, Zhang Chen wrote: > > > On 07/08/2016 11:40 AM, Jason Wang wrote: >> >> >> On 2016年06月23日 19:34, Zhang Chen wrote: >>> Packets coming from the primary char indev will be sent to outdev >>> Packets coming from the secondary char dev will be dropped >>> >>> usage: >>> >>> primary: >>> -netdev >>> tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown >>> -device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66 >>> -chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait >>> -chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait >>> -chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait >>> -chardev socket,id=compare0-0,host=3.3.3.3,port=9001 >>> -chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait >>> -chardev socket,id=compare_out0,host=3.3.3.3,port=9005 >>> -object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 >>> -object >>> filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out >>> -object >>> filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 >>> -object >>> colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0 >>> >>> secondary: >>> -netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down >>> script=/etc/qemu-ifdown >>> -device e1000,netdev=hn0,mac=52:a4:00:12:78:66 >>> -chardev socket,id=red0,host=3.3.3.3,port=9003 >>> -chardev socket,id=red1,host=3.3.3.3,port=9004 >>> -object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 >>> -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 >> >> Consider we finally want a non-rfc patch, it's better to have a some >> explanations on the above configurations since it was not easy to for >> starters at first glance.Maybe you can use either a ascii figure or a >> paragraph. Also need to explain the parameter of colo-compare in detail. > > Make sense,I will add a ascii figure and some comments to explain it. > >> >>> >>> Signed-off-by: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> >>> Signed-off-by: Li Zhijian <lizhijian@cn.fujitsu.com> >>> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> >>> --- >>> net/Makefile.objs | 1 + >>> net/colo-compare.c | 231 >>> +++++++++++++++++++++++++++++++++++++++++++++++++++++ >>> qemu-options.hx | 34 ++++++++ >>> vl.c | 3 +- >>> 4 files changed, 268 insertions(+), 1 deletion(-) >>> create mode 100644 net/colo-compare.c >>> >>> diff --git a/net/Makefile.objs b/net/Makefile.objs >>> index b7c22fd..ba92f73 100644 >>> --- a/net/Makefile.objs >>> +++ b/net/Makefile.objs >>> @@ -16,3 +16,4 @@ common-obj-$(CONFIG_NETMAP) += netmap.o >>> common-obj-y += filter.o >>> common-obj-y += filter-buffer.o >>> common-obj-y += filter-mirror.o >>> +common-obj-y += colo-compare.o >>> diff --git a/net/colo-compare.c b/net/colo-compare.c >>> new file mode 100644 >>> index 0000000..a3e1456 >>> --- /dev/null >>> +++ b/net/colo-compare.c >>> @@ -0,0 +1,231 @@ >>> +/* >>> + * COarse-grain LOck-stepping Virtual Machines for Non-stop Service >>> (COLO) >>> + * (a.k.a. Fault Tolerance or Continuous Replication) >>> + * >>> + * 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 "qemu/osdep.h" >>> +#include "qemu/error-report.h" >>> +#include "qemu-common.h" >>> +#include "qapi/qmp/qerror.h" >>> +#include "qapi/error.h" >>> +#include "net/net.h" >>> +#include "net/vhost_net.h" >>> +#include "qom/object_interfaces.h" >>> +#include "qemu/iov.h" >>> +#include "qom/object.h" >>> +#include "qemu/typedefs.h" >>> +#include "net/queue.h" >>> +#include "sysemu/char.h" >>> +#include "qemu/sockets.h" >>> +#include "qapi-visit.h" >>> +#include "trace.h" >> >> Looks like trace were not really used in the patch, you can delay the >> inclusion until is was really used. > > OK~~~ > >> >>> + >>> +#define TYPE_COLO_COMPARE "colo-compare" >>> +#define COLO_COMPARE(obj) \ >>> + OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE) >>> + >>> +#define COMPARE_READ_LEN_MAX NET_BUFSIZE >>> + >>> +static QTAILQ_HEAD(, CompareState) net_compares = >>> + QTAILQ_HEAD_INITIALIZER(net_compares); >> >> What's the usage of this? A comment would be better. > > If we need compare more than one netdev,we should use > more than one colo-compare. we do checkpoint should flush > all enqueued packet in colo-compare when work with colo-frame. > we use this queue to find all colo-compare. > So, look like no need here, I will move it to after patch. Yes unless you want a single colo comparing threads to do comparing for all netdevs. (But I agree, looks not need). > > >> >>> + >>> +typedef struct CompareState { >>> + Object parent; >>> + >>> + char *pri_indev; >>> + char *sec_indev; >>> + char *outdev; >>> + CharDriverState *chr_pri_in; >>> + CharDriverState *chr_sec_in; >>> + CharDriverState *chr_out; >>> + QTAILQ_ENTRY(CompareState) next; >>> + SocketReadState pri_rs; >>> + SocketReadState sec_rs; >>> +} CompareState; >>> + >>> +typedef struct CompareClass { >>> + ObjectClass parent_class; >>> +} CompareClass; >>> + >>> +static char *compare_get_pri_indev(Object *obj, Error **errp) >>> +{ >>> + CompareState *s = COLO_COMPARE(obj); >>> + >>> + return g_strdup(s->pri_indev); >>> +} >>> + >>> +static void compare_set_pri_indev(Object *obj, const char *value, >>> Error **errp) >>> +{ >>> + CompareState *s = COLO_COMPARE(obj); >>> + >>> + g_free(s->pri_indev); >>> + s->pri_indev = g_strdup(value); >> >> I think we need do something more than this, e.g release the orig dev >> and get the new one? Or just forbid setting this property. >> > > Do you means that: > qemu_chr_fe_release(s->chr_pri_in); > > If yes,in here we just get/set char* pri_indev(chardev's name). > We don't get or set CharDriverState, so I think we needn't do more. Maybe I miss something, but is there any usage for just changing chardev's name here? > > >> And looks like we have similar issues for sec_indev and outdev. >> >>> +} >>> + >>> [...] >>> + >>> +static void colo_compare_finalize(Object *obj) >>> +{ >>> + CompareState *s = COLO_COMPARE(obj); >>> + >>> + if (s->chr_pri_in) { >>> + qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL); >> >> Why need do this? > > more safty before do qemu_chr_fe_release() for chardev > like backends/rng-egd.c Ok, but looks like we don't set any handlers in the patch, so I don't get why need to clear it. For the things of eng-egd, I think we need fail if it was not a socket chardev. Vhost-use did similar check in net_vhost_chardev_opts() which maybe useful for here (we probably need this for mirror/redirector too). [...]
On 07/08/2016 05:12 PM, Jason Wang wrote: > > > On 2016年07月08日 16:21, Zhang Chen wrote: >> >> >> On 07/08/2016 11:40 AM, Jason Wang wrote: >>> >>> >>> On 2016年06月23日 19:34, Zhang Chen wrote: >>>> Packets coming from the primary char indev will be sent to outdev >>>> Packets coming from the secondary char dev will be dropped >>>> >>>> usage: >>>> >>>> primary: >>>> -netdev >>>> tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown >>>> -device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66 >>>> -chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait >>>> -chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait >>>> -chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait >>>> -chardev socket,id=compare0-0,host=3.3.3.3,port=9001 >>>> -chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait >>>> -chardev socket,id=compare_out0,host=3.3.3.3,port=9005 >>>> -object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 >>>> -object >>>> filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out >>>> -object >>>> filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 >>>> -object >>>> colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0 >>>> >>>> secondary: >>>> -netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down >>>> script=/etc/qemu-ifdown >>>> -device e1000,netdev=hn0,mac=52:a4:00:12:78:66 >>>> -chardev socket,id=red0,host=3.3.3.3,port=9003 >>>> -chardev socket,id=red1,host=3.3.3.3,port=9004 >>>> -object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 >>>> -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 >>> >>> Consider we finally want a non-rfc patch, it's better to have a some >>> explanations on the above configurations since it was not easy to >>> for starters at first glance.Maybe you can use either a ascii figure >>> or a paragraph. Also need to explain the parameter of colo-compare >>> in detail. >> >> Make sense,I will add a ascii figure and some comments to explain it. >> >>> >>>> >>>> Signed-off-by: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> >>>> Signed-off-by: Li Zhijian <lizhijian@cn.fujitsu.com> >>>> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> >>>> --- >>>> net/Makefile.objs | 1 + >>>> net/colo-compare.c | 231 >>>> +++++++++++++++++++++++++++++++++++++++++++++++++++++ >>>> qemu-options.hx | 34 ++++++++ >>>> vl.c | 3 +- >>>> 4 files changed, 268 insertions(+), 1 deletion(-) >>>> create mode 100644 net/colo-compare.c >>>> >>>> diff --git a/net/Makefile.objs b/net/Makefile.objs >>>> index b7c22fd..ba92f73 100644 >>>> --- a/net/Makefile.objs >>>> +++ b/net/Makefile.objs >>>> @@ -16,3 +16,4 @@ common-obj-$(CONFIG_NETMAP) += netmap.o >>>> common-obj-y += filter.o >>>> common-obj-y += filter-buffer.o >>>> common-obj-y += filter-mirror.o >>>> +common-obj-y += colo-compare.o >>>> diff --git a/net/colo-compare.c b/net/colo-compare.c >>>> new file mode 100644 >>>> index 0000000..a3e1456 >>>> --- /dev/null >>>> +++ b/net/colo-compare.c >>>> @@ -0,0 +1,231 @@ >>>> +/* >>>> + * COarse-grain LOck-stepping Virtual Machines for Non-stop >>>> Service (COLO) >>>> + * (a.k.a. Fault Tolerance or Continuous Replication) >>>> + * >>>> + * 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 "qemu/osdep.h" >>>> +#include "qemu/error-report.h" >>>> +#include "qemu-common.h" >>>> +#include "qapi/qmp/qerror.h" >>>> +#include "qapi/error.h" >>>> +#include "net/net.h" >>>> +#include "net/vhost_net.h" >>>> +#include "qom/object_interfaces.h" >>>> +#include "qemu/iov.h" >>>> +#include "qom/object.h" >>>> +#include "qemu/typedefs.h" >>>> +#include "net/queue.h" >>>> +#include "sysemu/char.h" >>>> +#include "qemu/sockets.h" >>>> +#include "qapi-visit.h" >>>> +#include "trace.h" >>> >>> Looks like trace were not really used in the patch, you can delay >>> the inclusion until is was really used. >> >> OK~~~ >> >>> >>>> + >>>> +#define TYPE_COLO_COMPARE "colo-compare" >>>> +#define COLO_COMPARE(obj) \ >>>> + OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE) >>>> + >>>> +#define COMPARE_READ_LEN_MAX NET_BUFSIZE >>>> + >>>> +static QTAILQ_HEAD(, CompareState) net_compares = >>>> + QTAILQ_HEAD_INITIALIZER(net_compares); >>> >>> What's the usage of this? A comment would be better. >> >> If we need compare more than one netdev,we should use >> more than one colo-compare. we do checkpoint should flush >> all enqueued packet in colo-compare when work with colo-frame. >> we use this queue to find all colo-compare. >> So, look like no need here, I will move it to after patch. > > Yes unless you want a single colo comparing threads to do comparing > for all netdevs. (But I agree, looks not need). > >> >> >>> >>>> + >>>> +typedef struct CompareState { >>>> + Object parent; >>>> + >>>> + char *pri_indev; >>>> + char *sec_indev; >>>> + char *outdev; >>>> + CharDriverState *chr_pri_in; >>>> + CharDriverState *chr_sec_in; >>>> + CharDriverState *chr_out; >>>> + QTAILQ_ENTRY(CompareState) next; >>>> + SocketReadState pri_rs; >>>> + SocketReadState sec_rs; >>>> +} CompareState; >>>> + >>>> +typedef struct CompareClass { >>>> + ObjectClass parent_class; >>>> +} CompareClass; >>>> + >>>> +static char *compare_get_pri_indev(Object *obj, Error **errp) >>>> +{ >>>> + CompareState *s = COLO_COMPARE(obj); >>>> + >>>> + return g_strdup(s->pri_indev); >>>> +} >>>> + >>>> +static void compare_set_pri_indev(Object *obj, const char *value, >>>> Error **errp) >>>> +{ >>>> + CompareState *s = COLO_COMPARE(obj); >>>> + >>>> + g_free(s->pri_indev); >>>> + s->pri_indev = g_strdup(value); >>> >>> I think we need do something more than this, e.g release the orig >>> dev and get the new one? Or just forbid setting this property. >>> >> >> Do you means that: >> qemu_chr_fe_release(s->chr_pri_in); >> >> If yes,in here we just get/set char* pri_indev(chardev's name). >> We don't get or set CharDriverState, so I think we needn't do more. > > Maybe I miss something, but is there any usage for just changing > chardev's name here? Yes, colo-compare get the name of chardev and save it. like primary_in=xxx, secondary_in=xxxx,outdev=xxxxx. > >> >> >>> And looks like we have similar issues for sec_indev and outdev. >>> >>>> +} >>>> + >>>> > > [...] > >>>> + >>>> +static void colo_compare_finalize(Object *obj) >>>> +{ >>>> + CompareState *s = COLO_COMPARE(obj); >>>> + >>>> + if (s->chr_pri_in) { >>>> + qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL); >>> >>> Why need do this? >> >> more safty before do qemu_chr_fe_release() for chardev >> like backends/rng-egd.c > > Ok, but looks like we don't set any handlers in the patch, so I don't > get why need to clear it. > > For the things of eng-egd, I think we need fail if it was not a socket > chardev. Vhost-use did similar check in net_vhost_chardev_opts() which > maybe useful for here (we probably need this for mirror/redirector too). > > [...] > > > . >
diff --git a/net/Makefile.objs b/net/Makefile.objs index b7c22fd..ba92f73 100644 --- a/net/Makefile.objs +++ b/net/Makefile.objs @@ -16,3 +16,4 @@ common-obj-$(CONFIG_NETMAP) += netmap.o common-obj-y += filter.o common-obj-y += filter-buffer.o common-obj-y += filter-mirror.o +common-obj-y += colo-compare.o diff --git a/net/colo-compare.c b/net/colo-compare.c new file mode 100644 index 0000000..a3e1456 --- /dev/null +++ b/net/colo-compare.c @@ -0,0 +1,231 @@ +/* + * COarse-grain LOck-stepping Virtual Machines for Non-stop Service (COLO) + * (a.k.a. Fault Tolerance or Continuous Replication) + * + * 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 "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qemu-common.h" +#include "qapi/qmp/qerror.h" +#include "qapi/error.h" +#include "net/net.h" +#include "net/vhost_net.h" +#include "qom/object_interfaces.h" +#include "qemu/iov.h" +#include "qom/object.h" +#include "qemu/typedefs.h" +#include "net/queue.h" +#include "sysemu/char.h" +#include "qemu/sockets.h" +#include "qapi-visit.h" +#include "trace.h" + +#define TYPE_COLO_COMPARE "colo-compare" +#define COLO_COMPARE(obj) \ + OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE) + +#define COMPARE_READ_LEN_MAX NET_BUFSIZE + +static QTAILQ_HEAD(, CompareState) net_compares = + QTAILQ_HEAD_INITIALIZER(net_compares); + +typedef struct CompareState { + Object parent; + + char *pri_indev; + char *sec_indev; + char *outdev; + CharDriverState *chr_pri_in; + CharDriverState *chr_sec_in; + CharDriverState *chr_out; + QTAILQ_ENTRY(CompareState) next; + SocketReadState pri_rs; + SocketReadState sec_rs; +} CompareState; + +typedef struct CompareClass { + ObjectClass parent_class; +} CompareClass; + +static char *compare_get_pri_indev(Object *obj, Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + + return g_strdup(s->pri_indev); +} + +static void compare_set_pri_indev(Object *obj, const char *value, Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + + g_free(s->pri_indev); + s->pri_indev = g_strdup(value); +} + +static char *compare_get_sec_indev(Object *obj, Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + + return g_strdup(s->sec_indev); +} + +static void compare_set_sec_indev(Object *obj, const char *value, Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + + g_free(s->sec_indev); + s->sec_indev = g_strdup(value); +} + +static char *compare_get_outdev(Object *obj, Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + + return g_strdup(s->outdev); +} + +static void compare_set_outdev(Object *obj, const char *value, Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + + g_free(s->outdev); + s->outdev = g_strdup(value); +} + +static void compare_pri_rs_finalize(SocketReadState *pri_rs) +{ + /* if packet_enqueue pri pkt failed we will send unsupported packet */ +} + +static void compare_sec_rs_finalize(SocketReadState *sec_rs) +{ + /* if packet_enqueue sec pkt failed we will notify trace */ +} + +/* + * called from the main thread on the primary + * to setup colo-compare. + */ +static void colo_compare_complete(UserCreatable *uc, Error **errp) +{ + CompareState *s = COLO_COMPARE(uc); + + if (!s->pri_indev || !s->sec_indev || !s->outdev) { + error_setg(errp, "colo compare needs 'primary_in' ," + "'secondary_in','outdev' property set"); + return; + } else if (!strcmp(s->pri_indev, s->outdev) || + !strcmp(s->sec_indev, s->outdev) || + !strcmp(s->pri_indev, s->sec_indev)) { + error_setg(errp, "'indev' and 'outdev' could not be same " + "for compare module"); + return; + } + + s->chr_pri_in = qemu_chr_find(s->pri_indev); + if (s->chr_pri_in == NULL) { + error_setg(errp, "Primary IN Device '%s' not found", + s->pri_indev); + return; + } + + s->chr_sec_in = qemu_chr_find(s->sec_indev); + if (s->chr_sec_in == NULL) { + error_setg(errp, "Secondary IN Device '%s' not found", + s->sec_indev); + return; + } + + s->chr_out = qemu_chr_find(s->outdev); + if (s->chr_out == NULL) { + error_setg(errp, "OUT Device '%s' not found", s->outdev); + return; + } + + qemu_chr_fe_claim_no_fail(s->chr_pri_in); + + qemu_chr_fe_claim_no_fail(s->chr_sec_in); + + qemu_chr_fe_claim_no_fail(s->chr_out); + QTAILQ_INSERT_TAIL(&net_compares, s, next); + + net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize); + net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize); + + return; +} + +static void colo_compare_class_init(ObjectClass *oc, void *data) +{ + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + + ucc->complete = colo_compare_complete; +} + +static void colo_compare_init(Object *obj) +{ + object_property_add_str(obj, "primary_in", + compare_get_pri_indev, compare_set_pri_indev, + NULL); + object_property_add_str(obj, "secondary_in", + compare_get_sec_indev, compare_set_sec_indev, + NULL); + object_property_add_str(obj, "outdev", + compare_get_outdev, compare_set_outdev, + NULL); +} + +static void colo_compare_finalize(Object *obj) +{ + CompareState *s = COLO_COMPARE(obj); + + if (s->chr_pri_in) { + qemu_chr_add_handlers(s->chr_pri_in, NULL, NULL, NULL, NULL); + qemu_chr_fe_release(s->chr_pri_in); + } + if (s->chr_sec_in) { + qemu_chr_add_handlers(s->chr_sec_in, NULL, NULL, NULL, NULL); + qemu_chr_fe_release(s->chr_sec_in); + } + if (s->chr_out) { + qemu_chr_fe_release(s->chr_out); + } + + if (!QTAILQ_EMPTY(&net_compares)) { + QTAILQ_REMOVE(&net_compares, s, next); + } + + g_free(s->pri_indev); + g_free(s->sec_indev); + g_free(s->outdev); +} + +static const TypeInfo colo_compare_info = { + .name = TYPE_COLO_COMPARE, + .parent = TYPE_OBJECT, + .instance_size = sizeof(CompareState), + .instance_init = colo_compare_init, + .instance_finalize = colo_compare_finalize, + .class_size = sizeof(CompareClass), + .class_init = colo_compare_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void register_types(void) +{ + type_register_static(&colo_compare_info); +} + +type_init(register_types); diff --git a/qemu-options.hx b/qemu-options.hx index 587de8f..14bade5 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3866,6 +3866,40 @@ Dump the network traffic on netdev @var{dev} to the file specified by The file format is libpcap, so it can be analyzed with tools such as tcpdump or Wireshark. +@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid}, +outdev=@var{chardevid} + +Colo-compare gets packet from primary_in@var{chardevid} and secondary_in@var{chardevid}, +and outputs to outdev@var{chardevid}, we can use it with the help of filter-mirror and filter-redirector. + +The simple usage: + +@example + +primary: +-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown +-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66 +-chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait +-chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait +-chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait +-chardev socket,id=compare0-0,host=3.3.3.3,port=9001 +-chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait +-chardev socket,id=compare_out0,host=3.3.3.3,port=9005 +-object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 +-object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out +-object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 +-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0 + +secondary: +-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown +-device e1000,netdev=hn0,mac=52:a4:00:12:78:66 +-chardev socket,id=red0,host=3.3.3.3,port=9003 +-chardev socket,id=red1,host=3.3.3.3,port=9004 +-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 +-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 + +@end example + @item -object secret,id=@var{id},data=@var{string},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}] @item -object secret,id=@var{id},file=@var{filename},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}] diff --git a/vl.c b/vl.c index cbe51ac..c6b9a6f 100644 --- a/vl.c +++ b/vl.c @@ -2865,7 +2865,8 @@ static bool object_create_initial(const char *type) if (g_str_equal(type, "filter-buffer") || g_str_equal(type, "filter-dump") || g_str_equal(type, "filter-mirror") || - g_str_equal(type, "filter-redirector")) { + g_str_equal(type, "filter-redirector") || + g_str_equal(type, "colo-compare")) { return false; }