From 015cb16699199b7c062f02a0b89a869fdb18330f Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 5 Jun 2009 14:47:18 -0600 Subject: [PATCH] virtio-net: Add new RX filter controls Add a few new RX modes to better control the receive_filter. These are all fairly obvious features that hardware could provide. Signed-off-by: Alex Williamson Signed-off-by: Mark McLoughlin --- hw/virtio-net.c | 40 ++++++++++++++++++++++++++++++++++++---- hw/virtio-net.h | 14 ++++++++++---- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 7863d5ddbf..a64244c1a2 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -16,7 +16,7 @@ #include "qemu-timer.h" #include "virtio-net.h" -#define VIRTIO_NET_VM_VERSION 9 +#define VIRTIO_NET_VM_VERSION 10 #define MAC_TABLE_ENTRIES 32 #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ @@ -35,6 +35,10 @@ typedef struct VirtIONet int mergeable_rx_bufs; uint8_t promisc; uint8_t allmulti; + uint8_t alluni; + uint8_t nomulti; + uint8_t nouni; + uint8_t nobcast; struct { int in_use; int first_multi; @@ -98,6 +102,10 @@ static void virtio_net_reset(VirtIODevice *vdev) /* Reset back to compatibility mode */ n->promisc = 1; n->allmulti = 0; + n->alluni = 0; + n->nomulti = 0; + n->nouni = 0; + n->nobcast = 0; /* Flush any MAC and VLAN filter table state */ n->mac_table.in_use = 0; @@ -114,7 +122,8 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev) (1 << VIRTIO_NET_F_STATUS) | (1 << VIRTIO_NET_F_CTRL_VQ) | (1 << VIRTIO_NET_F_CTRL_RX) | - (1 << VIRTIO_NET_F_CTRL_VLAN); + (1 << VIRTIO_NET_F_CTRL_VLAN) | + (1 << VIRTIO_NET_F_CTRL_RX_EXTRA); return features; } @@ -157,6 +166,14 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, n->promisc = on; else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI) n->allmulti = on; + else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLUNI) + n->alluni = on; + else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOMULTI) + n->nomulti = on; + else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOUNI) + n->nouni = on; + else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOBCAST) + n->nobcast = on; else return VIRTIO_NET_ERR; @@ -360,7 +377,9 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) if (ptr[0] & 1) { // multicast if (!memcmp(ptr, bcast, sizeof(bcast))) { - return 1; + return !n->nobcast; + } else if (n->nomulti) { + return 0; } else if (n->allmulti || n->mac_table.multi_overflow) { return 1; } @@ -371,7 +390,9 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) } } } else { // unicast - if (n->mac_table.uni_overflow) { + if (n->nouni) { + return 0; + } else if (n->alluni || n->mac_table.uni_overflow) { return 1; } else if (!memcmp(ptr, n->mac, ETH_ALEN)) { return 1; @@ -554,6 +575,10 @@ static void virtio_net_save(QEMUFile *f, void *opaque) qemu_put_be32(f, 0); /* vnet-hdr placeholder */ qemu_put_byte(f, n->mac_table.multi_overflow); qemu_put_byte(f, n->mac_table.uni_overflow); + qemu_put_byte(f, n->alluni); + qemu_put_byte(f, n->nomulti); + qemu_put_byte(f, n->nouni); + qemu_put_byte(f, n->nobcast); } static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) @@ -610,6 +635,13 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) n->mac_table.uni_overflow = qemu_get_byte(f); } + if (version_id >= 10) { + n->alluni = qemu_get_byte(f); + n->nomulti = qemu_get_byte(f); + n->nouni = qemu_get_byte(f); + n->nobcast = qemu_get_byte(f); + } + /* Find the first multicast entry in the saved MAC filter */ for (i = 0; i < n->mac_table.in_use; i++) { if (n->mac_table.macs[i * ETH_ALEN] & 1) { diff --git a/hw/virtio-net.h b/hw/virtio-net.h index 390fe10224..2085181673 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -43,6 +43,7 @@ #define VIRTIO_NET_F_CTRL_VQ 17 /* Control channel available */ #define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support */ #define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */ +#define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */ #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ @@ -103,14 +104,19 @@ typedef uint8_t virtio_net_ctrl_ack; #define VIRTIO_NET_ERR 1 /* - * Control the RX mode, ie. promisucous and allmulti. PROMISC and - * ALLMULTI commands require an "out" sg entry containing a 1 byte - * state value, zero = disable, non-zero = enable. These commands - * are supported with the VIRTIO_NET_F_CTRL_RX feature. + * Control the RX mode, ie. promisucous, allmulti, etc... + * All commands require an "out" sg entry containing a 1 byte + * state value, zero = disable, non-zero = enable. Commands + * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature. + * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA. */ #define VIRTIO_NET_CTRL_RX_MODE 0 #define VIRTIO_NET_CTRL_RX_MODE_PROMISC 0 #define VIRTIO_NET_CTRL_RX_MODE_ALLMULTI 1 + #define VIRTIO_NET_CTRL_RX_MODE_ALLUNI 2 + #define VIRTIO_NET_CTRL_RX_MODE_NOMULTI 3 + #define VIRTIO_NET_CTRL_RX_MODE_NOUNI 4 + #define VIRTIO_NET_CTRL_RX_MODE_NOBCAST 5 /* * Control the MAC filter table. -- GitLab