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
|
# util/virnetdevopenvswitch.h
|
||||||
virNetDevOpenvswitchAddPort;
|
virNetDevOpenvswitchAddPort;
|
||||||
virNetDevOpenvswitchGetMigrateData;
|
virNetDevOpenvswitchGetMigrateData;
|
||||||
|
virNetDevOpenvswitchInterfaceStats;
|
||||||
virNetDevOpenvswitchRemovePort;
|
virNetDevOpenvswitchRemovePort;
|
||||||
virNetDevOpenvswitchSetMigrateData;
|
virNetDevOpenvswitchSetMigrateData;
|
||||||
|
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
#include "virhostcpu.h"
|
#include "virhostcpu.h"
|
||||||
#include "virhostmem.h"
|
#include "virhostmem.h"
|
||||||
#include "virstats.h"
|
#include "virstats.h"
|
||||||
|
#include "virnetdevopenvswitch.h"
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
#include "viralloc.h"
|
#include "viralloc.h"
|
||||||
#include "viruuid.h"
|
#include "viruuid.h"
|
||||||
@ -10974,6 +10975,7 @@ qemuDomainInterfaceStats(virDomainPtr dom,
|
|||||||
virDomainInterfaceStatsPtr stats)
|
virDomainInterfaceStatsPtr stats)
|
||||||
{
|
{
|
||||||
virDomainObjPtr vm;
|
virDomainObjPtr vm;
|
||||||
|
virDomainNetDefPtr net = NULL;
|
||||||
size_t i;
|
size_t i;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
@ -10991,19 +10993,27 @@ qemuDomainInterfaceStats(virDomainPtr dom,
|
|||||||
|
|
||||||
/* Check the path is one of the domain's network interfaces. */
|
/* Check the path is one of the domain's network interfaces. */
|
||||||
for (i = 0; i < vm->def->nnets; i++) {
|
for (i = 0; i < vm->def->nnets; i++) {
|
||||||
if (vm->def->nets[i]->ifname &&
|
if (STREQ_NULLABLE(vm->def->nets[i]->ifname, path)) {
|
||||||
STREQ(vm->def->nets[i]->ifname, path)) {
|
net = vm->def->nets[i];
|
||||||
ret = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0)
|
if (!net) {
|
||||||
ret = virNetInterfaceStats(path, stats);
|
|
||||||
else
|
|
||||||
virReportError(VIR_ERR_INVALID_ARG,
|
virReportError(VIR_ERR_INVALID_ARG,
|
||||||
_("invalid path, '%s' is not a known interface"), path);
|
_("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:
|
cleanup:
|
||||||
virDomainObjEndAPI(&vm);
|
virDomainObjEndAPI(&vm);
|
||||||
return ret;
|
return ret;
|
||||||
@ -19187,9 +19197,17 @@ qemuDomainGetStatsInterface(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
|
|||||||
QEMU_ADD_NAME_PARAM(record, maxparams,
|
QEMU_ADD_NAME_PARAM(record, maxparams,
|
||||||
"net", "name", i, dom->def->nets[i]->ifname);
|
"net", "name", i, dom->def->nets[i]->ifname);
|
||||||
|
|
||||||
if (virNetInterfaceStats(dom->def->nets[i]->ifname, &tmp) < 0) {
|
if (dom->def->nets[i]->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
|
||||||
virResetLastError();
|
if (virNetDevOpenvswitchInterfaceStats(dom->def->nets[i]->ifname,
|
||||||
continue;
|
&tmp) < 0) {
|
||||||
|
virResetLastError();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (virNetInterfaceStats(dom->def->nets[i]->ifname, &tmp) < 0) {
|
||||||
|
virResetLastError();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QEMU_ADD_NET_PARAM(record, maxparams, i,
|
QEMU_ADD_NET_PARAM(record, maxparams, i,
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "virnetdevopenvswitch.h"
|
#include "virnetdevopenvswitch.h"
|
||||||
#include "vircommand.h"
|
#include "vircommand.h"
|
||||||
#include "viralloc.h"
|
#include "viralloc.h"
|
||||||
@ -270,3 +272,108 @@ int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname)
|
|||||||
virCommandFree(cmd);
|
virCommandFree(cmd);
|
||||||
return ret;
|
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)
|
int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname)
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
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__ */
|
#endif /* __VIR_NETDEV_OPENVSWITCH_H__ */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user