From 81c354a5025995d3e5c88b63a3de64f9c0731f20 Mon Sep 17 00:00:00 2001 Message-Id: <81c354a5025995d3e5c88b63a3de64f9c0731f20@dist-git> From: Laine Stump 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 --- 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