[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