[libvirt] [PATCH] Gathering network interface statistics with openvswitch

Hi, To follow up, my question about vhostuser/ovs interfaces statistics. This is my porposal to implement this feature. Regards, Mehdi Abaakouk (1): virstats: Gathering net interface stats with ovs src/util/virstats.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 3 deletions(-) -- 2.10.2

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

On Fri, Nov 18, 2016 at 09:06:51AM +0100, Mehdi Abaakouk wrote:
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
Rather than putting all this new code in virnetstats.h, I think we need todo some refactoring here. The existing code ought to live in a method in virnetdevtap.c, while your new code should live in a method in the virnetdevopenvswitch.c file. We should then modify the qemu driver code qemuDomainInterfaceStats so that it looks at 'vm->def->nets[i]->type' field to decide whether to call the TAP stats method or the openvswitch stats method or raise an error. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://entangle-photo.org -o- http://search.cpan.org/~danberr/ :|
participants (2)
-
Daniel P. Berrange
-
Mehdi Abaakouk