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 37 uint8_t allmulti;
38 38 struct {
39 39 int in_use;
  40 + int first_multi;
40 41 uint8_t multi_overflow;
41 42 uint8_t uni_overflow;
42 43 uint8_t *macs;
... ... @@ -100,6 +101,7 @@ static void virtio_net_reset(VirtIODevice *vdev)
100 101  
101 102 /* Flush any MAC and VLAN filter table state */
102 103 n->mac_table.in_use = 0;
  104 + n->mac_table.first_multi = 0;
103 105 n->mac_table.multi_overflow = 0;
104 106 n->mac_table.uni_overflow = 0;
105 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 174 return VIRTIO_NET_ERR;
173 175  
174 176 n->mac_table.in_use = 0;
  177 + n->mac_table.first_multi = 0;
175 178 n->mac_table.uni_overflow = 0;
176 179 n->mac_table.multi_overflow = 0;
177 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 193 n->mac_table.uni_overflow = 1;
191 194 }
192 195  
  196 + n->mac_table.first_multi = n->mac_table.in_use;
  197 +
193 198 mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base);
194 199  
195 200 if (sizeof(mac_data.entries) +
... ... @@ -359,17 +364,24 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
359 364 } else if (n->allmulti || n->mac_table.multi_overflow) {
360 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 373 } else { // unicast
363 374 if (n->mac_table.uni_overflow) {
364 375 return 1;
365 376 } else if (!memcmp(ptr, n->mac, ETH_ALEN)) {
366 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 387 return 0;
... ... @@ -547,6 +559,7 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
547 559 static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
548 560 {
549 561 VirtIONet *n = opaque;
  562 + int i;
550 563  
551 564 if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
552 565 return -EINVAL;
... ... @@ -597,6 +610,14 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
597 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 621 if (n->tx_timer_active) {
601 622 qemu_mod_timer(n->tx_timer,
602 623 qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
... ...