aboutsummaryrefslogtreecommitdiff
path: root/net/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/net.c')
-rw-r--r--net/net.c121
1 files changed, 93 insertions, 28 deletions
diff --git a/net/net.c b/net/net.c
index 28a5597..39af893 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)
@@ -285,8 +286,9 @@ 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);
}
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);
@@ -554,34 +561,42 @@ int qemu_can_send_packet(NetClientState *sender)
return 1;
}
-ssize_t qemu_deliver_packet(NetClientState *sender,
- unsigned flags,
- const uint8_t *data,
- size_t size,
- void *opaque)
+static ssize_t filter_receive_iov(NetClientState *nc,
+ NetFilterDirection direction,
+ NetClientState *sender,
+ unsigned flags,
+ const struct iovec *iov,
+ int iovcnt,
+ NetPacketSent *sent_cb)
{
- NetClientState *nc = opaque;
- ssize_t ret;
+ ssize_t ret = 0;
+ NetFilterState *nf = NULL;
- if (nc->link_down) {
- return size;
- }
-
- if (nc->receive_disabled) {
- return 0;
+ QTAILQ_FOREACH(nf, &nc->filters, next) {
+ ret = qemu_netfilter_receive(nf, direction, sender, flags, iov,
+ iovcnt, sent_cb);
+ if (ret) {
+ return ret;
+ }
}
- 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);
- }
+ return ret;
+}
- if (ret == 0) {
- nc->receive_disabled = 1;
- }
+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 ret;
+ return filter_receive_iov(nc, direction, sender, flags, &iov, 1, sent_cb);
}
void qemu_purge_queued_packets(NetClientState *nc)
@@ -625,6 +640,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");
@@ -635,6 +651,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);
@@ -660,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,
@@ -690,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) {
@@ -705,11 +745,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,
@@ -1125,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,