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