From 81c354a5025995d3e5c88b63a3de64f9c0731f20 Mon Sep 17 00:00:00 2001
Message-Id: <81c354a5025995d3e5c88b63a3de64f9c0731f20@dist-git>
From: Laine Stump <laine@laine.org>
Date: Mon, 3 Nov 2014 10:00:18 -0500
Subject: [PATCH] qemu: qemuMonitorQueryRxFilter - retrieve guest netdev
rx-filter
https://bugzilla.redhat.com/show_bug.cgi?id=848199
This function can be called at any time to get the current status of a
guest's network device rx-filter. In particular it is useful to call
after libvirt recieves a NIC_RX_FILTER_CHANGED event - this event only
tells you that something has changed in the rx-filter, the details are
retrieved with the query-rx-filter monitor command (only available in
the json monitor). The command sent to the qemu monitor looks like this:
{"execute":"query-rx-filter", "arguments": {"name":"net2"} }'
and the results will look something like this:
{
"return": [
{
"promiscuous": false,
"name": "net2",
"main-mac": "52:54:00:98:2d:e3",
"unicast": "normal",
"vlan": "normal",
"vlan-table": [
42,
0
],
"unicast-table": [
],
"multicast": "normal",
"multicast-overflow": false,
"unicast-overflow": false,
"multicast-table": [
"33:33:ff:98:2d:e3",
"01:80:c2:00:00:21",
"01:00:5e:00:00:fb",
"33:33:ff:98:2d:e2",
"01:00:5e:00:00:01",
"33:33:00:00:00:01"
],
"broadcast-allowed": false
}
],
"id": "libvirt-14"
}
This is all parsed from JSON into a virNetDevRxFilter object for
easier consumption. (unicast-table is usually empty, but is also an
array of mac addresses similar to multicast-table).
(NB: LIBNL_CFLAGS was added to tests/Makefile.am because virnetdev.h
now includes util/virnetlink.h, which includes netlink/msg.h when
appropriate. Without LIBNL_CFLAGS, gcc can't find that file (if
libnl/netlink isn't available, LIBNL_CFLAGS will be empty and
virnetlink.h won't try to include netlink/msg.h anyway).)
(cherry picked from commit ab989962d4c2ef9045a9b8344b8e6f4094027c7c)
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
src/qemu/qemu_monitor.c | 26 ++++++
src/qemu/qemu_monitor.h | 4 +
src/qemu/qemu_monitor_json.c | 215 +++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_json.h | 3 +
tests/Makefile.am | 1 +
5 files changed, 249 insertions(+)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 8e14366..be8d60b 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2933,6 +2933,32 @@ int qemuMonitorRemoveNetdev(qemuMonitorPtr mon,
}
+int
+qemuMonitorQueryRxFilter(qemuMonitorPtr mon, const char *alias,
+ virNetDevRxFilterPtr *filter)
+{
+ int ret = -1;
+ VIR_DEBUG("mon=%p alias=%s filter=%p",
+ mon, alias, filter);
+
+ if (!mon) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+
+ VIR_DEBUG("mon=%p, alias=%s", mon, alias);
+
+ if (mon->json)
+ ret = qemuMonitorJSONQueryRxFilter(mon, alias, filter);
+ else
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("query-rx-filter requires JSON monitor"));
+ return ret;
+}
+
+
int qemuMonitorGetPtyPaths(qemuMonitorPtr mon,
virHashTablePtr paths)
{
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 5bffca8..cfcaf30 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -31,6 +31,7 @@
# include "virbitmap.h"
# include "virhash.h"
# include "virjson.h"
+# include "virnetdev.h"
# include "device_conf.h"
# include "cpu/cpu.h"
@@ -627,6 +628,9 @@ int qemuMonitorAddNetdev(qemuMonitorPtr mon,
int qemuMonitorRemoveNetdev(qemuMonitorPtr mon,
const char *alias);
+int qemuMonitorQueryRxFilter(qemuMonitorPtr mon, const char *alias,
+ virNetDevRxFilterPtr *filter);
+
int qemuMonitorGetPtyPaths(qemuMonitorPtr mon,
virHashTablePtr paths);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index cad6be8..7a6d1e1 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -3297,6 +3297,221 @@ int qemuMonitorJSONRemoveNetdev(qemuMonitorPtr mon,
}
+static int
+qemuMonitorJSONQueryRxFilterParse(virJSONValuePtr msg,
+ virNetDevRxFilterPtr *filter)
+{
+ int ret = -1;
+ const char *tmp;
+ virJSONValuePtr returnArray, entry, table, element;
+ int nTable;
+ size_t i;
+ virNetDevRxFilterPtr fil = virNetDevRxFilterNew();
+
+ if (!fil)
+ goto cleanup;
+
+ if (!(returnArray = virJSONValueObjectGet(msg, "return"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("query-rx-filter reply was missing return data"));
+ goto cleanup;
+ }
+ if (returnArray->type != VIR_JSON_TYPE_ARRAY) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("query-rx-filter return data was not an array"));
+ goto cleanup;
+ }
+ if (!(entry = virJSONValueArrayGet(returnArray, 0))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("query -rx-filter return data missing array element"));
+ goto cleanup;
+ }
+
+ if (!(tmp = virJSONValueObjectGetString(entry, "name"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid name "
+ "in query-rx-filter response"));
+ goto cleanup;
+ }
+ if (VIR_STRDUP(fil->name, tmp) < 0)
+ goto cleanup;
+ if ((!(tmp = virJSONValueObjectGetString(entry, "main-mac"))) ||
+ virMacAddrParse(tmp, &fil->mac) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid 'main-mac' "
+ "in query-rx-filter response"));
+ goto cleanup;
+ }
+ if (virJSONValueObjectGetBoolean(entry, "promiscuous",
+ &fil->promiscuous) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid 'promiscuous' "
+ "in query-rx-filter response"));
+ goto cleanup;
+ }
+ if (virJSONValueObjectGetBoolean(entry, "broadcast-allowed",
+ &fil->broadcastAllowed) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid 'broadcast-allowed' "
+ "in query-rx-filter response"));
+ goto cleanup;
+ }
+
+ if ((!(tmp = virJSONValueObjectGetString(entry, "unicast"))) ||
+ ((fil->unicast.mode
+ = virNetDevRxFilterModeTypeFromString(tmp)) < 0)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid 'unicast' "
+ "in query-rx-filter response"));
+ goto cleanup;
+ }
+ if (virJSONValueObjectGetBoolean(entry, "unicast-overflow",
+ &fil->unicast.overflow) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid 'unicast-overflow' "
+ "in query-rx-filter response"));
+ goto cleanup;
+ }
+ if ((!(table = virJSONValueObjectGet(entry, "unicast-table"))) ||
+ ((nTable = virJSONValueArraySize(table)) < 0)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid 'unicast-table' array "
+ "in query-rx-filter response"));
+ goto cleanup;
+ }
+ if (VIR_ALLOC_N(fil->unicast.table, nTable))
+ goto cleanup;
+ for (i = 0; i < nTable; i++) {
+ if (!(element = virJSONValueArrayGet(table, i)) ||
+ !(tmp = virJSONValueGetString(element))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Missing or invalid element %zu of 'unicast' "
+ "list in query-rx-filter response"), i);
+ goto cleanup;
+ }
+ if (virMacAddrParse(tmp, &fil->unicast.table[i]) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("invalid mac address '%s' in 'unicast-table' "
+ "array in query-rx-filter response"), tmp);
+ goto cleanup;
+ }
+ }
+ fil->unicast.nTable = nTable;
+
+ if ((!(tmp = virJSONValueObjectGetString(entry, "multicast"))) ||
+ ((fil->multicast.mode
+ = virNetDevRxFilterModeTypeFromString(tmp)) < 0)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid 'multicast' "
+ "in query-rx-filter response"));
+ goto cleanup;
+ }
+ if (virJSONValueObjectGetBoolean(entry, "multicast-overflow",
+ &fil->multicast.overflow) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid 'multicast-overflow' "
+ "in query-rx-filter response"));
+ goto cleanup;
+ }
+ if ((!(table = virJSONValueObjectGet(entry, "multicast-table"))) ||
+ ((nTable = virJSONValueArraySize(table)) < 0)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid 'multicast-table' array "
+ "in query-rx-filter response"));
+ goto cleanup;
+ }
+ if (VIR_ALLOC_N(fil->multicast.table, nTable))
+ goto cleanup;
+ for (i = 0; i < nTable; i++) {
+ if (!(element = virJSONValueArrayGet(table, i)) ||
+ !(tmp = virJSONValueGetString(element))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Missing or invalid element %zu of 'multicast' "
+ "list in query-rx-filter response"), i);
+ goto cleanup;
+ }
+ if (virMacAddrParse(tmp, &fil->multicast.table[i]) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("invalid mac address '%s' in 'multicast-table' "
+ "array in query-rx-filter response"), tmp);
+ goto cleanup;
+ }
+ }
+ fil->multicast.nTable = nTable;
+
+ if ((!(tmp = virJSONValueObjectGetString(entry, "vlan"))) ||
+ ((fil->vlan.mode
+ = virNetDevRxFilterModeTypeFromString(tmp)) < 0)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid 'vlan' "
+ "in query-rx-filter response"));
+ goto cleanup;
+ }
+ if ((!(table = virJSONValueObjectGet(entry, "vlan-table"))) ||
+ ((nTable = virJSONValueArraySize(table)) < 0)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing or invalid 'vlan-table' array "
+ "in query-rx-filter response"));
+ goto cleanup;
+ }
+ if (VIR_ALLOC_N(fil->vlan.table, nTable))
+ goto cleanup;
+ for (i = 0; i < nTable; i++) {
+ if (!(element = virJSONValueArrayGet(table, i)) ||
+ virJSONValueGetNumberUint(element, &fil->vlan.table[i]) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Missing or invalid element %zu of 'vlan-table' "
+ "array in query-rx-filter response"), i);
+ goto cleanup;
+ }
+ }
+ fil->vlan.nTable = nTable;
+
+ ret = 0;
+ cleanup:
+ if (ret < 0) {
+ virNetDevRxFilterFree(fil);
+ fil = NULL;
+ }
+ *filter = fil;
+ return ret;
+}
+
+
+int
+qemuMonitorJSONQueryRxFilter(qemuMonitorPtr mon, const char *alias,
+ virNetDevRxFilterPtr *filter)
+{
+ int ret = -1;
+ virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-rx-filter",
+ "s:name", alias,
+ NULL);
+ virJSONValuePtr reply = NULL;
+
+ if (!cmd)
+ goto cleanup;
+
+ if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+ goto cleanup;
+
+ if (qemuMonitorJSONQueryRxFilterParse(reply, filter) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ if (ret == 0)
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+ if (ret < 0) {
+ virNetDevRxFilterFree(*filter);
+ *filter = NULL;
+ }
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
/*
* Example return data
*
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 289bd11..8d88c6d 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -210,6 +210,9 @@ int qemuMonitorJSONAddNetdev(qemuMonitorPtr mon,
int qemuMonitorJSONRemoveNetdev(qemuMonitorPtr mon,
const char *alias);
+int qemuMonitorJSONQueryRxFilter(qemuMonitorPtr mon, const char *alias,
+ virNetDevRxFilterPtr *filter);
+
int qemuMonitorJSONGetPtyPaths(qemuMonitorPtr mon,
virHashTablePtr paths);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d6c3cfb..110effd 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -35,6 +35,7 @@ AM_CFLAGS = \
-Dabs_builddir="\"$(abs_builddir)\"" \
-Dabs_srcdir="\"$(abs_srcdir)\"" \
$(LIBXML_CFLAGS) \
+ $(LIBNL_CFLAGS) \
$(GNUTLS_CFLAGS) \
$(SASL_CFLAGS) \
$(SELINUX_CFLAGS) \
--
2.1.3