Blame SOURCES/kvm-net-add-support-of-mac-programming-over-macvtap-in-Q.patch

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