|
|
25aafc |
From 5ca75531afd1244898ee7c8d2307857ba8260cba Mon Sep 17 00:00:00 2001
|
|
|
25aafc |
Message-Id: <5ca75531afd1244898ee7c8d2307857ba8260cba@dist-git>
|
|
|
25aafc |
From: Michal Privoznik <mprivozn@redhat.com>
|
|
|
25aafc |
Date: Wed, 9 Oct 2019 14:27:41 +0200
|
|
|
25aafc |
Subject: [PATCH] virNetDevOpenvswitchInterfaceStats: Optimize for speed
|
|
|
25aafc |
MIME-Version: 1.0
|
|
|
25aafc |
Content-Type: text/plain; charset=UTF-8
|
|
|
25aafc |
Content-Transfer-Encoding: 8bit
|
|
|
25aafc |
|
|
|
25aafc |
We run 'ovs-vsctl' nine times (first to find if interface is
|
|
|
25aafc |
there and then eight times = for each stats member separately).
|
|
|
25aafc |
This is very inefficient. I've found a way to run it once and
|
|
|
25aafc |
with a bit of help from virJSON module we can parse out stats
|
|
|
25aafc |
we need.
|
|
|
25aafc |
|
|
|
25aafc |
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
25aafc |
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
|
|
25aafc |
(cherry picked from commit c297eab52599c91a4cb26b66dbdfe9d07c3142d3)
|
|
|
25aafc |
|
|
|
25aafc |
https://bugzilla.redhat.com/show_bug.cgi?id=1759904
|
|
|
25aafc |
|
|
|
25aafc |
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
25aafc |
Message-Id: <9904d3bee93a9e103012d088b77999f023acaa2b.1570623892.git.mprivozn@redhat.com>
|
|
|
25aafc |
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
25aafc |
---
|
|
|
25aafc |
src/util/virnetdevopenvswitch.c | 119 +++++++++++++++++++++-----------
|
|
|
25aafc |
1 file changed, 78 insertions(+), 41 deletions(-)
|
|
|
25aafc |
|
|
|
25aafc |
diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c
|
|
|
25aafc |
index f36916a300..fc92ab2e7f 100644
|
|
|
25aafc |
--- a/src/util/virnetdevopenvswitch.c
|
|
|
25aafc |
+++ b/src/util/virnetdevopenvswitch.c
|
|
|
25aafc |
@@ -35,6 +35,7 @@
|
|
|
25aafc |
#include "virmacaddr.h"
|
|
|
25aafc |
#include "virstring.h"
|
|
|
25aafc |
#include "virlog.h"
|
|
|
25aafc |
+#include "virjson.h"
|
|
|
25aafc |
|
|
|
25aafc |
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
25aafc |
|
|
|
25aafc |
@@ -339,58 +340,94 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname,
|
|
|
25aafc |
virDomainInterfaceStatsPtr stats)
|
|
|
25aafc |
{
|
|
|
25aafc |
virCommandPtr cmd = NULL;
|
|
|
25aafc |
- char *output;
|
|
|
25aafc |
- char *tmp;
|
|
|
25aafc |
- bool gotStats = false;
|
|
|
25aafc |
+ VIR_AUTOFREE(char *) output = NULL;
|
|
|
25aafc |
+ virJSONValuePtr jsonStats = NULL;
|
|
|
25aafc |
+ virJSONValuePtr jsonMap = NULL;
|
|
|
25aafc |
+ size_t i;
|
|
|
25aafc |
int ret = -1;
|
|
|
25aafc |
|
|
|
25aafc |
- /* Just ensure the interface exists in ovs */
|
|
|
25aafc |
cmd = virCommandNew(OVSVSCTL);
|
|
|
25aafc |
virNetDevOpenvswitchAddTimeout(cmd);
|
|
|
25aafc |
- virCommandAddArgList(cmd, "get", "Interface", ifname, "name", NULL);
|
|
|
25aafc |
+ virCommandAddArgList(cmd, "--if-exists", "--format=list", "--data=json",
|
|
|
25aafc |
+ "--no-headings", "--columns=statistics", "list",
|
|
|
25aafc |
+ "Interface", ifname, NULL);
|
|
|
25aafc |
virCommandSetOutputBuffer(cmd, &output);
|
|
|
25aafc |
|
|
|
25aafc |
- if (virCommandRun(cmd, NULL) < 0) {
|
|
|
25aafc |
+ /* The above command returns either:
|
|
|
25aafc |
+ * 1) empty string if @ifname doesn't exist, or
|
|
|
25aafc |
+ * 2) a JSON array, for instance:
|
|
|
25aafc |
+ * ["map",[["collisions",0],["rx_bytes",0],["rx_crc_err",0],["rx_dropped",0],
|
|
|
25aafc |
+ * ["rx_errors",0],["rx_frame_err",0],["rx_over_err",0],["rx_packets",0],
|
|
|
25aafc |
+ * ["tx_bytes",12406],["tx_dropped",0],["tx_errors",0],["tx_packets",173]]]
|
|
|
25aafc |
+ */
|
|
|
25aafc |
+
|
|
|
25aafc |
+ if (virCommandRun(cmd, NULL) < 0 ||
|
|
|
25aafc |
+ STREQ_NULLABLE(output, "")) {
|
|
|
25aafc |
/* no ovs-vsctl or interface 'ifname' doesn't exists in ovs */
|
|
|
25aafc |
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
25aafc |
_("Interface not found"));
|
|
|
25aafc |
goto cleanup;
|
|
|
25aafc |
}
|
|
|
25aafc |
|
|
|
25aafc |
-#define GET_STAT(name, member) \
|
|
|
25aafc |
- do { \
|
|
|
25aafc |
- VIR_FREE(output); \
|
|
|
25aafc |
- virCommandFree(cmd); \
|
|
|
25aafc |
- cmd = virCommandNew(OVSVSCTL); \
|
|
|
25aafc |
- virNetDevOpenvswitchAddTimeout(cmd); \
|
|
|
25aafc |
- virCommandAddArgList(cmd, "--if-exists", "get", "Interface", \
|
|
|
25aafc |
- ifname, "statistics:" name, NULL); \
|
|
|
25aafc |
- virCommandSetOutputBuffer(cmd, &output); \
|
|
|
25aafc |
- if (virCommandRun(cmd, NULL) < 0 || !output || !*output || *output == '\n') { \
|
|
|
25aafc |
- stats->member = -1; \
|
|
|
25aafc |
- } else { \
|
|
|
25aafc |
- if (virStrToLong_ll(output, &tmp, 10, &stats->member) < 0 || \
|
|
|
25aafc |
- *tmp != '\n') { \
|
|
|
25aafc |
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", \
|
|
|
25aafc |
- _("Fail to parse ovs-vsctl output")); \
|
|
|
25aafc |
- goto cleanup; \
|
|
|
25aafc |
- } \
|
|
|
25aafc |
- gotStats = true; \
|
|
|
25aafc |
- } \
|
|
|
25aafc |
- } while (0)
|
|
|
25aafc |
-
|
|
|
25aafc |
- /* The TX/RX fields appear to be swapped here
|
|
|
25aafc |
- * because this is the host view. */
|
|
|
25aafc |
- GET_STAT("rx_bytes", tx_bytes);
|
|
|
25aafc |
- GET_STAT("rx_packets", tx_packets);
|
|
|
25aafc |
- GET_STAT("rx_errors", tx_errs);
|
|
|
25aafc |
- GET_STAT("rx_dropped", tx_drop);
|
|
|
25aafc |
- GET_STAT("tx_bytes", rx_bytes);
|
|
|
25aafc |
- GET_STAT("tx_packets", rx_packets);
|
|
|
25aafc |
- GET_STAT("tx_errors", rx_errs);
|
|
|
25aafc |
- GET_STAT("tx_dropped", rx_drop);
|
|
|
25aafc |
-
|
|
|
25aafc |
- if (!gotStats) {
|
|
|
25aafc |
+ if (!(jsonStats = virJSONValueFromString(output)) ||
|
|
|
25aafc |
+ !virJSONValueIsArray(jsonStats) ||
|
|
|
25aafc |
+ !(jsonMap = virJSONValueArrayGet(jsonStats, 1))) {
|
|
|
25aafc |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
25aafc |
+ _("Unable to parse ovs-vsctl output"));
|
|
|
25aafc |
+ goto cleanup;
|
|
|
25aafc |
+ }
|
|
|
25aafc |
+
|
|
|
25aafc |
+ stats->rx_bytes = stats->rx_packets = stats->rx_errs = stats->rx_drop = -1;
|
|
|
25aafc |
+ stats->tx_bytes = stats->tx_packets = stats->tx_errs = stats->tx_drop = -1;
|
|
|
25aafc |
+
|
|
|
25aafc |
+ for (i = 0; i < virJSONValueArraySize(jsonMap); i++) {
|
|
|
25aafc |
+ virJSONValuePtr item = virJSONValueArrayGet(jsonMap, i);
|
|
|
25aafc |
+ virJSONValuePtr jsonKey;
|
|
|
25aafc |
+ virJSONValuePtr jsonVal;
|
|
|
25aafc |
+ const char *key;
|
|
|
25aafc |
+ long long val;
|
|
|
25aafc |
+
|
|
|
25aafc |
+ if (!item ||
|
|
|
25aafc |
+ (!(jsonKey = virJSONValueArrayGet(item, 0))) ||
|
|
|
25aafc |
+ (!(jsonVal = virJSONValueArrayGet(item, 1))) ||
|
|
|
25aafc |
+ (!(key = virJSONValueGetString(jsonKey))) ||
|
|
|
25aafc |
+ (virJSONValueGetNumberLong(jsonVal, &val) < 0)) {
|
|
|
25aafc |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
25aafc |
+ _("Malformed ovs-vsctl output"));
|
|
|
25aafc |
+ goto cleanup;
|
|
|
25aafc |
+ }
|
|
|
25aafc |
+
|
|
|
25aafc |
+ /* The TX/RX fields appear to be swapped here
|
|
|
25aafc |
+ * because this is the host view. */
|
|
|
25aafc |
+ if (STREQ(key, "rx_bytes")) {
|
|
|
25aafc |
+ stats->tx_bytes = val;
|
|
|
25aafc |
+ } else if (STREQ(key, "rx_packets")) {
|
|
|
25aafc |
+ stats->tx_packets = val;
|
|
|
25aafc |
+ } else if (STREQ(key, "rx_errors")) {
|
|
|
25aafc |
+ stats->tx_errs = val;
|
|
|
25aafc |
+ } else if (STREQ(key, "rx_dropped")) {
|
|
|
25aafc |
+ stats->tx_drop = val;
|
|
|
25aafc |
+ } else if (STREQ(key, "tx_bytes")) {
|
|
|
25aafc |
+ stats->rx_bytes = val;
|
|
|
25aafc |
+ } else if (STREQ(key, "tx_packets")) {
|
|
|
25aafc |
+ stats->rx_packets = val;
|
|
|
25aafc |
+ } else if (STREQ(key, "tx_errors")) {
|
|
|
25aafc |
+ stats->rx_errs = val;
|
|
|
25aafc |
+ } else if (STREQ(key, "tx_dropped")) {
|
|
|
25aafc |
+ stats->rx_drop = val;
|
|
|
25aafc |
+ } else {
|
|
|
25aafc |
+ VIR_DEBUG("Unused ovs-vsctl stat key=%s val=%lld", key, val);
|
|
|
25aafc |
+ }
|
|
|
25aafc |
+ }
|
|
|
25aafc |
+
|
|
|
25aafc |
+ if (stats->rx_bytes == -1 &&
|
|
|
25aafc |
+ stats->rx_packets == -1 &&
|
|
|
25aafc |
+ stats->rx_errs == -1 &&
|
|
|
25aafc |
+ stats->rx_drop == -1 &&
|
|
|
25aafc |
+ stats->tx_bytes == -1 &&
|
|
|
25aafc |
+ stats->tx_packets == -1 &&
|
|
|
25aafc |
+ stats->tx_errs == -1 &&
|
|
|
25aafc |
+ stats->tx_drop == -1) {
|
|
|
25aafc |
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
25aafc |
_("Interface doesn't have any statistics"));
|
|
|
25aafc |
goto cleanup;
|
|
|
25aafc |
@@ -399,7 +436,7 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname,
|
|
|
25aafc |
ret = 0;
|
|
|
25aafc |
|
|
|
25aafc |
cleanup:
|
|
|
25aafc |
- VIR_FREE(output);
|
|
|
25aafc |
+ virJSONValueFree(jsonStats);
|
|
|
25aafc |
virCommandFree(cmd);
|
|
|
25aafc |
return ret;
|
|
|
25aafc |
}
|
|
|
25aafc |
--
|
|
|
25aafc |
2.23.0
|
|
|
25aafc |
|