From: Mehdi Abaakouk <sileht(a)redhat.com>
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