From: Alex Williamson <alex.williamson@hp.com>
To: anthony@codemonkey.ws, qemu-devel@nongnu.org
Cc: markmc@redhat.com, kvm@vger.kernel.org, alex.williamson@hp.com
Subject: [PATCH v3 7/8] qemu:virtio-net: Add additional MACs via a filter table
Date: Wed, 04 Feb 2009 17:18:27 -0700 [thread overview]
Message-ID: <20090205001827.27879.65637.stgit@kvm.aw> (raw)
In-Reply-To: <20090205001707.27879.22745.stgit@kvm.aw>
Create a filter table and allow the guest to populate it with the
MAC class control commands. We manage the size and usage of the
filter table including enabling promiscuous and all-multi modes
as necessary. The guest should therefore assume the table is
infinite. Eventually this might allow us to bind directly to a
hardware NIC and manipulate a physical MAC filter.
The specifics of the TABLE_SET command are documented in
virtio-net.h. Separate buffers in the same command are used
for unicaste and multicast addresses for priority and
sychronization. With this we can export the VIRTIO_NET_F_CTRL_RX
feature bit.
Signed-off-by: Alex Williamson <alex.williamson@hp.com>
---
hw/virtio-net.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
hw/virtio-net.h | 22 ++++++++++++++
2 files changed, 109 insertions(+), 2 deletions(-)
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 001169d..524ef37 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -16,7 +16,9 @@
#include "qemu-timer.h"
#include "virtio-net.h"
-#define VIRTIO_NET_VM_VERSION 4
+#define VIRTIO_NET_VM_VERSION 5
+
+#define MAC_TABLE_ENTRIES 32
typedef struct VirtIONet
{
@@ -32,6 +34,10 @@ typedef struct VirtIONet
int mergeable_rx_bufs;
int promisc;
int allmulti;
+ struct {
+ int in_use;
+ uint8_t *macs;
+ } mac_table;
} VirtIONet;
/* TODO
@@ -87,13 +93,18 @@ static void virtio_net_reset(VirtIODevice *vdev)
/* Reset back to compatibility mode */
n->promisc = 1;
n->allmulti = 0;
+
+ /* Flush any MAC filter table state */
+ n->mac_table.in_use = 0;
+ memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
}
static uint32_t virtio_net_get_features(VirtIODevice *vdev)
{
uint32_t features = (1 << VIRTIO_NET_F_MAC) |
(1 << VIRTIO_NET_F_STATUS) |
- (1 << VIRTIO_NET_F_CTRL_VQ);
+ (1 << VIRTIO_NET_F_CTRL_VQ) |
+ (1 << VIRTIO_NET_F_CTRL_RX);
return features;
}
@@ -127,6 +138,53 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
return VIRTIO_NET_OK;
}
+static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
+ VirtQueueElement *elem)
+{
+ struct virtio_net_ctrl_mac mac_data;
+
+ if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET || elem->out_num != 3 ||
+ elem->out_sg[1].iov_len < sizeof(mac_data) ||
+ elem->out_sg[2].iov_len < sizeof(mac_data))
+ return VIRTIO_NET_ERR;
+
+ n->mac_table.in_use = 0;
+ memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
+
+ mac_data.entries = ldl_le_p(elem->out_sg[1].iov_base);
+
+ if (sizeof(mac_data.entries) +
+ (mac_data.entries * ETH_ALEN) > elem->out_sg[1].iov_len)
+ return VIRTIO_NET_ERR;
+
+ if (mac_data.entries <= MAC_TABLE_ENTRIES) {
+ memcpy(n->mac_table.macs, elem->out_sg[1].iov_base + sizeof(mac_data),
+ mac_data.entries * ETH_ALEN);
+ n->mac_table.in_use += mac_data.entries;
+ } else {
+ n->promisc = 1;
+ return VIRTIO_NET_OK;
+ }
+
+ mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base);
+
+ if (sizeof(mac_data.entries) +
+ (mac_data.entries * ETH_ALEN) > elem->out_sg[2].iov_len)
+ return VIRTIO_NET_ERR;
+
+ if (mac_data.entries) {
+ if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
+ memcpy(n->mac_table.macs + (n->mac_table.in_use * ETH_ALEN),
+ elem->out_sg[2].iov_base + sizeof(mac_data),
+ mac_data.entries * ETH_ALEN);
+ n->mac_table.in_use += mac_data.entries;
+ } else
+ n->allmulti = 1;
+ }
+
+ return VIRTIO_NET_OK;
+}
+
static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIONet *n = to_virtio_net(vdev);
@@ -151,6 +209,8 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
if (ctrl.class == VIRTIO_NET_CTRL_RX_MODE)
status = virtio_net_handle_rx_mode(n, ctrl.cmd, &elem);
+ else if (ctrl.class == VIRTIO_NET_CTRL_MAC)
+ status = virtio_net_handle_mac(n, ctrl.cmd, &elem);
stb_p(elem.in_sg[elem.in_num - 1].iov_base, status);
@@ -226,6 +286,7 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
{
static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t *ptr = (uint8_t *)buf;
+ int i;
if (n->promisc)
return 1;
@@ -244,6 +305,11 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
if (!memcmp(ptr, n->mac, ETH_ALEN))
return 1;
+ for (i = 0; i < n->mac_table.in_use; i++) {
+ if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN))
+ return 1;
+ }
+
return 0;
}
@@ -406,6 +472,8 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
qemu_put_be16(f, n->status);
qemu_put_be32(f, n->promisc);
qemu_put_be32(f, n->allmulti);
+ qemu_put_be32(f, n->mac_table.in_use);
+ qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
}
static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
@@ -429,6 +497,19 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
n->allmulti = qemu_get_be32(f);
}
+ if (version_id >= 5) {
+ n->mac_table.in_use = qemu_get_be32(f);
+ /* MAC_TABLE_ENTRIES may be different from the saved image */
+ if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) {
+ qemu_get_buffer(f, n->mac_table.macs,
+ n->mac_table.in_use * ETH_ALEN);
+ } else if (n->mac_table.in_use) {
+ qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR);
+ n->promisc = 1;
+ n->mac_table.in_use = 0;
+ }
+ }
+
if (n->tx_timer_active) {
qemu_mod_timer(n->tx_timer,
qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
@@ -474,6 +555,10 @@ void virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
n->mergeable_rx_bufs = 0;
n->promisc = 1; /* for compatibility */
+ n->mac_table.macs = qemu_mallocz(MAC_TABLE_ENTRIES * ETH_ALEN);
+ if (!n->mac_table.macs)
+ return;
+
register_savevm("virtio-net", virtio_net_id++, VIRTIO_NET_VM_VERSION,
virtio_net_save, virtio_net_load, n);
}
diff --git a/hw/virtio-net.h b/hw/virtio-net.h
index ce8e4b4..291fa9d 100644
--- a/hw/virtio-net.h
+++ b/hw/virtio-net.h
@@ -113,4 +113,26 @@ typedef uint8_t virtio_net_ctrl_ack;
#define VIRTIO_NET_CTRL_RX_MODE_PROMISC 0
#define VIRTIO_NET_CTRL_RX_MODE_ALLMULTI 1
+/*
+ * Control the MAC filter table.
+ *
+ * The MAC filter table is managed by the hypervisor, the guest should
+ * assume the size is infinite. Filtering should be considered
+ * non-perfect, ie. based on hypervisor resources, the guest may
+ * received packets from sources not specified in the filter list.
+ *
+ * In addition to the class/cmd header, the TABLE_SET command requires
+ * two out scatterlists. Each contains a 4 byte count of entries followed
+ * by a concatenated byte stream of the ETH_ALEN MAC addresses. The
+ * first sg list contains unicast addresses, the second is for multicast.
+ * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature
+ * is available.
+ */
+struct virtio_net_ctrl_mac {
+ uint32_t entries;
+ uint8_t macs[][ETH_ALEN];
+};
+#define VIRTIO_NET_CTRL_MAC 1
+ #define VIRTIO_NET_CTRL_MAC_TABLE_SET 0
+
#endif
WARNING: multiple messages have this Message-ID (diff)
From: Alex Williamson <alex.williamson@hp.com>
To: anthony@codemonkey.ws, qemu-devel@nongnu.org
Cc: markmc@redhat.com, alex.williamson@hp.com, kvm@vger.kernel.org
Subject: [Qemu-devel] [PATCH v3 7/8] qemu:virtio-net: Add additional MACs via a filter table
Date: Wed, 04 Feb 2009 17:18:27 -0700 [thread overview]
Message-ID: <20090205001827.27879.65637.stgit@kvm.aw> (raw)
In-Reply-To: <20090205001707.27879.22745.stgit@kvm.aw>
Create a filter table and allow the guest to populate it with the
MAC class control commands. We manage the size and usage of the
filter table including enabling promiscuous and all-multi modes
as necessary. The guest should therefore assume the table is
infinite. Eventually this might allow us to bind directly to a
hardware NIC and manipulate a physical MAC filter.
The specifics of the TABLE_SET command are documented in
virtio-net.h. Separate buffers in the same command are used
for unicaste and multicast addresses for priority and
sychronization. With this we can export the VIRTIO_NET_F_CTRL_RX
feature bit.
Signed-off-by: Alex Williamson <alex.williamson@hp.com>
---
hw/virtio-net.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
hw/virtio-net.h | 22 ++++++++++++++
2 files changed, 109 insertions(+), 2 deletions(-)
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 001169d..524ef37 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -16,7 +16,9 @@
#include "qemu-timer.h"
#include "virtio-net.h"
-#define VIRTIO_NET_VM_VERSION 4
+#define VIRTIO_NET_VM_VERSION 5
+
+#define MAC_TABLE_ENTRIES 32
typedef struct VirtIONet
{
@@ -32,6 +34,10 @@ typedef struct VirtIONet
int mergeable_rx_bufs;
int promisc;
int allmulti;
+ struct {
+ int in_use;
+ uint8_t *macs;
+ } mac_table;
} VirtIONet;
/* TODO
@@ -87,13 +93,18 @@ static void virtio_net_reset(VirtIODevice *vdev)
/* Reset back to compatibility mode */
n->promisc = 1;
n->allmulti = 0;
+
+ /* Flush any MAC filter table state */
+ n->mac_table.in_use = 0;
+ memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
}
static uint32_t virtio_net_get_features(VirtIODevice *vdev)
{
uint32_t features = (1 << VIRTIO_NET_F_MAC) |
(1 << VIRTIO_NET_F_STATUS) |
- (1 << VIRTIO_NET_F_CTRL_VQ);
+ (1 << VIRTIO_NET_F_CTRL_VQ) |
+ (1 << VIRTIO_NET_F_CTRL_RX);
return features;
}
@@ -127,6 +138,53 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
return VIRTIO_NET_OK;
}
+static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
+ VirtQueueElement *elem)
+{
+ struct virtio_net_ctrl_mac mac_data;
+
+ if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET || elem->out_num != 3 ||
+ elem->out_sg[1].iov_len < sizeof(mac_data) ||
+ elem->out_sg[2].iov_len < sizeof(mac_data))
+ return VIRTIO_NET_ERR;
+
+ n->mac_table.in_use = 0;
+ memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
+
+ mac_data.entries = ldl_le_p(elem->out_sg[1].iov_base);
+
+ if (sizeof(mac_data.entries) +
+ (mac_data.entries * ETH_ALEN) > elem->out_sg[1].iov_len)
+ return VIRTIO_NET_ERR;
+
+ if (mac_data.entries <= MAC_TABLE_ENTRIES) {
+ memcpy(n->mac_table.macs, elem->out_sg[1].iov_base + sizeof(mac_data),
+ mac_data.entries * ETH_ALEN);
+ n->mac_table.in_use += mac_data.entries;
+ } else {
+ n->promisc = 1;
+ return VIRTIO_NET_OK;
+ }
+
+ mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base);
+
+ if (sizeof(mac_data.entries) +
+ (mac_data.entries * ETH_ALEN) > elem->out_sg[2].iov_len)
+ return VIRTIO_NET_ERR;
+
+ if (mac_data.entries) {
+ if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
+ memcpy(n->mac_table.macs + (n->mac_table.in_use * ETH_ALEN),
+ elem->out_sg[2].iov_base + sizeof(mac_data),
+ mac_data.entries * ETH_ALEN);
+ n->mac_table.in_use += mac_data.entries;
+ } else
+ n->allmulti = 1;
+ }
+
+ return VIRTIO_NET_OK;
+}
+
static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIONet *n = to_virtio_net(vdev);
@@ -151,6 +209,8 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
if (ctrl.class == VIRTIO_NET_CTRL_RX_MODE)
status = virtio_net_handle_rx_mode(n, ctrl.cmd, &elem);
+ else if (ctrl.class == VIRTIO_NET_CTRL_MAC)
+ status = virtio_net_handle_mac(n, ctrl.cmd, &elem);
stb_p(elem.in_sg[elem.in_num - 1].iov_base, status);
@@ -226,6 +286,7 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
{
static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t *ptr = (uint8_t *)buf;
+ int i;
if (n->promisc)
return 1;
@@ -244,6 +305,11 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
if (!memcmp(ptr, n->mac, ETH_ALEN))
return 1;
+ for (i = 0; i < n->mac_table.in_use; i++) {
+ if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN))
+ return 1;
+ }
+
return 0;
}
@@ -406,6 +472,8 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
qemu_put_be16(f, n->status);
qemu_put_be32(f, n->promisc);
qemu_put_be32(f, n->allmulti);
+ qemu_put_be32(f, n->mac_table.in_use);
+ qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
}
static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
@@ -429,6 +497,19 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
n->allmulti = qemu_get_be32(f);
}
+ if (version_id >= 5) {
+ n->mac_table.in_use = qemu_get_be32(f);
+ /* MAC_TABLE_ENTRIES may be different from the saved image */
+ if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) {
+ qemu_get_buffer(f, n->mac_table.macs,
+ n->mac_table.in_use * ETH_ALEN);
+ } else if (n->mac_table.in_use) {
+ qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR);
+ n->promisc = 1;
+ n->mac_table.in_use = 0;
+ }
+ }
+
if (n->tx_timer_active) {
qemu_mod_timer(n->tx_timer,
qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
@@ -474,6 +555,10 @@ void virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
n->mergeable_rx_bufs = 0;
n->promisc = 1; /* for compatibility */
+ n->mac_table.macs = qemu_mallocz(MAC_TABLE_ENTRIES * ETH_ALEN);
+ if (!n->mac_table.macs)
+ return;
+
register_savevm("virtio-net", virtio_net_id++, VIRTIO_NET_VM_VERSION,
virtio_net_save, virtio_net_load, n);
}
diff --git a/hw/virtio-net.h b/hw/virtio-net.h
index ce8e4b4..291fa9d 100644
--- a/hw/virtio-net.h
+++ b/hw/virtio-net.h
@@ -113,4 +113,26 @@ typedef uint8_t virtio_net_ctrl_ack;
#define VIRTIO_NET_CTRL_RX_MODE_PROMISC 0
#define VIRTIO_NET_CTRL_RX_MODE_ALLMULTI 1
+/*
+ * Control the MAC filter table.
+ *
+ * The MAC filter table is managed by the hypervisor, the guest should
+ * assume the size is infinite. Filtering should be considered
+ * non-perfect, ie. based on hypervisor resources, the guest may
+ * received packets from sources not specified in the filter list.
+ *
+ * In addition to the class/cmd header, the TABLE_SET command requires
+ * two out scatterlists. Each contains a 4 byte count of entries followed
+ * by a concatenated byte stream of the ETH_ALEN MAC addresses. The
+ * first sg list contains unicast addresses, the second is for multicast.
+ * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature
+ * is available.
+ */
+struct virtio_net_ctrl_mac {
+ uint32_t entries;
+ uint8_t macs[][ETH_ALEN];
+};
+#define VIRTIO_NET_CTRL_MAC 1
+ #define VIRTIO_NET_CTRL_MAC_TABLE_SET 0
+
#endif
next prev parent reply other threads:[~2009-02-05 0:21 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-02-05 0:17 [PATCH v3 0/8] qemu:virtio-net: Add MAC and VLAN filtering Alex Williamson
2009-02-05 0:17 ` [Qemu-devel] " Alex Williamson
2009-02-05 0:17 ` [PATCH v3 1/8] qemu:virtio-net: Save status and add some save infrastructure Alex Williamson
2009-02-05 0:17 ` [Qemu-devel] " Alex Williamson
2009-02-05 22:36 ` Anthony Liguori
2009-02-05 22:36 ` [Qemu-devel] " Anthony Liguori
2009-02-05 0:18 ` [PATCH v3 2/8] qemu:virtio-net: Allow setting the MAC address via set_config Alex Williamson
2009-02-05 0:18 ` [Qemu-devel] " Alex Williamson
2009-02-05 0:18 ` [PATCH v3 3/8] qemu:virtio-net: Define ETH_ALEN for use when manipulating MAC addresses Alex Williamson
2009-02-05 0:18 ` [Qemu-devel] " Alex Williamson
2009-02-05 0:18 ` [PATCH v3 4/8] qemu:virtio-net: Add a virtqueue for control commands from the guest Alex Williamson
2009-02-05 0:18 ` [Qemu-devel] " Alex Williamson
2009-02-05 0:18 ` [PATCH v3 5/8] qemu:virtio-net: Add promiscuous and all-multicast mode bits Alex Williamson
2009-02-05 0:18 ` [Qemu-devel] " Alex Williamson
2009-02-05 0:18 ` [PATCH v3 6/8] qemu:virtio-net: Enable filtering based on MAC, promisc, broadcast and allmulti Alex Williamson
2009-02-05 0:18 ` [Qemu-devel] " Alex Williamson
2009-02-05 0:18 ` Alex Williamson [this message]
2009-02-05 0:18 ` [Qemu-devel] [PATCH v3 7/8] qemu:virtio-net: Add additional MACs via a filter table Alex Williamson
2009-02-05 0:18 ` [PATCH v3 8/8] qemu:virtio-net: Add VLAN filtering Alex Williamson
2009-02-05 0:18 ` [Qemu-devel] " Alex Williamson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090205001827.27879.65637.stgit@kvm.aw \
--to=alex.williamson@hp.com \
--cc=anthony@codemonkey.ws \
--cc=kvm@vger.kernel.org \
--cc=markmc@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.