提交 8fd2a2f1 编写于 作者: A Alex Williamson 提交者: Mark McLoughlin

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: NAlex Williamson <alex.williamson@hp.com>
Signed-off-by: NMark McLoughlin <markmc@redhat.com>
上级 bbe2f399
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include "qemu-timer.h" #include "qemu-timer.h"
#include "virtio-net.h" #include "virtio-net.h"
#define VIRTIO_NET_VM_VERSION 8 #define VIRTIO_NET_VM_VERSION 9
#define MAC_TABLE_ENTRIES 32 #define MAC_TABLE_ENTRIES 32
#define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */
...@@ -37,6 +37,8 @@ typedef struct VirtIONet ...@@ -37,6 +37,8 @@ typedef struct VirtIONet
uint8_t allmulti; uint8_t allmulti;
struct { struct {
int in_use; int in_use;
uint8_t multi_overflow;
uint8_t uni_overflow;
uint8_t *macs; uint8_t *macs;
} mac_table; } mac_table;
uint32_t *vlans; 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)
/* Flush any MAC and VLAN filter table state */ /* Flush any MAC and VLAN filter table state */
n->mac_table.in_use = 0; n->mac_table.in_use = 0;
n->mac_table.multi_overflow = 0;
n->mac_table.uni_overflow = 0;
memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
memset(n->vlans, 0, MAX_VLAN >> 3); memset(n->vlans, 0, MAX_VLAN >> 3);
} }
...@@ -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,
return VIRTIO_NET_ERR; return VIRTIO_NET_ERR;
n->mac_table.in_use = 0; n->mac_table.in_use = 0;
n->mac_table.uni_overflow = 0;
n->mac_table.multi_overflow = 0;
memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
mac_data.entries = ldl_le_p(elem->out_sg[1].iov_base); 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,
mac_data.entries * ETH_ALEN); mac_data.entries * ETH_ALEN);
n->mac_table.in_use += mac_data.entries; n->mac_table.in_use += mac_data.entries;
} else { } else {
n->promisc = 1; n->mac_table.uni_overflow = 1;
return VIRTIO_NET_OK;
} }
mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base); 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,
elem->out_sg[2].iov_base + sizeof(mac_data), elem->out_sg[2].iov_base + sizeof(mac_data),
mac_data.entries * ETH_ALEN); mac_data.entries * ETH_ALEN);
n->mac_table.in_use += mac_data.entries; n->mac_table.in_use += mac_data.entries;
} else } else {
n->allmulti = 1; n->mac_table.multi_overflow = 1;
}
} }
return VIRTIO_NET_OK; 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)
if (ptr[0] & 1) { // multicast if (ptr[0] & 1) { // multicast
if (!memcmp(ptr, bcast, sizeof(bcast))) { if (!memcmp(ptr, bcast, sizeof(bcast))) {
return 1; return 1;
} else if (n->allmulti) { } else if (n->allmulti || n->mac_table.multi_overflow) {
return 1; return 1;
} }
} else { // unicast } else { // unicast
if (!memcmp(ptr, n->mac, ETH_ALEN)) { if (n->mac_table.uni_overflow) {
return 1;
} else if (!memcmp(ptr, n->mac, ETH_ALEN)) {
return 1; return 1;
} }
} }
...@@ -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)
qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
qemu_put_be32(f, 0); /* vnet-hdr placeholder */ qemu_put_be32(f, 0); /* vnet-hdr placeholder */
qemu_put_byte(f, n->mac_table.multi_overflow);
qemu_put_byte(f, n->mac_table.uni_overflow);
} }
static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) 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)
n->mac_table.in_use * ETH_ALEN); n->mac_table.in_use * ETH_ALEN);
} else if (n->mac_table.in_use) { } else if (n->mac_table.in_use) {
qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR); qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR);
n->promisc = 1; n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1;
n->mac_table.in_use = 0; n->mac_table.in_use = 0;
} }
} }
...@@ -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)
exit(1); exit(1);
} }
if (version_id >= 9) {
n->mac_table.multi_overflow = qemu_get_byte(f);
n->mac_table.uni_overflow = qemu_get_byte(f);
}
if (n->tx_timer_active) { if (n->tx_timer_active) {
qemu_mod_timer(n->tx_timer, qemu_mod_timer(n->tx_timer,
qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL); qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册