Commit 8fd2a2f1a9048b9e37a898c2a5e9ef59d0c1a095

Authored by Alex Williamson
Committed by Mark McLoughlin
1 parent bbe2f399

virtio-net: Fix MAC filter overflow handling

Overloading the promisc and allmulti flags for indicating filter
table overflow makes it difficult to track the actual requested
operating mode.  Split these out into separate flags.

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Showing 1 changed file with 23 additions and 8 deletions
hw/virtio-net.c
... ... @@ -16,7 +16,7 @@
16 16 #include "qemu-timer.h"
17 17 #include "virtio-net.h"
18 18  
19   -#define VIRTIO_NET_VM_VERSION 8
  19 +#define VIRTIO_NET_VM_VERSION 9
20 20  
21 21 #define MAC_TABLE_ENTRIES 32
22 22 #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */
... ... @@ -37,6 +37,8 @@ typedef struct VirtIONet
37 37 uint8_t allmulti;
38 38 struct {
39 39 int in_use;
  40 + uint8_t multi_overflow;
  41 + uint8_t uni_overflow;
40 42 uint8_t *macs;
41 43 } mac_table;
42 44 uint32_t *vlans;
... ... @@ -98,6 +100,8 @@ static void virtio_net_reset(VirtIODevice *vdev)
98 100  
99 101 /* Flush any MAC and VLAN filter table state */
100 102 n->mac_table.in_use = 0;
  103 + n->mac_table.multi_overflow = 0;
  104 + n->mac_table.uni_overflow = 0;
101 105 memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
102 106 memset(n->vlans, 0, MAX_VLAN >> 3);
103 107 }
... ... @@ -168,6 +172,8 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
168 172 return VIRTIO_NET_ERR;
169 173  
170 174 n->mac_table.in_use = 0;
  175 + n->mac_table.uni_overflow = 0;
  176 + n->mac_table.multi_overflow = 0;
171 177 memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
172 178  
173 179 mac_data.entries = ldl_le_p(elem->out_sg[1].iov_base);
... ... @@ -181,8 +187,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
181 187 mac_data.entries * ETH_ALEN);
182 188 n->mac_table.in_use += mac_data.entries;
183 189 } else {
184   - n->promisc = 1;
185   - return VIRTIO_NET_OK;
  190 + n->mac_table.uni_overflow = 1;
186 191 }
187 192  
188 193 mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base);
... ... @@ -197,8 +202,9 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
197 202 elem->out_sg[2].iov_base + sizeof(mac_data),
198 203 mac_data.entries * ETH_ALEN);
199 204 n->mac_table.in_use += mac_data.entries;
200   - } else
201   - n->allmulti = 1;
  205 + } else {
  206 + n->mac_table.multi_overflow = 1;
  207 + }
202 208 }
203 209  
204 210 return VIRTIO_NET_OK;
... ... @@ -350,11 +356,13 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
350 356 if (ptr[0] & 1) { // multicast
351 357 if (!memcmp(ptr, bcast, sizeof(bcast))) {
352 358 return 1;
353   - } else if (n->allmulti) {
  359 + } else if (n->allmulti || n->mac_table.multi_overflow) {
354 360 return 1;
355 361 }
356 362 } else { // unicast
357   - if (!memcmp(ptr, n->mac, ETH_ALEN)) {
  363 + if (n->mac_table.uni_overflow) {
  364 + return 1;
  365 + } else if (!memcmp(ptr, n->mac, ETH_ALEN)) {
358 366 return 1;
359 367 }
360 368 }
... ... @@ -532,6 +540,8 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
532 540 qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
533 541 qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
534 542 qemu_put_be32(f, 0); /* vnet-hdr placeholder */
  543 + qemu_put_byte(f, n->mac_table.multi_overflow);
  544 + qemu_put_byte(f, n->mac_table.uni_overflow);
535 545 }
536 546  
537 547 static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
... ... @@ -568,7 +578,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
568 578 n->mac_table.in_use * ETH_ALEN);
569 579 } else if (n->mac_table.in_use) {
570 580 qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR);
571   - n->promisc = 1;
  581 + n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1;
572 582 n->mac_table.in_use = 0;
573 583 }
574 584 }
... ... @@ -582,6 +592,11 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
582 592 exit(1);
583 593 }
584 594  
  595 + if (version_id >= 9) {
  596 + n->mac_table.multi_overflow = qemu_get_byte(f);
  597 + n->mac_table.uni_overflow = qemu_get_byte(f);
  598 + }
  599 +
585 600 if (n->tx_timer_active) {
586 601 qemu_mod_timer(n->tx_timer,
587 602 qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
... ...