On 18.11.2016 23:51, Mehdi Abaakouk wrote: > From: Mehdi Abaakouk <sileht@xxxxxxxxxx> > > When vhostuser interfaces are used, the interface statistics > are not available in /proc/net/dev. > > This change looks at the openvswitch interfaces statistics > tables to provide this information for vhostuser interface. > > 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/libvirt_private.syms | 1 + > src/qemu/qemu_driver.c | 29 ++++++++--- > src/util/virnetdevopenvswitch.c | 106 ++++++++++++++++++++++++++++++++++++++++ > src/util/virnetdevopenvswitch.h | 4 ++ > 4 files changed, 133 insertions(+), 7 deletions(-) > > diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > index baff82b..aa27f78 100644 > --- a/src/libvirt_private.syms > +++ b/src/libvirt_private.syms > @@ -2034,6 +2034,7 @@ virNetDevMidonetUnbindPort; > # util/virnetdevopenvswitch.h > virNetDevOpenvswitchAddPort; > virNetDevOpenvswitchGetMigrateData; > +virNetDevOpenvswitchInterfaceStats; > virNetDevOpenvswitchRemovePort; > virNetDevOpenvswitchSetMigrateData; > > diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c > index d039255..87ca09d 100644 > --- a/src/qemu/qemu_driver.c > +++ b/src/qemu/qemu_driver.c > @@ -66,6 +66,7 @@ > #include "virhostcpu.h" > #include "virhostmem.h" > #include "virstats.h" > +#include "virnetdevopenvswitch.h" > #include "capabilities.h" > #include "viralloc.h" > #include "viruuid.h" > @@ -10975,6 +10976,7 @@ qemuDomainInterfaceStats(virDomainPtr dom, > virDomainInterfaceStatsPtr stats) > { > virDomainObjPtr vm; > + virDomainNetDefPtr net = NULL; > size_t i; > int ret = -1; > > @@ -10994,16 +10996,21 @@ qemuDomainInterfaceStats(virDomainPtr dom, > for (i = 0; i < vm->def->nnets; i++) { > if (vm->def->nets[i]->ifname && > STREQ(vm->def->nets[i]->ifname, path)) { > - ret = 0; > + net = vm->def->nets[i]; > break; > } > } > > - if (ret == 0) > - ret = virNetInterfaceStats(path, stats); > - else > + if (net) { > + if (net->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) { > + ret = virNetDevOpenvswitchInterfaceStats(path, stats); > + } else { > + ret = virNetInterfaceStats(path, stats); > + } > + } else { > virReportError(VIR_ERR_INVALID_ARG, > _("invalid path, '%s' is not a known interface"), path); > + } > Oh my. Not your fault but this looks ugly. It has even before you've touched it. BTW: maybe I am misreading something but my understanding of vhost-user is that it can be plugged into any type of bridge (e.g. snabb). How does this work then if we run ovs-vsctl then? Do you perhaps have a set of steps how can I test this feature? Because so far I've used vhost-user-bridge helper from qemu repo but this will not work with it. > cleanup: > virDomainObjEndAPI(&vm); > @@ -19140,9 +19147,17 @@ qemuDomainGetStatsInterface(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, > QEMU_ADD_NAME_PARAM(record, maxparams, > "net", "name", i, dom->def->nets[i]->ifname); > > - if (virNetInterfaceStats(dom->def->nets[i]->ifname, &tmp) < 0) { > - virResetLastError(); > - continue; > + if (dom->def->nets[i]->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) { > + if (virNetDevOpenvswitchInterfaceStats(dom->def->nets[i]->ifname, > + &tmp) < 0) { > + virResetLastError(); > + continue; > + } > + } else { > + if (virNetInterfaceStats(dom->def->nets[i]->ifname, &tmp) < 0) { > + virResetLastError(); > + continue; > + } > } > > QEMU_ADD_NET_PARAM(record, maxparams, i, > diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c > index 9283bbb..db8b542 100644 > --- a/src/util/virnetdevopenvswitch.c > +++ b/src/util/virnetdevopenvswitch.c > @@ -24,6 +24,8 @@ > > #include <config.h> > > +#include <stdio.h> > + > #include "virnetdevopenvswitch.h" > #include "vircommand.h" > #include "viralloc.h" > @@ -270,3 +272,107 @@ int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname) > virCommandFree(cmd); > return ret; > } > + > +/** > + * virNetDevOpenvswitchInterfaceStats: > + * @ifname: the name of the interface > + * @stats: the retreived domain interface stat > + * > + * Retrieves the OVS interfaces stats > + * > + * Returns 0 in case of success or -1 in case of failure > + */ > +int > +virNetDevOpenvswitchInterfaceStats(const char *ifname, > + virDomainInterfaceStatsPtr stats) > +{ > + 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", ifname, > + "name", NULL); > + virCommandSetOutputBuffer(cmd, &output); > + > + if (virCommandRun(cmd, NULL) < 0) { > + // no ovs-vsctl or interface 'ifname' doesn't exists in ovs We prefer c89 style of comments. > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("Interface not found")); > + goto cleanup; > + } > + > + VIR_FREE(output); > + virCommandFree(cmd); > + > + cmd = virCommandNewArgList(OVSVSCTL, "--timeout=5", > + "get", "Interface", ifname, > + "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; > + } > + > + // The TX/RX fields appear to be swapped here because this is the host view. > + 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", ifname, > + "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; > +} Michal -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list