|
|
9ae3a8 |
From 8eab8301249fa8f5b3f68a91a87edac676ff7f0f Mon Sep 17 00:00:00 2001
|
|
|
9ae3a8 |
From: Amos Kong <akong@redhat.com>
|
|
|
9ae3a8 |
Date: Fri, 8 Nov 2013 06:13:59 +0100
|
|
|
9ae3a8 |
Subject: [PATCH 4/4] net: add support of mac-programming over macvtap in QEMU side
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
RH-Author: Amos Kong <akong@redhat.com>
|
|
|
9ae3a8 |
Message-id: <1383891239-29531-5-git-send-email-akong@redhat.com>
|
|
|
9ae3a8 |
Patchwork-id: 55611
|
|
|
9ae3a8 |
O-Subject: [RHEL-7.0 qemu-kvm PATCH v2 4/4] net: add support of mac-programming over macvtap in QEMU side
|
|
|
9ae3a8 |
Bugzilla: 848203
|
|
|
9ae3a8 |
RH-Acked-by: Vlad Yasevich <vyasevic@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Currently macvtap based macvlan device is working in promiscuous
|
|
|
9ae3a8 |
mode, we want to implement mac-programming over macvtap through
|
|
|
9ae3a8 |
Libvirt for better performance.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Design:
|
|
|
9ae3a8 |
QEMU notifies Libvirt when rx-filter config is changed in guest,
|
|
|
9ae3a8 |
then Libvirt query the rx-filter information by a monitor command,
|
|
|
9ae3a8 |
and sync the change to macvtap device. Related rx-filter config
|
|
|
9ae3a8 |
of the nic contains main mac, rx-mode items and vlan table.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
This patch adds a QMP event to notify management of rx-filter change,
|
|
|
9ae3a8 |
and adds a monitor command for management to query rx-filter
|
|
|
9ae3a8 |
information.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Test:
|
|
|
9ae3a8 |
If we repeatedly add/remove vlan, and change macaddr of vlan
|
|
|
9ae3a8 |
interfaces in guest by a loop script.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Result:
|
|
|
9ae3a8 |
The events will flood the QMP client(management), management takes
|
|
|
9ae3a8 |
too much resource to process the events.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Event_throttle API (set rate to 1 ms) can avoid the events to flood
|
|
|
9ae3a8 |
QMP client, but it could cause an unexpected delay (~1ms), guests
|
|
|
9ae3a8 |
guests normally expect rx-filter updates immediately.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
So we use a flag for each nic to avoid events flooding, the event
|
|
|
9ae3a8 |
is emitted once until the query command is executed. The flag
|
|
|
9ae3a8 |
implementation could not introduce unexpected delay.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
There maybe exist an uncontrollable delay if we let Libvirt do the
|
|
|
9ae3a8 |
real change, guests normally expect rx-filter updates immediately.
|
|
|
9ae3a8 |
But it's another separate issue, we can investigate it when the
|
|
|
9ae3a8 |
work in Libvirt side is done.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Michael S. Tsirkin: tweaked to enable events on start
|
|
|
9ae3a8 |
Michael S. Tsirkin: fixed not to crash when no id
|
|
|
9ae3a8 |
Michael S. Tsirkin: fold in patch:
|
|
|
9ae3a8 |
"additional fixes for mac-programming feature"
|
|
|
9ae3a8 |
Amos Kong: always notify QMP client if mactable is changed
|
|
|
9ae3a8 |
Amos Kong: return NULL list if no net client supports rx-filter query
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Reviewed-by: Eric Blake <eblake@redhat.com>
|
|
|
9ae3a8 |
Reviewed-by: Markus Armbruster <armbru@redhat.com>
|
|
|
9ae3a8 |
Signed-off-by: Amos Kong <akong@redhat.com>
|
|
|
9ae3a8 |
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
9ae3a8 |
(cherry picked from commit b1be42803b31a913bab65bab563a8760ad2e7f7f)
|
|
|
9ae3a8 |
---
|
|
|
9ae3a8 |
QMP/qmp-events.txt | 17 ++++++
|
|
|
9ae3a8 |
hw/net/virtio-net.c | 133 +++++++++++++++++++++++++++++++++++++++++++--
|
|
|
9ae3a8 |
include/monitor/monitor.h | 1 +
|
|
|
9ae3a8 |
include/net/net.h | 3 +
|
|
|
9ae3a8 |
monitor.c | 1 +
|
|
|
9ae3a8 |
net/net.c | 48 ++++++++++++++++
|
|
|
9ae3a8 |
qapi-schema.json | 77 ++++++++++++++++++++++++++-
|
|
|
9ae3a8 |
qmp-commands.hx | 64 ++++++++++++++++++++++
|
|
|
9ae3a8 |
8 files changed, 337 insertions(+), 7 deletions(-)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
9ae3a8 |
---
|
|
|
9ae3a8 |
QMP/qmp-events.txt | 17 ++++++
|
|
|
9ae3a8 |
hw/net/virtio-net.c | 133 +++++++++++++++++++++++++++++++++++++++++++--
|
|
|
9ae3a8 |
include/monitor/monitor.h | 1 +
|
|
|
9ae3a8 |
include/net/net.h | 3 +
|
|
|
9ae3a8 |
monitor.c | 1 +
|
|
|
9ae3a8 |
net/net.c | 48 ++++++++++++++++
|
|
|
9ae3a8 |
qapi-schema.json | 77 ++++++++++++++++++++++++++-
|
|
|
9ae3a8 |
qmp-commands.hx | 64 ++++++++++++++++++++++
|
|
|
9ae3a8 |
8 files changed, 337 insertions(+), 7 deletions(-)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
|
|
|
9ae3a8 |
index e185030..79fb1c9 100644
|
|
|
9ae3a8 |
--- a/QMP/qmp-events.txt
|
|
|
9ae3a8 |
+++ b/QMP/qmp-events.txt
|
|
|
9ae3a8 |
@@ -194,6 +194,23 @@ Data:
|
|
|
9ae3a8 |
},
|
|
|
9ae3a8 |
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+NIC_RX_FILTER_CHANGED
|
|
|
9ae3a8 |
+-----------------
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+The event is emitted once until the query command is executed,
|
|
|
9ae3a8 |
+the first event will always be emitted.
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+Data:
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+- "name": net client name (json-string)
|
|
|
9ae3a8 |
+- "path": device path (json-string)
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+{ "event": "NIC_RX_FILTER_CHANGED",
|
|
|
9ae3a8 |
+ "data": { "name": "vnet0",
|
|
|
9ae3a8 |
+ "path": "/machine/peripheral/vnet0/virtio-backend" },
|
|
|
9ae3a8 |
+ "timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
RESET
|
|
|
9ae3a8 |
-----
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
|
|
|
9ae3a8 |
index 3290013..19c5030 100644
|
|
|
9ae3a8 |
--- a/hw/net/virtio-net.c
|
|
|
9ae3a8 |
+++ b/hw/net/virtio-net.c
|
|
|
9ae3a8 |
@@ -21,6 +21,8 @@
|
|
|
9ae3a8 |
#include "hw/virtio/virtio-net.h"
|
|
|
9ae3a8 |
#include "net/vhost_net.h"
|
|
|
9ae3a8 |
#include "hw/virtio/virtio-bus.h"
|
|
|
9ae3a8 |
+#include "qapi/qmp/qjson.h"
|
|
|
9ae3a8 |
+#include "monitor/monitor.h"
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
#define VIRTIO_NET_VM_VERSION 11
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
@@ -192,6 +194,105 @@ static void virtio_net_set_link_status(NetClientState *nc)
|
|
|
9ae3a8 |
virtio_net_set_status(vdev, vdev->status);
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+static void rxfilter_notify(NetClientState *nc)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ QObject *event_data;
|
|
|
9ae3a8 |
+ VirtIONet *n = qemu_get_nic_opaque(nc);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (nc->rxfilter_notify_enabled) {
|
|
|
9ae3a8 |
+ if (n->netclient_name) {
|
|
|
9ae3a8 |
+ event_data = qobject_from_jsonf("{ 'name': %s, 'path': %s }",
|
|
|
9ae3a8 |
+ n->netclient_name,
|
|
|
9ae3a8 |
+ object_get_canonical_path(OBJECT(n->qdev)));
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ event_data = qobject_from_jsonf("{ 'path': %s }",
|
|
|
9ae3a8 |
+ object_get_canonical_path(OBJECT(n->qdev)));
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ monitor_protocol_event(QEVENT_NIC_RX_FILTER_CHANGED, event_data);
|
|
|
9ae3a8 |
+ qobject_decref(event_data);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* disable event notification to avoid events flooding */
|
|
|
9ae3a8 |
+ nc->rxfilter_notify_enabled = 0;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+static char *mac_strdup_printf(const uint8_t *mac)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ return g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", mac[0],
|
|
|
9ae3a8 |
+ mac[1], mac[2], mac[3], mac[4], mac[5]);
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ VirtIONet *n = qemu_get_nic_opaque(nc);
|
|
|
9ae3a8 |
+ RxFilterInfo *info;
|
|
|
9ae3a8 |
+ strList *str_list, *entry;
|
|
|
9ae3a8 |
+ intList *int_list, *int_entry;
|
|
|
9ae3a8 |
+ int i, j;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ info = g_malloc0(sizeof(*info));
|
|
|
9ae3a8 |
+ info->name = g_strdup(nc->name);
|
|
|
9ae3a8 |
+ info->promiscuous = n->promisc;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (n->nouni) {
|
|
|
9ae3a8 |
+ info->unicast = RX_STATE_NONE;
|
|
|
9ae3a8 |
+ } else if (n->alluni) {
|
|
|
9ae3a8 |
+ info->unicast = RX_STATE_ALL;
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ info->unicast = RX_STATE_NORMAL;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (n->nomulti) {
|
|
|
9ae3a8 |
+ info->multicast = RX_STATE_NONE;
|
|
|
9ae3a8 |
+ } else if (n->allmulti) {
|
|
|
9ae3a8 |
+ info->multicast = RX_STATE_ALL;
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ info->multicast = RX_STATE_NORMAL;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ info->broadcast_allowed = n->nobcast;
|
|
|
9ae3a8 |
+ info->multicast_overflow = n->mac_table.multi_overflow;
|
|
|
9ae3a8 |
+ info->unicast_overflow = n->mac_table.uni_overflow;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ info->main_mac = mac_strdup_printf(n->mac);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ str_list = NULL;
|
|
|
9ae3a8 |
+ for (i = 0; i < n->mac_table.first_multi; i++) {
|
|
|
9ae3a8 |
+ entry = g_malloc0(sizeof(*entry));
|
|
|
9ae3a8 |
+ entry->value = mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
|
|
|
9ae3a8 |
+ entry->next = str_list;
|
|
|
9ae3a8 |
+ str_list = entry;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ info->unicast_table = str_list;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ str_list = NULL;
|
|
|
9ae3a8 |
+ for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
|
|
|
9ae3a8 |
+ entry = g_malloc0(sizeof(*entry));
|
|
|
9ae3a8 |
+ entry->value = mac_strdup_printf(n->mac_table.macs + i * ETH_ALEN);
|
|
|
9ae3a8 |
+ entry->next = str_list;
|
|
|
9ae3a8 |
+ str_list = entry;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ info->multicast_table = str_list;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ int_list = NULL;
|
|
|
9ae3a8 |
+ for (i = 0; i < MAX_VLAN >> 5; i++) {
|
|
|
9ae3a8 |
+ for (j = 0; n->vlans[i] && j < 0x1f; j++) {
|
|
|
9ae3a8 |
+ if (n->vlans[i] & (1U << j)) {
|
|
|
9ae3a8 |
+ int_entry = g_malloc0(sizeof(*int_entry));
|
|
|
9ae3a8 |
+ int_entry->value = (i << 5) + j;
|
|
|
9ae3a8 |
+ int_entry->next = int_list;
|
|
|
9ae3a8 |
+ int_list = int_entry;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ info->vlan_table = int_list;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* enable event notification after query */
|
|
|
9ae3a8 |
+ nc->rxfilter_notify_enabled = 1;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ return info;
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
static void virtio_net_reset(VirtIODevice *vdev)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
VirtIONet *n = VIRTIO_NET(vdev);
|
|
|
9ae3a8 |
@@ -396,6 +497,7 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
uint8_t on;
|
|
|
9ae3a8 |
size_t s;
|
|
|
9ae3a8 |
+ NetClientState *nc = qemu_get_queue(n->nic);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
s = iov_to_buf(iov, iov_cnt, 0, &on, sizeof(on));
|
|
|
9ae3a8 |
if (s != sizeof(on)) {
|
|
|
9ae3a8 |
@@ -418,6 +520,8 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
|
|
|
9ae3a8 |
return VIRTIO_NET_ERR;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+ rxfilter_notify(nc);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
return VIRTIO_NET_OK;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
@@ -426,6 +530,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
struct virtio_net_ctrl_mac mac_data;
|
|
|
9ae3a8 |
size_t s;
|
|
|
9ae3a8 |
+ NetClientState *nc = qemu_get_queue(n->nic);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
if (cmd == VIRTIO_NET_CTRL_MAC_ADDR_SET) {
|
|
|
9ae3a8 |
if (iov_size(iov, iov_cnt) != sizeof(n->mac)) {
|
|
|
9ae3a8 |
@@ -434,6 +539,8 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
|
|
|
9ae3a8 |
s = iov_to_buf(iov, iov_cnt, 0, &n->mac, sizeof(n->mac));
|
|
|
9ae3a8 |
assert(s == sizeof(n->mac));
|
|
|
9ae3a8 |
qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
|
|
|
9ae3a8 |
+ rxfilter_notify(nc);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
return VIRTIO_NET_OK;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
@@ -451,19 +558,19 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
|
|
|
9ae3a8 |
sizeof(mac_data.entries));
|
|
|
9ae3a8 |
mac_data.entries = ldl_p(&mac_data.entries);
|
|
|
9ae3a8 |
if (s != sizeof(mac_data.entries)) {
|
|
|
9ae3a8 |
- return VIRTIO_NET_ERR;
|
|
|
9ae3a8 |
+ goto error;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
iov_discard_front(&iov, &iov_cnt, s);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
if (mac_data.entries * ETH_ALEN > iov_size(iov, iov_cnt)) {
|
|
|
9ae3a8 |
- return VIRTIO_NET_ERR;
|
|
|
9ae3a8 |
+ goto error;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
if (mac_data.entries <= MAC_TABLE_ENTRIES) {
|
|
|
9ae3a8 |
s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs,
|
|
|
9ae3a8 |
mac_data.entries * ETH_ALEN);
|
|
|
9ae3a8 |
if (s != mac_data.entries * ETH_ALEN) {
|
|
|
9ae3a8 |
- return VIRTIO_NET_ERR;
|
|
|
9ae3a8 |
+ goto error;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
n->mac_table.in_use += mac_data.entries;
|
|
|
9ae3a8 |
} else {
|
|
|
9ae3a8 |
@@ -478,27 +585,33 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
|
|
|
9ae3a8 |
sizeof(mac_data.entries));
|
|
|
9ae3a8 |
mac_data.entries = ldl_p(&mac_data.entries);
|
|
|
9ae3a8 |
if (s != sizeof(mac_data.entries)) {
|
|
|
9ae3a8 |
- return VIRTIO_NET_ERR;
|
|
|
9ae3a8 |
+ goto error;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
iov_discard_front(&iov, &iov_cnt, s);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
if (mac_data.entries * ETH_ALEN != iov_size(iov, iov_cnt)) {
|
|
|
9ae3a8 |
- return VIRTIO_NET_ERR;
|
|
|
9ae3a8 |
+ goto error;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
|
|
|
9ae3a8 |
s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs,
|
|
|
9ae3a8 |
mac_data.entries * ETH_ALEN);
|
|
|
9ae3a8 |
if (s != mac_data.entries * ETH_ALEN) {
|
|
|
9ae3a8 |
- return VIRTIO_NET_ERR;
|
|
|
9ae3a8 |
+ goto error;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
n->mac_table.in_use += mac_data.entries;
|
|
|
9ae3a8 |
} else {
|
|
|
9ae3a8 |
n->mac_table.multi_overflow = 1;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+ rxfilter_notify(nc);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
return VIRTIO_NET_OK;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+error:
|
|
|
9ae3a8 |
+ rxfilter_notify(nc);
|
|
|
9ae3a8 |
+ return VIRTIO_NET_ERR;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
|
|
|
9ae3a8 |
@@ -506,6 +619,7 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
uint16_t vid;
|
|
|
9ae3a8 |
size_t s;
|
|
|
9ae3a8 |
+ NetClientState *nc = qemu_get_queue(n->nic);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid));
|
|
|
9ae3a8 |
vid = lduw_p(&vid);
|
|
|
9ae3a8 |
@@ -523,6 +637,8 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
|
|
|
9ae3a8 |
else
|
|
|
9ae3a8 |
return VIRTIO_NET_ERR;
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+ rxfilter_notify(nc);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
return VIRTIO_NET_OK;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
@@ -1244,6 +1360,7 @@ static NetClientInfo net_virtio_info = {
|
|
|
9ae3a8 |
.receive = virtio_net_receive,
|
|
|
9ae3a8 |
.cleanup = virtio_net_cleanup,
|
|
|
9ae3a8 |
.link_status_changed = virtio_net_set_link_status,
|
|
|
9ae3a8 |
+ .query_rx_filter = virtio_net_query_rxfilter,
|
|
|
9ae3a8 |
};
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx)
|
|
|
9ae3a8 |
@@ -1305,6 +1422,7 @@ static int virtio_net_device_init(VirtIODevice *vdev)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
DeviceState *qdev = DEVICE(vdev);
|
|
|
9ae3a8 |
VirtIONet *n = VIRTIO_NET(vdev);
|
|
|
9ae3a8 |
+ NetClientState *nc;
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
virtio_init(VIRTIO_DEVICE(n), "virtio-net", VIRTIO_ID_NET,
|
|
|
9ae3a8 |
n->config_size);
|
|
|
9ae3a8 |
@@ -1371,6 +1489,9 @@ static int virtio_net_device_init(VirtIODevice *vdev)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
n->vlans = g_malloc0(MAX_VLAN >> 3);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+ nc = qemu_get_queue(n->nic);
|
|
|
9ae3a8 |
+ nc->rxfilter_notify_enabled = 1;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
n->qdev = qdev;
|
|
|
9ae3a8 |
register_savevm(qdev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
|
|
|
9ae3a8 |
virtio_net_save, virtio_net_load, n);
|
|
|
9ae3a8 |
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
|
|
|
9ae3a8 |
index 07b41a6..10fa0e3 100644
|
|
|
9ae3a8 |
--- a/include/monitor/monitor.h
|
|
|
9ae3a8 |
+++ b/include/monitor/monitor.h
|
|
|
9ae3a8 |
@@ -41,6 +41,7 @@ typedef enum MonitorEvent {
|
|
|
9ae3a8 |
QEVENT_BLOCK_JOB_READY,
|
|
|
9ae3a8 |
QEVENT_DEVICE_DELETED,
|
|
|
9ae3a8 |
QEVENT_DEVICE_TRAY_MOVED,
|
|
|
9ae3a8 |
+ QEVENT_NIC_RX_FILTER_CHANGED,
|
|
|
9ae3a8 |
QEVENT_SUSPEND,
|
|
|
9ae3a8 |
QEVENT_SUSPEND_DISK,
|
|
|
9ae3a8 |
QEVENT_WAKEUP,
|
|
|
9ae3a8 |
diff --git a/include/net/net.h b/include/net/net.h
|
|
|
9ae3a8 |
index 43d85a1..30e4b04 100644
|
|
|
9ae3a8 |
--- a/include/net/net.h
|
|
|
9ae3a8 |
+++ b/include/net/net.h
|
|
|
9ae3a8 |
@@ -49,6 +49,7 @@ typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int);
|
|
|
9ae3a8 |
typedef void (NetCleanup) (NetClientState *);
|
|
|
9ae3a8 |
typedef void (LinkStatusChanged)(NetClientState *);
|
|
|
9ae3a8 |
typedef void (NetClientDestructor)(NetClientState *);
|
|
|
9ae3a8 |
+typedef RxFilterInfo *(QueryRxFilter)(NetClientState *);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
typedef struct NetClientInfo {
|
|
|
9ae3a8 |
NetClientOptionsKind type;
|
|
|
9ae3a8 |
@@ -59,6 +60,7 @@ typedef struct NetClientInfo {
|
|
|
9ae3a8 |
NetCanReceive *can_receive;
|
|
|
9ae3a8 |
NetCleanup *cleanup;
|
|
|
9ae3a8 |
LinkStatusChanged *link_status_changed;
|
|
|
9ae3a8 |
+ QueryRxFilter *query_rx_filter;
|
|
|
9ae3a8 |
NetPoll *poll;
|
|
|
9ae3a8 |
} NetClientInfo;
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
@@ -74,6 +76,7 @@ struct NetClientState {
|
|
|
9ae3a8 |
unsigned receive_disabled : 1;
|
|
|
9ae3a8 |
NetClientDestructor *destructor;
|
|
|
9ae3a8 |
unsigned int queue_index;
|
|
|
9ae3a8 |
+ unsigned rxfilter_notify_enabled:1;
|
|
|
9ae3a8 |
};
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
typedef struct NICState {
|
|
|
9ae3a8 |
diff --git a/monitor.c b/monitor.c
|
|
|
9ae3a8 |
index c226acf..8f36f91 100644
|
|
|
9ae3a8 |
--- a/monitor.c
|
|
|
9ae3a8 |
+++ b/monitor.c
|
|
|
9ae3a8 |
@@ -498,6 +498,7 @@ static const char *monitor_event_names[] = {
|
|
|
9ae3a8 |
[QEVENT_BLOCK_JOB_READY] = "BLOCK_JOB_READY",
|
|
|
9ae3a8 |
[QEVENT_DEVICE_DELETED] = "DEVICE_DELETED",
|
|
|
9ae3a8 |
[QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
|
|
|
9ae3a8 |
+ [QEVENT_NIC_RX_FILTER_CHANGED] = "NIC_RX_FILTER_CHANGED",
|
|
|
9ae3a8 |
[QEVENT_SUSPEND] = "SUSPEND",
|
|
|
9ae3a8 |
[QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
|
|
|
9ae3a8 |
[QEVENT_WAKEUP] = "WAKEUP",
|
|
|
9ae3a8 |
diff --git a/net/net.c b/net/net.c
|
|
|
9ae3a8 |
index 43a74e4..c0d61bf 100644
|
|
|
9ae3a8 |
--- a/net/net.c
|
|
|
9ae3a8 |
+++ b/net/net.c
|
|
|
9ae3a8 |
@@ -961,6 +961,54 @@ void print_net_client(Monitor *mon, NetClientState *nc)
|
|
|
9ae3a8 |
nc->info_str);
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name,
|
|
|
9ae3a8 |
+ Error **errp)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ NetClientState *nc;
|
|
|
9ae3a8 |
+ RxFilterInfoList *filter_list = NULL, *last_entry = NULL;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ QTAILQ_FOREACH(nc, &net_clients, next) {
|
|
|
9ae3a8 |
+ RxFilterInfoList *entry;
|
|
|
9ae3a8 |
+ RxFilterInfo *info;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (has_name && strcmp(nc->name, name) != 0) {
|
|
|
9ae3a8 |
+ continue;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* only query rx-filter information of NIC */
|
|
|
9ae3a8 |
+ if (nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC) {
|
|
|
9ae3a8 |
+ if (has_name) {
|
|
|
9ae3a8 |
+ error_setg(errp, "net client(%s) isn't a NIC", name);
|
|
|
9ae3a8 |
+ break;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ continue;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (nc->info->query_rx_filter) {
|
|
|
9ae3a8 |
+ info = nc->info->query_rx_filter(nc);
|
|
|
9ae3a8 |
+ entry = g_malloc0(sizeof(*entry));
|
|
|
9ae3a8 |
+ entry->value = info;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (!filter_list) {
|
|
|
9ae3a8 |
+ filter_list = entry;
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ last_entry->next = entry;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ last_entry = entry;
|
|
|
9ae3a8 |
+ } else if (has_name) {
|
|
|
9ae3a8 |
+ error_setg(errp, "net client(%s) doesn't support"
|
|
|
9ae3a8 |
+ " rx-filter querying", name);
|
|
|
9ae3a8 |
+ break;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (filter_list == NULL && !error_is_set(errp) && has_name) {
|
|
|
9ae3a8 |
+ error_setg(errp, "invalid net client name: %s", name);
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ return filter_list;
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
void do_info_network(Monitor *mon, const QDict *qdict)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
NetClientState *nc, *peer;
|
|
|
9ae3a8 |
diff --git a/qapi-schema.json b/qapi-schema.json
|
|
|
9ae3a8 |
index 64696a9..92fcd54 100644
|
|
|
9ae3a8 |
--- a/qapi-schema.json
|
|
|
9ae3a8 |
+++ b/qapi-schema.json
|
|
|
9ae3a8 |
@@ -3737,7 +3737,6 @@
|
|
|
9ae3a8 |
'cpuid-register': 'X86CPURegister32',
|
|
|
9ae3a8 |
'features': 'int' } }
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
##
|
|
|
9ae3a8 |
# @BlockdevDiscardOptions
|
|
|
9ae3a8 |
#
|
|
|
9ae3a8 |
@@ -3972,3 +3971,79 @@
|
|
|
9ae3a8 |
# Since: 1.7
|
|
|
9ae3a8 |
##
|
|
|
9ae3a8 |
{ 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+##
|
|
|
9ae3a8 |
+# @RxState:
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# Packets receiving state
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @normal: filter assigned packets according to the mac-table
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @none: don't receive any assigned packet
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @all: receive all assigned packets
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# Since: 1.6
|
|
|
9ae3a8 |
+##
|
|
|
9ae3a8 |
+{ 'enum': 'RxState', 'data': [ 'normal', 'none', 'all' ] }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+##
|
|
|
9ae3a8 |
+# @RxFilterInfo:
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# Rx-filter information for a NIC.
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @name: net client name
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @promiscuous: whether promiscuous mode is enabled
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @multicast: multicast receive state
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @unicast: unicast receive state
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @broadcast-allowed: whether to receive broadcast
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @multicast-overflow: multicast table is overflowed or not
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @unicast-overflow: unicast table is overflowed or not
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @main-mac: the main macaddr string
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @vlan-table: a list of active vlan id
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @unicast-table: a list of unicast macaddr string
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @multicast-table: a list of multicast macaddr string
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# Since 1.6
|
|
|
9ae3a8 |
+##
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+{ 'type': 'RxFilterInfo',
|
|
|
9ae3a8 |
+ 'data': {
|
|
|
9ae3a8 |
+ 'name': 'str',
|
|
|
9ae3a8 |
+ 'promiscuous': 'bool',
|
|
|
9ae3a8 |
+ 'multicast': 'RxState',
|
|
|
9ae3a8 |
+ 'unicast': 'RxState',
|
|
|
9ae3a8 |
+ 'broadcast-allowed': 'bool',
|
|
|
9ae3a8 |
+ 'multicast-overflow': 'bool',
|
|
|
9ae3a8 |
+ 'unicast-overflow': 'bool',
|
|
|
9ae3a8 |
+ 'main-mac': 'str',
|
|
|
9ae3a8 |
+ 'vlan-table': ['int'],
|
|
|
9ae3a8 |
+ 'unicast-table': ['str'],
|
|
|
9ae3a8 |
+ 'multicast-table': ['str'] }}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+##
|
|
|
9ae3a8 |
+# @query-rx-filter:
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# Return rx-filter information for all NICs (or for the given NIC).
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# @name: #optional net client name
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# Returns: list of @RxFilterInfo for all NICs (or for the given NIC).
|
|
|
9ae3a8 |
+# Returns an error if the given @name doesn't exist, or given
|
|
|
9ae3a8 |
+# NIC doesn't support rx-filter querying, or given net client
|
|
|
9ae3a8 |
+# isn't a NIC.
|
|
|
9ae3a8 |
+#
|
|
|
9ae3a8 |
+# Since: 1.6
|
|
|
9ae3a8 |
+##
|
|
|
9ae3a8 |
+{ 'command': 'query-rx-filter', 'data': { '*name': 'str' },
|
|
|
9ae3a8 |
+ 'returns': ['RxFilterInfo'] }
|
|
|
9ae3a8 |
diff --git a/qmp-commands.hx b/qmp-commands.hx
|
|
|
9ae3a8 |
index f71c34e..4942590 100644
|
|
|
9ae3a8 |
--- a/qmp-commands.hx
|
|
|
9ae3a8 |
+++ b/qmp-commands.hx
|
|
|
9ae3a8 |
@@ -3061,3 +3061,67 @@ Example (2):
|
|
|
9ae3a8 |
<- { "return": {} }
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
EQMP
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ {
|
|
|
9ae3a8 |
+ .name = "query-rx-filter",
|
|
|
9ae3a8 |
+ .args_type = "name:s?",
|
|
|
9ae3a8 |
+ .mhandler.cmd_new = qmp_marshal_input_query_rx_filter,
|
|
|
9ae3a8 |
+ },
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+SQMP
|
|
|
9ae3a8 |
+query-rx-filter
|
|
|
9ae3a8 |
+---------------
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+Show rx-filter information.
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+Returns a json-array of rx-filter information for all NICs (or for the
|
|
|
9ae3a8 |
+given NIC), returning an error if the given NIC doesn't exist, or
|
|
|
9ae3a8 |
+given NIC doesn't support rx-filter querying, or given net client
|
|
|
9ae3a8 |
+isn't a NIC.
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+The query will clear the event notification flag of each NIC, then qemu
|
|
|
9ae3a8 |
+will start to emit event to QMP monitor.
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+Each array entry contains the following:
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+- "name": net client name (json-string)
|
|
|
9ae3a8 |
+- "promiscuous": promiscuous mode is enabled (json-bool)
|
|
|
9ae3a8 |
+- "multicast": multicast receive state (one of 'normal', 'none', 'all')
|
|
|
9ae3a8 |
+- "unicast": unicast receive state (one of 'normal', 'none', 'all')
|
|
|
9ae3a8 |
+- "broadcast-allowed": allow to receive broadcast (json-bool)
|
|
|
9ae3a8 |
+- "multicast-overflow": multicast table is overflowed (json-bool)
|
|
|
9ae3a8 |
+- "unicast-overflow": unicast table is overflowed (json-bool)
|
|
|
9ae3a8 |
+- "main-mac": main macaddr string (json-string)
|
|
|
9ae3a8 |
+- "vlan-table": a json-array of active vlan id
|
|
|
9ae3a8 |
+- "unicast-table": a json-array of unicast macaddr string
|
|
|
9ae3a8 |
+- "multicast-table": a json-array of multicast macaddr string
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+Example:
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+-> { "execute": "query-rx-filter", "arguments": { "name": "vnet0" } }
|
|
|
9ae3a8 |
+<- { "return": [
|
|
|
9ae3a8 |
+ {
|
|
|
9ae3a8 |
+ "promiscuous": true,
|
|
|
9ae3a8 |
+ "name": "vnet0",
|
|
|
9ae3a8 |
+ "main-mac": "52:54:00:12:34:56",
|
|
|
9ae3a8 |
+ "unicast": "normal",
|
|
|
9ae3a8 |
+ "vlan-table": [
|
|
|
9ae3a8 |
+ 4,
|
|
|
9ae3a8 |
+ 0
|
|
|
9ae3a8 |
+ ],
|
|
|
9ae3a8 |
+ "unicast-table": [
|
|
|
9ae3a8 |
+ ],
|
|
|
9ae3a8 |
+ "multicast": "normal",
|
|
|
9ae3a8 |
+ "multicast-overflow": false,
|
|
|
9ae3a8 |
+ "unicast-overflow": false,
|
|
|
9ae3a8 |
+ "multicast-table": [
|
|
|
9ae3a8 |
+ "01:00:5e:00:00:01",
|
|
|
9ae3a8 |
+ "33:33:00:00:00:01",
|
|
|
9ae3a8 |
+ "33:33:ff:12:34:56"
|
|
|
9ae3a8 |
+ ],
|
|
|
9ae3a8 |
+ "broadcast-allowed": false
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ ]
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+EQMP
|
|
|
9ae3a8 |
--
|
|
|
9ae3a8 |
1.7.1
|
|
|
9ae3a8 |
|