]> xenbits.xensource.com Git - libvirt.git/commitdiff
Gathering vhostuser interface stats with ovs
authorMehdi Abaakouk <sileht@redhat.com>
Fri, 18 Nov 2016 22:51:13 +0000 (23:51 +0100)
committerMichal Privoznik <mprivozn@redhat.com>
Fri, 9 Dec 2016 09:23:09 +0000 (10:23 +0100)
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.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
src/libvirt_private.syms
src/qemu/qemu_driver.c
src/util/virnetdevopenvswitch.c
src/util/virnetdevopenvswitch.h

index 826efbd29363f609431c864f32aa8afc358aa997..500419c177feff2f74a86fabfff41ebe476c4a19 100644 (file)
@@ -2047,6 +2047,7 @@ virNetDevMidonetUnbindPort;
 # util/virnetdevopenvswitch.h
 virNetDevOpenvswitchAddPort;
 virNetDevOpenvswitchGetMigrateData;
+virNetDevOpenvswitchInterfaceStats;
 virNetDevOpenvswitchRemovePort;
 virNetDevOpenvswitchSetMigrateData;
 
index 2997f1f95d7edb4b7b73b7562fbde13decd9403b..d86d301a9164d15bb39e99893a3e1ef002e54981 100644 (file)
@@ -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"
@@ -10974,6 +10975,7 @@ qemuDomainInterfaceStats(virDomainPtr dom,
                          virDomainInterfaceStatsPtr stats)
 {
     virDomainObjPtr vm;
+    virDomainNetDefPtr net = NULL;
     size_t i;
     int ret = -1;
 
@@ -10991,19 +10993,27 @@ qemuDomainInterfaceStats(virDomainPtr dom,
 
     /* Check the path is one of the domain's network interfaces. */
     for (i = 0; i < vm->def->nnets; i++) {
-        if (vm->def->nets[i]->ifname &&
-            STREQ(vm->def->nets[i]->ifname, path)) {
-            ret = 0;
+        if (STREQ_NULLABLE(vm->def->nets[i]->ifname, path)) {
+            net = vm->def->nets[i];
             break;
         }
     }
 
-    if (ret == 0)
-        ret = virNetInterfaceStats(path, stats);
-    else
+    if (!net) {
         virReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path, '%s' is not a known interface"), path);
+        goto cleanup;
+    }
+
+    if (net->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
+        if (virNetDevOpenvswitchInterfaceStats(path, stats) < 0)
+            goto cleanup;
+    } else {
+        if (virNetInterfaceStats(path, stats) < 0)
+            goto cleanup;
+    }
 
+    ret = 0;
  cleanup:
     virDomainObjEndAPI(&vm);
     return ret;
@@ -19187,9 +19197,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,
index 9283bbb6d9407d6b01aed8e64fdfd5e97001fa1d..f003b3b134af13fdee17ab89eb24807acde2ea3e 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <config.h>
 
+#include <stdio.h>
+
 #include "virnetdevopenvswitch.h"
 #include "vircommand.h"
 #include "viralloc.h"
@@ -270,3 +272,108 @@ 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;
+}
index 131be732430417b66f769d79fccecc3eab74c11e..0f9e1dfa66f7b0f0d51b7013d2b1a715098afe81 100644 (file)
@@ -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__ */