[libvirt] [PATCH v3 1/4] Gathering vhostuser interface stats with ovs

Michal Privoznik mprivozn at redhat.com
Thu Dec 8 12:51:13 UTC 2016


On 18.11.2016 23:51, Mehdi Abaakouk wrote:
> From: Mehdi Abaakouk <sileht at redhat.com>
> 
> 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




More information about the libvir-list mailing list