From fdccce4596218e49ca4d0f5d4b3f0c453bd99ba0 Mon Sep 17 00:00:00 2001 From: Yang Hongyang Date: Wed, 7 Oct 2015 11:52:14 +0800 Subject: init/cleanup of netfilter object Add a netfilter object based on QOM. A netfilter is attached to a netdev, captures all network packets that pass through the netdev. When we delete the netdev, we also delete the netfilter object attached to it, because if the netdev is removed, the filter which attached to it is useless. Signed-off-by: Yang Hongyang Reviewed-by: Markus Armbruster Signed-off-by: Jason Wang --- net/net.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'net/net.c') diff --git a/net/net.c b/net/net.c index 28a5597b8d..033f4f3387 100644 --- a/net/net.c +++ b/net/net.c @@ -44,6 +44,7 @@ #include "qapi/opts-visitor.h" #include "qapi/dealloc-visitor.h" #include "sysemu/sysemu.h" +#include "net/filter.h" /* Net bridge is currently not supported for W32. */ #if !defined(_WIN32) @@ -287,6 +288,7 @@ static void qemu_net_client_setup(NetClientState *nc, nc->incoming_queue = qemu_new_net_queue(nc); nc->destructor = destructor; + QTAILQ_INIT(&nc->filters); } NetClientState *qemu_new_net_client(NetClientInfo *info, @@ -384,6 +386,7 @@ void qemu_del_net_client(NetClientState *nc) { NetClientState *ncs[MAX_QUEUE_NUM]; int queues, i; + NetFilterState *nf, *next; assert(nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC); @@ -395,6 +398,10 @@ void qemu_del_net_client(NetClientState *nc) MAX_QUEUE_NUM); assert(queues != 0); + QTAILQ_FOREACH_SAFE(nf, &nc->filters, next, next) { + object_unparent(OBJECT(nf)); + } + /* If there is a peer NIC, delete and cleanup client, but do not free. */ if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { NICState *nic = qemu_get_nic(nc->peer); -- cgit v1.2.3 From e64c770d1fa859bd8ee583d339b085fe345ac02b Mon Sep 17 00:00:00 2001 From: Yang Hongyang Date: Wed, 7 Oct 2015 11:52:15 +0800 Subject: netfilter: hook packets before net queue send Capture packets that will be sent. Signed-off-by: Yang Hongyang Reviewed-by: Thomas Huth Signed-off-by: Jason Wang --- net/net.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'net/net.c') diff --git a/net/net.c b/net/net.c index 033f4f3387..e27643d503 100644 --- a/net/net.c +++ b/net/net.c @@ -561,6 +561,44 @@ int qemu_can_send_packet(NetClientState *sender) return 1; } +static ssize_t filter_receive_iov(NetClientState *nc, + NetFilterDirection direction, + NetClientState *sender, + unsigned flags, + const struct iovec *iov, + int iovcnt, + NetPacketSent *sent_cb) +{ + ssize_t ret = 0; + NetFilterState *nf = NULL; + + QTAILQ_FOREACH(nf, &nc->filters, next) { + ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, + iovcnt, sent_cb); + if (ret) { + return ret; + } + } + + return ret; +} + +static ssize_t filter_receive(NetClientState *nc, + NetFilterDirection direction, + NetClientState *sender, + unsigned flags, + const uint8_t *data, + size_t size, + NetPacketSent *sent_cb) +{ + struct iovec iov = { + .iov_base = (void *)data, + .iov_len = size + }; + + return filter_receive_iov(nc, direction, sender, flags, &iov, 1, sent_cb); +} + ssize_t qemu_deliver_packet(NetClientState *sender, unsigned flags, const uint8_t *data, @@ -632,6 +670,7 @@ static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, NetPacketSent *sent_cb) { NetQueue *queue; + int ret; #ifdef DEBUG_NET printf("qemu_send_packet_async:\n"); @@ -642,6 +681,19 @@ static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, return size; } + /* Let filters handle the packet first */ + ret = filter_receive(sender, NET_FILTER_DIRECTION_TX, + sender, flags, buf, size, sent_cb); + if (ret) { + return ret; + } + + ret = filter_receive(sender->peer, NET_FILTER_DIRECTION_RX, + sender, flags, buf, size, sent_cb); + if (ret) { + return ret; + } + queue = sender->peer->incoming_queue; return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb); @@ -712,11 +764,25 @@ ssize_t qemu_sendv_packet_async(NetClientState *sender, NetPacketSent *sent_cb) { NetQueue *queue; + int ret; if (sender->link_down || !sender->peer) { return iov_size(iov, iovcnt); } + /* Let filters handle the packet first */ + ret = filter_receive_iov(sender, NET_FILTER_DIRECTION_TX, sender, + QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); + if (ret) { + return ret; + } + + ret = filter_receive_iov(sender->peer, NET_FILTER_DIRECTION_RX, sender, + QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); + if (ret) { + return ret; + } + queue = sender->peer->incoming_queue; return qemu_net_queue_send_iov(queue, sender, -- cgit v1.2.3 From fefe2a78abde932e0f340b21bded2c86def1d242 Mon Sep 17 00:00:00 2001 From: Yang Hongyang Date: Wed, 7 Oct 2015 11:52:16 +0800 Subject: net: merge qemu_deliver_packet and qemu_deliver_packet_iov qemu_deliver_packet_iov already have the compat delivery, we can drop qemu_deliver_packet. Signed-off-by: Yang Hongyang Signed-off-by: Jason Wang --- net/net.c | 51 ++++++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 35 deletions(-) (limited to 'net/net.c') diff --git a/net/net.c b/net/net.c index e27643d503..2f939f90c1 100644 --- a/net/net.c +++ b/net/net.c @@ -599,36 +599,6 @@ static ssize_t filter_receive(NetClientState *nc, return filter_receive_iov(nc, direction, sender, flags, &iov, 1, sent_cb); } -ssize_t qemu_deliver_packet(NetClientState *sender, - unsigned flags, - const uint8_t *data, - size_t size, - void *opaque) -{ - NetClientState *nc = opaque; - ssize_t ret; - - if (nc->link_down) { - return size; - } - - if (nc->receive_disabled) { - return 0; - } - - if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) { - ret = nc->info->receive_raw(nc, data, size); - } else { - ret = nc->info->receive(nc, data, size); - } - - if (ret == 0) { - nc->receive_disabled = 1; - } - - return ret; -} - void qemu_purge_queued_packets(NetClientState *nc) { if (!nc->peer) { @@ -719,14 +689,25 @@ ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) } static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov, - int iovcnt) + int iovcnt, unsigned flags) { - uint8_t buffer[NET_BUFSIZE]; + uint8_t buf[NET_BUFSIZE]; + uint8_t *buffer; size_t offset; - offset = iov_to_buf(iov, iovcnt, 0, buffer, sizeof(buffer)); + if (iovcnt == 1) { + buffer = iov[0].iov_base; + offset = iov[0].iov_len; + } else { + buffer = buf; + offset = iov_to_buf(iov, iovcnt, 0, buffer, sizeof(buffer)); + } - return nc->info->receive(nc, buffer, offset); + if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) { + return nc->info->receive_raw(nc, buffer, offset); + } else { + return nc->info->receive(nc, buffer, offset); + } } ssize_t qemu_deliver_packet_iov(NetClientState *sender, @@ -749,7 +730,7 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender, if (nc->info->receive_iov) { ret = nc->info->receive_iov(nc, iov, iovcnt); } else { - ret = nc_sendv_compat(nc, iov, iovcnt); + ret = nc_sendv_compat(nc, iov, iovcnt, flags); } if (ret == 0) { -- cgit v1.2.3 From 3e033a46a7e39ea31e15f1b53402df990977115a Mon Sep 17 00:00:00 2001 From: Yang Hongyang Date: Wed, 7 Oct 2015 11:52:17 +0800 Subject: net/queue: introduce NetQueueDeliverFunc net/queue.c has logic to send/queue/flush packets but a qemu_deliver_packet_iov() call is hardcoded. Abstract this func so that we can use our own deliver function in netfilter. Signed-off-by: Yang Hongyang Cc: Stefan Hajnoczi Signed-off-by: Jason Wang --- net/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/net.c') diff --git a/net/net.c b/net/net.c index 2f939f90c1..c0ebb13211 100644 --- a/net/net.c +++ b/net/net.c @@ -286,7 +286,7 @@ static void qemu_net_client_setup(NetClientState *nc, } QTAILQ_INSERT_TAIL(&net_clients, nc, next); - nc->incoming_queue = qemu_new_net_queue(nc); + nc->incoming_queue = qemu_new_net_queue(qemu_deliver_packet_iov, nc); nc->destructor = destructor; QTAILQ_INIT(&nc->filters); } -- cgit v1.2.3 From a4960f52e7f402a4b7402ace204283de7b9d4879 Mon Sep 17 00:00:00 2001 From: Yang Hongyang Date: Wed, 7 Oct 2015 11:52:19 +0800 Subject: netfilter: print filter info associate with the netdev When execute "info network", print filter info also. add a info_str member to NetFilterState, store specific filters info. Signed-off-by: Yang Hongyang Signed-off-by: Jason Wang --- net/net.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'net/net.c') diff --git a/net/net.c b/net/net.c index c0ebb13211..39af8930b4 100644 --- a/net/net.c +++ b/net/net.c @@ -1179,10 +1179,21 @@ void qmp_netdev_del(const char *id, Error **errp) void print_net_client(Monitor *mon, NetClientState *nc) { + NetFilterState *nf; + monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, nc->queue_index, NetClientOptionsKind_lookup[nc->info->type], nc->info_str); + if (!QTAILQ_EMPTY(&nc->filters)) { + monitor_printf(mon, "filters:\n"); + } + QTAILQ_FOREACH(nf, &nc->filters, next) { + monitor_printf(mon, " - %s: type=%s%s\n", + object_get_canonical_path_component(OBJECT(nf)), + object_get_typename(OBJECT(nf)), + nf->info_str); + } } RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, -- cgit v1.2.3