[libvirt] [PATCH] virstats: Gathering net interface stats with ovs

Daniel P. Berrange berrange at redhat.com
Fri Nov 18 13:57:23 UTC 2016


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/ :|




More information about the libvir-list mailing list