[libvirt] [PATCH] virstats: Gathering net interface stats with ovs

Mehdi Abaakouk sileht at sileht.net
Fri Nov 18 08:06:51 UTC 2016


When vhostuser or ovs interfaces are used, the interface statistics
are not always available in /proc/net/dev.

This change looks at the openvswitch interfaces statistics
tables to provide this information in additional to /proc/net/dev.

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/util/virstats.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 96 insertions(+), 3 deletions(-)

diff --git a/src/util/virstats.c b/src/util/virstats.c
index c4725ed..457526d 100644
--- a/src/util/virstats.c
+++ b/src/util/virstats.c
@@ -34,6 +34,7 @@
 # include <ifaddrs.h>
 #endif
 
+#include "vircommand.h"
 #include "virerror.h"
 #include "datatypes.h"
 #include "virstats.h"
@@ -115,9 +116,101 @@ virNetInterfaceStats(const char *path,
     }
     VIR_FORCE_FCLOSE(fp);
 
-    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                   _("/proc/net/dev: Interface not found"));
-    return -1;
+
+    /* We don't find the interface in /proc/net/dev, let's see if we can find
+     * it in openvswitch. We only looks for bytes and packets first.
+     * errors and dropped does not exists for all type of ovs interfaces.
+     * For the same reason as /proc/net/dev the TX/RX fields appear to be
+     * swapped here.
+     */
+    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", path,
+                               "name", NULL);
+    virCommandSetOutputBuffer(cmd, &output);
+
+    if (virCommandRun(cmd, NULL) < 0) {
+        // no ovs-vsctl or interface 'path' 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", path,
+                               "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;
+    }
+
+    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", path,
+                               "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;
 }
 #elif defined(HAVE_GETIFADDRS) && defined(AF_LINK)
 int
-- 
2.10.2




More information about the libvir-list mailing list