mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-27 07:22:07 +03:00
virNetDevOpenvswitchInterfaceStats: Be more forgiving when fetching stats
https://bugzilla.redhat.com/show_bug.cgi?id=1461270 When fetching stats for a vhost-user type of interface, we run couple of ovs-vsctl commands and parse their output. However, not all stats exist at all times, for instance "rx_dropped" or "tx_errors" can be missing. Thing is, we ask for a bulk of statistics and if one of them is missing an error is reported instead of returning the rest. Since we ignore errors, we fail to set statistics. Fix this by asking for each piece alone. Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
10c2bb2b19
commit
edaf135657
@ -317,14 +317,8 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname,
|
|||||||
{
|
{
|
||||||
virCommandPtr cmd = NULL;
|
virCommandPtr cmd = NULL;
|
||||||
char *output;
|
char *output;
|
||||||
long long rx_bytes;
|
char *tmp;
|
||||||
long long rx_packets;
|
bool gotStats = false;
|
||||||
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;
|
int ret = -1;
|
||||||
|
|
||||||
/* Just ensure the interface exists in ovs */
|
/* Just ensure the interface exists in ovs */
|
||||||
@ -340,67 +334,45 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
VIR_FREE(output);
|
#define GET_STAT(name, member) \
|
||||||
virCommandFree(cmd);
|
do { \
|
||||||
|
VIR_FREE(output); \
|
||||||
cmd = virCommandNew(OVSVSCTL);
|
virCommandFree(cmd); \
|
||||||
virNetDevOpenvswitchAddTimeout(cmd);
|
cmd = virCommandNew(OVSVSCTL); \
|
||||||
virCommandAddArgList(cmd, "get", "Interface", ifname,
|
virNetDevOpenvswitchAddTimeout(cmd); \
|
||||||
"statistics:rx_bytes",
|
virCommandAddArgList(cmd, "get", "Interface", ifname, \
|
||||||
"statistics:rx_packets",
|
"statistics:" name, NULL); \
|
||||||
"statistics:tx_bytes",
|
virCommandSetOutputBuffer(cmd, &output); \
|
||||||
"statistics:tx_packets", NULL);
|
if (virCommandRun(cmd, NULL) < 0) { \
|
||||||
virCommandSetOutputBuffer(cmd, &output);
|
stats->member = -1; \
|
||||||
|
} else { \
|
||||||
if (virCommandRun(cmd, NULL) < 0) {
|
if (virStrToLong_ll(output, &tmp, 10, &stats->member) < 0 || \
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
*tmp != '\n') { \
|
||||||
_("Interface doesn't have statistics"));
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", \
|
||||||
goto cleanup;
|
_("Fail to parse ovs-vsctl output")); \
|
||||||
}
|
goto cleanup; \
|
||||||
|
} \
|
||||||
|
gotStats = true; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/* The TX/RX fields appear to be swapped here
|
/* The TX/RX fields appear to be swapped here
|
||||||
* because this is the host view. */
|
* because this is the host view. */
|
||||||
if (sscanf(output, "%lld\n%lld\n%lld\n%lld\n",
|
GET_STAT("rx_bytes", tx_bytes);
|
||||||
&tx_bytes, &tx_packets, &rx_bytes, &rx_packets) != 4) {
|
GET_STAT("rx_packets", tx_packets);
|
||||||
|
GET_STAT("rx_errors", tx_errs);
|
||||||
|
GET_STAT("rx_dropped", tx_drop);
|
||||||
|
GET_STAT("tx_bytes", rx_bytes);
|
||||||
|
GET_STAT("tx_packets", rx_packets);
|
||||||
|
GET_STAT("tx_errors", rx_errs);
|
||||||
|
GET_STAT("tx_dropped", rx_drop);
|
||||||
|
|
||||||
|
if (!gotStats) {
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
_("Fail to parse ovs-vsctl output"));
|
_("Interface doesn't have any statistics"));
|
||||||
goto cleanup;
|
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 = virCommandNew(OVSVSCTL);
|
|
||||||
virNetDevOpenvswitchAddTimeout(cmd);
|
|
||||||
virCommandAddArgList(cmd, "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;
|
ret = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
Loading…
Reference in New Issue
Block a user