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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list