Message ID | 1441783481-17698-7-git-send-email-yanghy@cn.fujitsu.com |
---|---|
State | New |
Headers | show |
On 09/09/2015 03:24 PM, Yang Hongyang wrote: > add an API qemu_netfilter_pass_to_next() to pass the packet > to next filter. > > Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com> > Reviewed-by: Thomas Huth <thuth@redhat.com> > --- > v10: adjust as a NetQueueDeliverFunc > v9: fix a bug when curr filter chain is all > v5: fold params to NetPacket struct > --- > include/net/filter.h | 7 ++++++ > net/filter.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 67 insertions(+) > > diff --git a/include/net/filter.h b/include/net/filter.h > index 4557cb9..ed2bb66 100644 > --- a/include/net/filter.h > +++ b/include/net/filter.h > @@ -57,4 +57,11 @@ struct NetFilterState { > QTAILQ_ENTRY(NetFilterState) next; > }; > > +/* pass the packet to the next filter */ > +ssize_t qemu_netfilter_pass_to_next(NetClientState *sender, > + unsigned flags, > + const struct iovec *iov, > + int iovcnt, > + void *opaque); > + > #endif /* QEMU_NET_FILTER_H */ > diff --git a/net/filter.c b/net/filter.c > index 5192c6d..086f271 100644 > --- a/net/filter.c > +++ b/net/filter.c > @@ -14,9 +14,69 @@ > #include "net/net.h" > #include "net/vhost_net.h" > #include "qom/object_interfaces.h" > +#include "qemu/iov.h" > > static QTAILQ_HEAD(, NetFilterState) net_filters; > > +ssize_t qemu_netfilter_pass_to_next(NetClientState *sender, > + unsigned flags, > + const struct iovec *iov, > + int iovcnt, > + void *opaque) > +{ > + int ret = 0; > + int chain; > + NetFilterState *nf = opaque; > + NetFilterState *next = QTAILQ_NEXT(nf, next); > + > + if (!sender || !sender->peer) { > + /* no receiver, or sender been deleted, no need to pass it further */ > + goto out; > + } > + > + if (nf->chain == NET_FILTER_CHAIN_ALL) { > + if (sender == nf->netdev) { > + /* This packet is sent by netdev itself */ > + chain = NET_FILTER_CHAIN_OUT; > + } else { > + chain = NET_FILTER_CHAIN_IN; > + } > + } else { > + chain = nf->chain; > + } > + > + while (next) { > + if (next->chain == chain || next->chain == NET_FILTER_CHAIN_ALL) { > + /* > + * if qemu_netfilter_pass_to_next been called, means that > + * the packet has been hold by filter and has already retured size > + * to the sender, so sent_cb shouldn't be called later, just > + * pass NULL to next. > + */ > + ret = NETFILTER_GET_CLASS(OBJECT(next))->receive_iov( > + next, sender, flags, iov, iovcnt, NULL); > + if (ret) { > + return ret; > + } > + } > + next = QTAILQ_NEXT(next, next); > + } Nitpick: Kind of codes duplication with filter_receive(). May consider to unify them it you want to send next version. > + > + /* > + * We have gone through all filters, pass it to receiver. > + * Do the valid check again incase sender or receiver been > + * deleted while we go through filters. > + */ > + if (sender && sender->peer) { > + return qemu_net_queue_send_iov(sender->peer->incoming_queue, > + sender, flags, iov, iovcnt, NULL); > + } > + > +out: > + /* no receiver, or sender been deleted */ > + return iov_size(iov, iovcnt); > +} > + > static char *netfilter_get_netdev_id(Object *obj, Error **errp) > { > NetFilterState *nf = NETFILTER(obj);
diff --git a/include/net/filter.h b/include/net/filter.h index 4557cb9..ed2bb66 100644 --- a/include/net/filter.h +++ b/include/net/filter.h @@ -57,4 +57,11 @@ struct NetFilterState { QTAILQ_ENTRY(NetFilterState) next; }; +/* pass the packet to the next filter */ +ssize_t qemu_netfilter_pass_to_next(NetClientState *sender, + unsigned flags, + const struct iovec *iov, + int iovcnt, + void *opaque); + #endif /* QEMU_NET_FILTER_H */ diff --git a/net/filter.c b/net/filter.c index 5192c6d..086f271 100644 --- a/net/filter.c +++ b/net/filter.c @@ -14,9 +14,69 @@ #include "net/net.h" #include "net/vhost_net.h" #include "qom/object_interfaces.h" +#include "qemu/iov.h" static QTAILQ_HEAD(, NetFilterState) net_filters; +ssize_t qemu_netfilter_pass_to_next(NetClientState *sender, + unsigned flags, + const struct iovec *iov, + int iovcnt, + void *opaque) +{ + int ret = 0; + int chain; + NetFilterState *nf = opaque; + NetFilterState *next = QTAILQ_NEXT(nf, next); + + if (!sender || !sender->peer) { + /* no receiver, or sender been deleted, no need to pass it further */ + goto out; + } + + if (nf->chain == NET_FILTER_CHAIN_ALL) { + if (sender == nf->netdev) { + /* This packet is sent by netdev itself */ + chain = NET_FILTER_CHAIN_OUT; + } else { + chain = NET_FILTER_CHAIN_IN; + } + } else { + chain = nf->chain; + } + + while (next) { + if (next->chain == chain || next->chain == NET_FILTER_CHAIN_ALL) { + /* + * if qemu_netfilter_pass_to_next been called, means that + * the packet has been hold by filter and has already retured size + * to the sender, so sent_cb shouldn't be called later, just + * pass NULL to next. + */ + ret = NETFILTER_GET_CLASS(OBJECT(next))->receive_iov( + next, sender, flags, iov, iovcnt, NULL); + if (ret) { + return ret; + } + } + next = QTAILQ_NEXT(next, next); + } + + /* + * We have gone through all filters, pass it to receiver. + * Do the valid check again incase sender or receiver been + * deleted while we go through filters. + */ + if (sender && sender->peer) { + return qemu_net_queue_send_iov(sender->peer->incoming_queue, + sender, flags, iov, iovcnt, NULL); + } + +out: + /* no receiver, or sender been deleted */ + return iov_size(iov, iovcnt); +} + static char *netfilter_get_netdev_id(Object *obj, Error **errp) { NetFilterState *nf = NETFILTER(obj);