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