mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 03:12:22 +00:00
Gathering vhostuser interface stats with ovs
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. Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
03876cf506
commit
013df874db
@ -2047,6 +2047,7 @@ virNetDevMidonetUnbindPort;
|
||||
# util/virnetdevopenvswitch.h
|
||||
virNetDevOpenvswitchAddPort;
|
||||
virNetDevOpenvswitchGetMigrateData;
|
||||
virNetDevOpenvswitchInterfaceStats;
|
||||
virNetDevOpenvswitchRemovePort;
|
||||
virNetDevOpenvswitchSetMigrateData;
|
||||
|
||||
|
@ -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"
|
||||
@ -10974,6 +10975,7 @@ qemuDomainInterfaceStats(virDomainPtr dom,
|
||||
virDomainInterfaceStatsPtr stats)
|
||||
{
|
||||
virDomainObjPtr vm;
|
||||
virDomainNetDefPtr net = NULL;
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
@ -10991,19 +10993,27 @@ qemuDomainInterfaceStats(virDomainPtr dom,
|
||||
|
||||
/* Check the path is one of the domain's network interfaces. */
|
||||
for (i = 0; i < vm->def->nnets; i++) {
|
||||
if (vm->def->nets[i]->ifname &&
|
||||
STREQ(vm->def->nets[i]->ifname, path)) {
|
||||
ret = 0;
|
||||
if (STREQ_NULLABLE(vm->def->nets[i]->ifname, path)) {
|
||||
net = vm->def->nets[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
ret = virNetInterfaceStats(path, stats);
|
||||
else
|
||||
if (!net) {
|
||||
virReportError(VIR_ERR_INVALID_ARG,
|
||||
_("invalid path, '%s' is not a known interface"), path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (net->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
|
||||
if (virNetDevOpenvswitchInterfaceStats(path, stats) < 0)
|
||||
goto cleanup;
|
||||
} else {
|
||||
if (virNetInterfaceStats(path, stats) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
virDomainObjEndAPI(&vm);
|
||||
return ret;
|
||||
@ -19187,9 +19197,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,
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "virnetdevopenvswitch.h"
|
||||
#include "vircommand.h"
|
||||
#include "viralloc.h"
|
||||
@ -270,3 +272,108 @@ 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 */
|
||||
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;
|
||||
}
|
||||
|
@ -48,4 +48,8 @@ int virNetDevOpenvswitchGetMigrateData(char **migrate, const char *ifname)
|
||||
int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||
|
||||
int virNetDevOpenvswitchInterfaceStats(const char *ifname,
|
||||
virDomainInterfaceStatsPtr stats)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||
|
||||
#endif /* __VIR_NETDEV_OPENVSWITCH_H__ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user