On 02/29/2016 08:23 PM, Zhang Chen wrote: > Filter-redirector is a netfilter plugin. > It gives qemu the ability to redirect net packet. > redirector can redirect filter's net packet to outdev. > and redirect indev's packet to filter. > > filter > + > | > | > redirector | > +-------------------------+ > | | | > | | | > | | | > indev +----------------+ +----------------> outdev > | | | > | | | > | | | > +-------------------------+ > | > | > v > filter > | > | > v > filter------> guest
As we've discussed, the actual destination should depend on "queue" parameter. E.g if queue = rx, the destination should be netdev not guest. > > usage: > > -netdev tap,id=hn0 > -chardev socket,id=s0,host=ip_primary,port=X,server,nowait > -chardev socket,id=s1,host=ip_primary,port=Y,server,nowait > -filter-redirector,id=r0,netdev=hn0,queue=tx/rx/all,indev=s0,outdev=s1 > > Signed-off-by: Zhang Chen <zhangchen.f...@cn.fujitsu.com> > Signed-off-by: Wen Congyang <we...@cn.fujitsu.com> > --- > net/Makefile.objs | 1 + > net/filter-redirector.c | 216 > ++++++++++++++++++++++++++++++++++++++++++++++++ > qemu-options.hx | 8 ++ > vl.c | 3 +- > 4 files changed, 227 insertions(+), 1 deletion(-) > create mode 100644 net/filter-redirector.c > > diff --git a/net/Makefile.objs b/net/Makefile.objs > index b7c22fd..8af9932 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 += filter-redirector.o > diff --git a/net/filter-redirector.c b/net/filter-redirector.c > new file mode 100644 > index 0000000..d0eb76d > --- /dev/null > +++ b/net/filter-redirector.c > @@ -0,0 +1,216 @@ > +/* > + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. > + * Copyright (c) 2016 FUJITSU LIMITED > + * Copyright (c) 2016 Intel Corporation > + * > + * Author: Zhang Chen <zhangchen.f...@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-traffic.h" > + > +#define FILTER_REDIRECTOR(obj) \ > + OBJECT_CHECK(TrafficState, (obj), TYPE_FILTER_REDIRECTOR) > + > +#define TYPE_FILTER_REDIRECTOR "filter-redirector" > +#define REDIRECT_HEADER_LEN sizeof(uint32_t) > + > +static int filter_redirector_send(NetFilterState *nf, > + const struct iovec *iov, > + int iovcnt) > +{ > + return filter_traffic_send(nf, iov, iovcnt); > +} > + > +static ssize_t filter_redirector_receive_iov(NetFilterState *nf, > + NetClientState *sender, > + unsigned flags, > + const struct iovec *iov, > + int iovcnt, > + NetPacketSent *sent_cb) > +{ > + TrafficState *s = FILTER_REDIRECTOR(nf); > + ssize_t ret = 0; > + > + if (s->chr_out) { > + ret = filter_redirector_send(nf, iov, iovcnt); > + if (ret < 0) { > + error_report("filter_redirector_send failed"); > + } > + return iov_size(iov, iovcnt); > + } else { > + return 0; > + } > +} > + > +static void filter_redirector_cleanup(NetFilterState *nf) > +{ > + TrafficState *s = FILTER_REDIRECTOR(nf); > + > + if (s->chr_in) { > + qemu_chr_fe_release(s->chr_in); > + } > + if (s->chr_out) { > + qemu_chr_fe_release(s->chr_out); > + } > +} > + > +static int redirector_chr_can_read(void *opaque) > +{ > + return REDIRECT_HEADER_LEN; > +} > + > +static void redirector_chr_read(void *opaque, const uint8_t *buf, int size) > +{ > + NetFilterState *nf = opaque; > + TrafficState *s = FILTER_REDIRECTOR(nf); > + uint32_t len; > + int ret = 0; > + uint8_t *recv_buf; > + int offset = size; > + > + while (offset < REDIRECT_HEADER_LEN) { > + ret = s->chr_in->chr_sync_read(s->chr_in, (uint8_t *)buf + offset, > + REDIRECT_HEADER_LEN - offset); > + if (ret == -1 && errno == EAGAIN) { > + g_usleep(100); > + } > + offset += ret; Why not use qemu_chr_fe_read_all() here? And what's better, instead of busy waiting/reading. You can save the partial packet in a temporary buffer, and do not forward it after it has been completely received. > + } > + > + memcpy(&len, buf, sizeof(len)); > + len = ntohl(len); > + > + if (len > 0 && len < NET_BUFSIZE) { > + recv_buf = g_malloc(len); > + ret = qemu_chr_fe_read_all(s->chr_in, recv_buf, len); > + if (ret != len) { > + error_report("filter-redirector recv buf failed"); > + g_free(recv_buf); > + return; > + } > + > + ret = qemu_net_queue_send(s->incoming_queue, nf->netdev, > + 0, (const uint8_t *)recv_buf, len, NULL); As I replied in last version. Sender should be chose depending on 'queues'. When 'queue=rx' sender should be be netdev's peer.