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,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 8 19 +#define VIRTIO_NET_VM_VERSION 9
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 */
@@ -37,6 +37,8 @@ typedef struct VirtIONet @@ -37,6 +37,8 @@ typedef struct VirtIONet
37 uint8_t allmulti; 37 uint8_t allmulti;
38 struct { 38 struct {
39 int in_use; 39 int in_use;
  40 + uint8_t multi_overflow;
  41 + uint8_t uni_overflow;
40 uint8_t *macs; 42 uint8_t *macs;
41 } mac_table; 43 } mac_table;
42 uint32_t *vlans; 44 uint32_t *vlans;
@@ -98,6 +100,8 @@ static void virtio_net_reset(VirtIODevice *vdev) @@ -98,6 +100,8 @@ static void virtio_net_reset(VirtIODevice *vdev)
98 100
99 /* Flush any MAC and VLAN filter table state */ 101 /* Flush any MAC and VLAN filter table state */
100 n->mac_table.in_use = 0; 102 n->mac_table.in_use = 0;
  103 + n->mac_table.multi_overflow = 0;
  104 + n->mac_table.uni_overflow = 0;
101 memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); 105 memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
102 memset(n->vlans, 0, MAX_VLAN >> 3); 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,6 +172,8 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
168 return VIRTIO_NET_ERR; 172 return VIRTIO_NET_ERR;
169 173
170 n->mac_table.in_use = 0; 174 n->mac_table.in_use = 0;
  175 + n->mac_table.uni_overflow = 0;
  176 + n->mac_table.multi_overflow = 0;
171 memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); 177 memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
172 178
173 mac_data.entries = ldl_le_p(elem->out_sg[1].iov_base); 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,8 +187,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
181 mac_data.entries * ETH_ALEN); 187 mac_data.entries * ETH_ALEN);
182 n->mac_table.in_use += mac_data.entries; 188 n->mac_table.in_use += mac_data.entries;
183 } else { 189 } else {
184 - n->promisc = 1;  
185 - return VIRTIO_NET_OK; 190 + n->mac_table.uni_overflow = 1;
186 } 191 }
187 192
188 mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base); 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,8 +202,9 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
197 elem->out_sg[2].iov_base + sizeof(mac_data), 202 elem->out_sg[2].iov_base + sizeof(mac_data),
198 mac_data.entries * ETH_ALEN); 203 mac_data.entries * ETH_ALEN);
199 n->mac_table.in_use += mac_data.entries; 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 return VIRTIO_NET_OK; 210 return VIRTIO_NET_OK;
@@ -350,11 +356,13 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) @@ -350,11 +356,13 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
350 if (ptr[0] & 1) { // multicast 356 if (ptr[0] & 1) { // multicast
351 if (!memcmp(ptr, bcast, sizeof(bcast))) { 357 if (!memcmp(ptr, bcast, sizeof(bcast))) {
352 return 1; 358 return 1;
353 - } else if (n->allmulti) { 359 + } else if (n->allmulti || n->mac_table.multi_overflow) {
354 return 1; 360 return 1;
355 } 361 }
356 } else { // unicast 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 return 1; 366 return 1;
359 } 367 }
360 } 368 }
@@ -532,6 +540,8 @@ static void virtio_net_save(QEMUFile *f, void *opaque) @@ -532,6 +540,8 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
532 qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); 540 qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
533 qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); 541 qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
534 qemu_put_be32(f, 0); /* vnet-hdr placeholder */ 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 static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) 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,7 +578,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
568 n->mac_table.in_use * ETH_ALEN); 578 n->mac_table.in_use * ETH_ALEN);
569 } else if (n->mac_table.in_use) { 579 } else if (n->mac_table.in_use) {
570 qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR); 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 n->mac_table.in_use = 0; 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,6 +592,11 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
582 exit(1); 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 if (n->tx_timer_active) { 600 if (n->tx_timer_active) {
586 qemu_mod_timer(n->tx_timer, 601 qemu_mod_timer(n->tx_timer,
587 qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL); 602 qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);