Commit 015cb16699199b7c062f02a0b89a869fdb18330f
Committed by
Mark McLoughlin
1 parent
2d9aba39
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 <alex.williamson@hp.com> Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Showing
2 changed files
with
46 additions
and
8 deletions
hw/virtio-net.c
| @@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
| 16 | #include "qemu-timer.h" | 16 | #include "qemu-timer.h" |
| 17 | #include "virtio-net.h" | 17 | #include "virtio-net.h" |
| 18 | 18 | ||
| 19 | -#define VIRTIO_NET_VM_VERSION 9 | 19 | +#define VIRTIO_NET_VM_VERSION 10 |
| 20 | 20 | ||
| 21 | #define MAC_TABLE_ENTRIES 32 | 21 | #define MAC_TABLE_ENTRIES 32 |
| 22 | #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ | 22 | #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ |
| @@ -35,6 +35,10 @@ typedef struct VirtIONet | @@ -35,6 +35,10 @@ typedef struct VirtIONet | ||
| 35 | int mergeable_rx_bufs; | 35 | int mergeable_rx_bufs; |
| 36 | uint8_t promisc; | 36 | uint8_t promisc; |
| 37 | uint8_t allmulti; | 37 | uint8_t allmulti; |
| 38 | + uint8_t alluni; | ||
| 39 | + uint8_t nomulti; | ||
| 40 | + uint8_t nouni; | ||
| 41 | + uint8_t nobcast; | ||
| 38 | struct { | 42 | struct { |
| 39 | int in_use; | 43 | int in_use; |
| 40 | int first_multi; | 44 | int first_multi; |
| @@ -98,6 +102,10 @@ static void virtio_net_reset(VirtIODevice *vdev) | @@ -98,6 +102,10 @@ static void virtio_net_reset(VirtIODevice *vdev) | ||
| 98 | /* Reset back to compatibility mode */ | 102 | /* Reset back to compatibility mode */ |
| 99 | n->promisc = 1; | 103 | n->promisc = 1; |
| 100 | n->allmulti = 0; | 104 | n->allmulti = 0; |
| 105 | + n->alluni = 0; | ||
| 106 | + n->nomulti = 0; | ||
| 107 | + n->nouni = 0; | ||
| 108 | + n->nobcast = 0; | ||
| 101 | 109 | ||
| 102 | /* Flush any MAC and VLAN filter table state */ | 110 | /* Flush any MAC and VLAN filter table state */ |
| 103 | n->mac_table.in_use = 0; | 111 | n->mac_table.in_use = 0; |
| @@ -114,7 +122,8 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev) | @@ -114,7 +122,8 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev) | ||
| 114 | (1 << VIRTIO_NET_F_STATUS) | | 122 | (1 << VIRTIO_NET_F_STATUS) | |
| 115 | (1 << VIRTIO_NET_F_CTRL_VQ) | | 123 | (1 << VIRTIO_NET_F_CTRL_VQ) | |
| 116 | (1 << VIRTIO_NET_F_CTRL_RX) | | 124 | (1 << VIRTIO_NET_F_CTRL_RX) | |
| 117 | - (1 << VIRTIO_NET_F_CTRL_VLAN); | 125 | + (1 << VIRTIO_NET_F_CTRL_VLAN) | |
| 126 | + (1 << VIRTIO_NET_F_CTRL_RX_EXTRA); | ||
| 118 | 127 | ||
| 119 | return features; | 128 | return features; |
| 120 | } | 129 | } |
| @@ -157,6 +166,14 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, | @@ -157,6 +166,14 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, | ||
| 157 | n->promisc = on; | 166 | n->promisc = on; |
| 158 | else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI) | 167 | else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI) |
| 159 | n->allmulti = on; | 168 | n->allmulti = on; |
| 169 | + else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLUNI) | ||
| 170 | + n->alluni = on; | ||
| 171 | + else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOMULTI) | ||
| 172 | + n->nomulti = on; | ||
| 173 | + else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOUNI) | ||
| 174 | + n->nouni = on; | ||
| 175 | + else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOBCAST) | ||
| 176 | + n->nobcast = on; | ||
| 160 | else | 177 | else |
| 161 | return VIRTIO_NET_ERR; | 178 | return VIRTIO_NET_ERR; |
| 162 | 179 | ||
| @@ -360,7 +377,9 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) | @@ -360,7 +377,9 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) | ||
| 360 | 377 | ||
| 361 | if (ptr[0] & 1) { // multicast | 378 | if (ptr[0] & 1) { // multicast |
| 362 | if (!memcmp(ptr, bcast, sizeof(bcast))) { | 379 | if (!memcmp(ptr, bcast, sizeof(bcast))) { |
| 363 | - return 1; | 380 | + return !n->nobcast; |
| 381 | + } else if (n->nomulti) { | ||
| 382 | + return 0; | ||
| 364 | } else if (n->allmulti || n->mac_table.multi_overflow) { | 383 | } else if (n->allmulti || n->mac_table.multi_overflow) { |
| 365 | return 1; | 384 | return 1; |
| 366 | } | 385 | } |
| @@ -371,7 +390,9 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) | @@ -371,7 +390,9 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) | ||
| 371 | } | 390 | } |
| 372 | } | 391 | } |
| 373 | } else { // unicast | 392 | } else { // unicast |
| 374 | - if (n->mac_table.uni_overflow) { | 393 | + if (n->nouni) { |
| 394 | + return 0; | ||
| 395 | + } else if (n->alluni || n->mac_table.uni_overflow) { | ||
| 375 | return 1; | 396 | return 1; |
| 376 | } else if (!memcmp(ptr, n->mac, ETH_ALEN)) { | 397 | } else if (!memcmp(ptr, n->mac, ETH_ALEN)) { |
| 377 | return 1; | 398 | return 1; |
| @@ -554,6 +575,10 @@ static void virtio_net_save(QEMUFile *f, void *opaque) | @@ -554,6 +575,10 @@ static void virtio_net_save(QEMUFile *f, void *opaque) | ||
| 554 | qemu_put_be32(f, 0); /* vnet-hdr placeholder */ | 575 | qemu_put_be32(f, 0); /* vnet-hdr placeholder */ |
| 555 | qemu_put_byte(f, n->mac_table.multi_overflow); | 576 | qemu_put_byte(f, n->mac_table.multi_overflow); |
| 556 | qemu_put_byte(f, n->mac_table.uni_overflow); | 577 | qemu_put_byte(f, n->mac_table.uni_overflow); |
| 578 | + qemu_put_byte(f, n->alluni); | ||
| 579 | + qemu_put_byte(f, n->nomulti); | ||
| 580 | + qemu_put_byte(f, n->nouni); | ||
| 581 | + qemu_put_byte(f, n->nobcast); | ||
| 557 | } | 582 | } |
| 558 | 583 | ||
| 559 | static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) | 584 | 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) | @@ -610,6 +635,13 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) | ||
| 610 | n->mac_table.uni_overflow = qemu_get_byte(f); | 635 | n->mac_table.uni_overflow = qemu_get_byte(f); |
| 611 | } | 636 | } |
| 612 | 637 | ||
| 638 | + if (version_id >= 10) { | ||
| 639 | + n->alluni = qemu_get_byte(f); | ||
| 640 | + n->nomulti = qemu_get_byte(f); | ||
| 641 | + n->nouni = qemu_get_byte(f); | ||
| 642 | + n->nobcast = qemu_get_byte(f); | ||
| 643 | + } | ||
| 644 | + | ||
| 613 | /* Find the first multicast entry in the saved MAC filter */ | 645 | /* Find the first multicast entry in the saved MAC filter */ |
| 614 | for (i = 0; i < n->mac_table.in_use; i++) { | 646 | for (i = 0; i < n->mac_table.in_use; i++) { |
| 615 | if (n->mac_table.macs[i * ETH_ALEN] & 1) { | 647 | if (n->mac_table.macs[i * ETH_ALEN] & 1) { |
hw/virtio-net.h
| @@ -43,6 +43,7 @@ | @@ -43,6 +43,7 @@ | ||
| 43 | #define VIRTIO_NET_F_CTRL_VQ 17 /* Control channel available */ | 43 | #define VIRTIO_NET_F_CTRL_VQ 17 /* Control channel available */ |
| 44 | #define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support */ | 44 | #define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support */ |
| 45 | #define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */ | 45 | #define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */ |
| 46 | +#define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */ | ||
| 46 | 47 | ||
| 47 | #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ | 48 | #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ |
| 48 | 49 | ||
| @@ -103,14 +104,19 @@ typedef uint8_t virtio_net_ctrl_ack; | @@ -103,14 +104,19 @@ typedef uint8_t virtio_net_ctrl_ack; | ||
| 103 | #define VIRTIO_NET_ERR 1 | 104 | #define VIRTIO_NET_ERR 1 |
| 104 | 105 | ||
| 105 | /* | 106 | /* |
| 106 | - * Control the RX mode, ie. promisucous and allmulti. PROMISC and | ||
| 107 | - * ALLMULTI commands require an "out" sg entry containing a 1 byte | ||
| 108 | - * state value, zero = disable, non-zero = enable. These commands | ||
| 109 | - * are supported with the VIRTIO_NET_F_CTRL_RX feature. | 107 | + * Control the RX mode, ie. promisucous, allmulti, etc... |
| 108 | + * All commands require an "out" sg entry containing a 1 byte | ||
| 109 | + * state value, zero = disable, non-zero = enable. Commands | ||
| 110 | + * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature. | ||
| 111 | + * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA. | ||
| 110 | */ | 112 | */ |
| 111 | #define VIRTIO_NET_CTRL_RX_MODE 0 | 113 | #define VIRTIO_NET_CTRL_RX_MODE 0 |
| 112 | #define VIRTIO_NET_CTRL_RX_MODE_PROMISC 0 | 114 | #define VIRTIO_NET_CTRL_RX_MODE_PROMISC 0 |
| 113 | #define VIRTIO_NET_CTRL_RX_MODE_ALLMULTI 1 | 115 | #define VIRTIO_NET_CTRL_RX_MODE_ALLMULTI 1 |
| 116 | + #define VIRTIO_NET_CTRL_RX_MODE_ALLUNI 2 | ||
| 117 | + #define VIRTIO_NET_CTRL_RX_MODE_NOMULTI 3 | ||
| 118 | + #define VIRTIO_NET_CTRL_RX_MODE_NOUNI 4 | ||
| 119 | + #define VIRTIO_NET_CTRL_RX_MODE_NOBCAST 5 | ||
| 114 | 120 | ||
| 115 | /* | 121 | /* |
| 116 | * Control the MAC filter table. | 122 | * Control the MAC filter table. |