From: Mehdi Abaakouk <sileht@xxxxxxxxxx> When vhostuser interfaces are used, the interface statistics are not available in /proc/net/dev. This change looks at the openvswitch interfaces statistics tables to provide this information for vhostuser interface. Note that in openvswitch world drop/error doesn't always make sense for some interface type. When these informations are not available we set them to 0 on the virDomainInterfaceStats. --- src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 29 ++++++++--- src/util/virnetdevopenvswitch.c | 106 ++++++++++++++++++++++++++++++++++++++++ src/util/virnetdevopenvswitch.h | 4 ++ 4 files changed, 133 insertions(+), 7 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index baff82b..aa27f78 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2034,6 +2034,7 @@ virNetDevMidonetUnbindPort; # util/virnetdevopenvswitch.h virNetDevOpenvswitchAddPort; virNetDevOpenvswitchGetMigrateData; +virNetDevOpenvswitchInterfaceStats; virNetDevOpenvswitchRemovePort; virNetDevOpenvswitchSetMigrateData; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d039255..87ca09d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -66,6 +66,7 @@ #include "virhostcpu.h" #include "virhostmem.h" #include "virstats.h" +#include "virnetdevopenvswitch.h" #include "capabilities.h" #include "viralloc.h" #include "viruuid.h" @@ -10975,6 +10976,7 @@ qemuDomainInterfaceStats(virDomainPtr dom, virDomainInterfaceStatsPtr stats) { virDomainObjPtr vm; + virDomainNetDefPtr net = NULL; size_t i; int ret = -1; @@ -10994,16 +10996,21 @@ qemuDomainInterfaceStats(virDomainPtr dom, for (i = 0; i < vm->def->nnets; i++) { if (vm->def->nets[i]->ifname && STREQ(vm->def->nets[i]->ifname, path)) { - ret = 0; + net = vm->def->nets[i]; break; } } - if (ret == 0) - ret = virNetInterfaceStats(path, stats); - else + if (net) { + if (net->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) { + ret = virNetDevOpenvswitchInterfaceStats(path, stats); + } else { + ret = virNetInterfaceStats(path, stats); + } + } else { virReportError(VIR_ERR_INVALID_ARG, _("invalid path, '%s' is not a known interface"), path); + } cleanup: virDomainObjEndAPI(&vm); @@ -19140,9 +19147,17 @@ qemuDomainGetStatsInterface(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, QEMU_ADD_NAME_PARAM(record, maxparams, "net", "name", i, dom->def->nets[i]->ifname); - if (virNetInterfaceStats(dom->def->nets[i]->ifname, &tmp) < 0) { - virResetLastError(); - continue; + if (dom->def->nets[i]->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) { + if (virNetDevOpenvswitchInterfaceStats(dom->def->nets[i]->ifname, + &tmp) < 0) { + virResetLastError(); + continue; + } + } else { + if (virNetInterfaceStats(dom->def->nets[i]->ifname, &tmp) < 0) { + virResetLastError(); + continue; + } } QEMU_ADD_NET_PARAM(record, maxparams, i, diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c index 9283bbb..db8b542 100644 --- a/src/util/virnetdevopenvswitch.c +++ b/src/util/virnetdevopenvswitch.c @@ -24,6 +24,8 @@ #include <config.h> +#include <stdio.h> + #include "virnetdevopenvswitch.h" #include "vircommand.h" #include "viralloc.h" @@ -270,3 +272,107 @@ int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname) virCommandFree(cmd); return ret; } + +/** + * virNetDevOpenvswitchInterfaceStats: + * @ifname: the name of the interface + * @stats: the retreived domain interface stat + * + * Retrieves the OVS interfaces stats + * + * Returns 0 in case of success or -1 in case of failure + */ +int +virNetDevOpenvswitchInterfaceStats(const char *ifname, + virDomainInterfaceStatsPtr stats) +{ + virCommandPtr cmd = NULL; + char *output; + long long rx_bytes; + long long rx_packets; + long long tx_bytes; + long long tx_packets; + long long rx_errs; + long long rx_drop; + long long tx_errs; + long long tx_drop; + int ret = -1; + + // Just ensure the interface exists in ovs + cmd = virCommandNewArgList(OVSVSCTL, "--timeout=5", + "get", "Interface", ifname, + "name", NULL); + virCommandSetOutputBuffer(cmd, &output); + + if (virCommandRun(cmd, NULL) < 0) { + // no ovs-vsctl or interface 'ifname' doesn't exists in ovs + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Interface not found")); + goto cleanup; + } + + VIR_FREE(output); + virCommandFree(cmd); + + cmd = virCommandNewArgList(OVSVSCTL, "--timeout=5", + "get", "Interface", ifname, + "statistics:rx_bytes", + "statistics:rx_packets", + "statistics:tx_bytes", + "statistics:tx_packets", NULL); + virCommandSetOutputBuffer(cmd, &output); + + if (virCommandRun(cmd, NULL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Interface doesn't have statistics")); + goto cleanup; + } + + // The TX/RX fields appear to be swapped here because this is the host view. + if (sscanf(output, "%lld\n%lld\n%lld\n%lld\n", + &tx_bytes, &tx_packets, &rx_bytes, &rx_packets) != 4) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Fail to parse ovs-vsctl output")); + goto cleanup; + } + + stats->rx_bytes = rx_bytes; + stats->rx_packets = rx_packets; + stats->tx_bytes = tx_bytes; + stats->tx_packets = tx_packets; + + VIR_FREE(output); + virCommandFree(cmd); + + cmd = virCommandNewArgList(OVSVSCTL, "--timeout=5", + "get", "Interface", ifname, + "statistics:rx_errors", + "statistics:rx_dropped", + "statistics:tx_errors", + "statistics:tx_dropped", NULL); + virCommandSetOutputBuffer(cmd, &output); + if (virCommandRun(cmd, NULL) < 0) { + // This interface don't have errors or dropped, so set them to 0 + stats->rx_errs = 0; + stats->rx_drop = 0; + stats->tx_errs = 0; + stats->tx_drop = 0; + } else if (sscanf(output, "%lld\n%lld\n%lld\n%lld\n", + &tx_errs, &tx_drop, &rx_errs, &rx_drop) == 4) { + stats->rx_errs = rx_errs; + stats->rx_drop = rx_drop; + stats->tx_errs = tx_errs; + stats->tx_drop = tx_drop; + ret = 0; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Fail to parse ovs-vsctl output")); + goto cleanup; + } + ret = 0; + + cleanup: + VIR_FREE(output); + virCommandFree(cmd); + return ret; +} diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitch.h index 131be73..0f9e1df 100644 --- a/src/util/virnetdevopenvswitch.h +++ b/src/util/virnetdevopenvswitch.h @@ -48,4 +48,8 @@ int virNetDevOpenvswitchGetMigrateData(char **migrate, const char *ifname) int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; +int virNetDevOpenvswitchInterfaceStats(const char *ifname, + virDomainInterfaceStatsPtr stats) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + #endif /* __VIR_NETDEV_OPENVSWITCH_H__ */ -- 2.10.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list