Commit 2d9aba3961dd6c18cdafecc8ce31b330b45e2723

Authored by Alex Williamson
Committed by Mark McLoughlin
1 parent 8fd2a2f1

virtio-net: MAC filter optimization

The MAC filter table is received from the guest as two separate
buffers, one with unicast entries, the other with multicast
entries.  If we track the index dividing the two sets, we can
avoid searching the part of the table with the wrong type of
entries.

We could store this index as part of the save image, but its
trivially easy to discover it on load.

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Showing 1 changed file with 25 additions and 4 deletions
hw/virtio-net.c
@@ -37,6 +37,7 @@ typedef struct VirtIONet @@ -37,6 +37,7 @@ typedef struct VirtIONet
37 uint8_t allmulti; 37 uint8_t allmulti;
38 struct { 38 struct {
39 int in_use; 39 int in_use;
  40 + int first_multi;
40 uint8_t multi_overflow; 41 uint8_t multi_overflow;
41 uint8_t uni_overflow; 42 uint8_t uni_overflow;
42 uint8_t *macs; 43 uint8_t *macs;
@@ -100,6 +101,7 @@ static void virtio_net_reset(VirtIODevice *vdev) @@ -100,6 +101,7 @@ static void virtio_net_reset(VirtIODevice *vdev)
100 101
101 /* Flush any MAC and VLAN filter table state */ 102 /* Flush any MAC and VLAN filter table state */
102 n->mac_table.in_use = 0; 103 n->mac_table.in_use = 0;
  104 + n->mac_table.first_multi = 0;
103 n->mac_table.multi_overflow = 0; 105 n->mac_table.multi_overflow = 0;
104 n->mac_table.uni_overflow = 0; 106 n->mac_table.uni_overflow = 0;
105 memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); 107 memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
@@ -172,6 +174,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, @@ -172,6 +174,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
172 return VIRTIO_NET_ERR; 174 return VIRTIO_NET_ERR;
173 175
174 n->mac_table.in_use = 0; 176 n->mac_table.in_use = 0;
  177 + n->mac_table.first_multi = 0;
175 n->mac_table.uni_overflow = 0; 178 n->mac_table.uni_overflow = 0;
176 n->mac_table.multi_overflow = 0; 179 n->mac_table.multi_overflow = 0;
177 memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); 180 memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
@@ -190,6 +193,8 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, @@ -190,6 +193,8 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
190 n->mac_table.uni_overflow = 1; 193 n->mac_table.uni_overflow = 1;
191 } 194 }
192 195
  196 + n->mac_table.first_multi = n->mac_table.in_use;
  197 +
193 mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base); 198 mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base);
194 199
195 if (sizeof(mac_data.entries) + 200 if (sizeof(mac_data.entries) +
@@ -359,17 +364,24 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) @@ -359,17 +364,24 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
359 } else if (n->allmulti || n->mac_table.multi_overflow) { 364 } else if (n->allmulti || n->mac_table.multi_overflow) {
360 return 1; 365 return 1;
361 } 366 }
  367 +
  368 + for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
  369 + if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
  370 + return 1;
  371 + }
  372 + }
362 } else { // unicast 373 } else { // unicast
363 if (n->mac_table.uni_overflow) { 374 if (n->mac_table.uni_overflow) {
364 return 1; 375 return 1;
365 } else if (!memcmp(ptr, n->mac, ETH_ALEN)) { 376 } else if (!memcmp(ptr, n->mac, ETH_ALEN)) {
366 return 1; 377 return 1;
367 } 378 }
368 - }  
369 379
370 - for (i = 0; i < n->mac_table.in_use; i++) {  
371 - if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN))  
372 - return 1; 380 + for (i = 0; i < n->mac_table.first_multi; i++) {
  381 + if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
  382 + return 1;
  383 + }
  384 + }
373 } 385 }
374 386
375 return 0; 387 return 0;
@@ -547,6 +559,7 @@ static void virtio_net_save(QEMUFile *f, void *opaque) @@ -547,6 +559,7 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
547 static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) 559 static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
548 { 560 {
549 VirtIONet *n = opaque; 561 VirtIONet *n = opaque;
  562 + int i;
550 563
551 if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) 564 if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
552 return -EINVAL; 565 return -EINVAL;
@@ -597,6 +610,14 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) @@ -597,6 +610,14 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
597 n->mac_table.uni_overflow = qemu_get_byte(f); 610 n->mac_table.uni_overflow = qemu_get_byte(f);
598 } 611 }
599 612
  613 + /* Find the first multicast entry in the saved MAC filter */
  614 + for (i = 0; i < n->mac_table.in_use; i++) {
  615 + if (n->mac_table.macs[i * ETH_ALEN] & 1) {
  616 + break;
  617 + }
  618 + }
  619 + n->mac_table.first_multi = i;
  620 +
600 if (n->tx_timer_active) { 621 if (n->tx_timer_active) {
601 qemu_mod_timer(n->tx_timer, 622 qemu_mod_timer(n->tx_timer,
602 qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL); 623 qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);