When --format json is passed to ovs-appctl, upcall/show returns a JSON
object keyed by datapath name. Each entry contains a "flows" sub-object
(with "average", "current", "limit", "maximum", and "offloaded" counts),
"dump-duration-ms", "ufid-enabled", and a "revalidators" object indexed
by revalidator ID.
The implementation is split into separate text and JSON helper functions.
Example output:
{"ovs-system": {"dump-duration-ms": 1,
"flows": {"average": 0, "current": 0,
"limit": 10000, "maximum": 0,
"offloaded": 0},
"revalidators": {"4": {"keys": 0}},
"ufid-enabled": true}}
Signed-off-by: Timothy Redaelli <[email protected]>
---
NEWS | 1 +
ofproto/ofproto-dpif-upcall.c | 95 +++++++++++++++++++++++++++++------
tests/ofproto-dpif.at | 49 +++++++++++++++++-
3 files changed, 130 insertions(+), 15 deletions(-)
diff --git a/NEWS b/NEWS
index eb5e84d6f..045cc0d6f 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ Post-v4.0.0
--------------------
- ovs-appctl:
* Added JSON output support (--format json) for 'fdb/stats-show'.
+ * Added JSON output support (--format json) for 'upcall/show'.
v4.0.0 - xx xxx xxxx
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 8e4897202..b3b80c8f4 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -28,6 +28,7 @@
#include "openvswitch/dynamic-string.h"
#include "fail-open.h"
#include "guarded-list.h"
+#include "openvswitch/json.h"
#include "latch.h"
#include "openvswitch/list.h"
#include "netlink.h"
@@ -3160,11 +3161,65 @@ dp_purge_cb(void *aux, unsigned pmd_id)
udpif_resume_revalidators(udpif);
}
+static struct json *
+upcall_unixctl_show_json(void)
+{
+ struct json *json_udpifs = json_object_create();
+ struct udpif *udpif;
+
+ LIST_FOR_EACH (udpif, list_node, &all_udpifs) {
+ struct json *json_revalidators = json_object_create();
+ struct json *json_flows = json_object_create();
+ struct json *json_udpif = json_object_create();
+ uint64_t n_offloaded_flows;
+ unsigned int flow_limit;
+ bool ufid_enabled;
+ size_t i;
+
+ atomic_read_relaxed(&udpif->flow_limit, &flow_limit);
+ ufid_enabled = udpif_use_ufid(udpif);
+ n_offloaded_flows = dpif_offload_flow_count(udpif->dpif);
+
+ json_object_put(json_flows, "average",
+ json_integer_create(udpif->avg_n_flows));
+ json_object_put(json_flows, "current",
+ json_integer_create(udpif_get_n_flows(udpif)));
+ json_object_put(json_flows, "limit",
+ json_integer_create(flow_limit));
+ json_object_put(json_flows, "maximum",
+ json_integer_create(udpif->max_n_flows));
+ json_object_put(json_flows, "offloaded",
+ json_integer_create(n_offloaded_flows));
+ json_object_put(json_udpif, "dump-duration-ms",
+ json_integer_create(udpif->dump_duration));
+ json_object_put(json_udpif, "flows", json_flows);
+
+ for (i = 0; i < udpif->n_revalidators; i++) {
+ struct revalidator *revalidator = &udpif->revalidators[i];
+ struct json *json_rv;
+ int j, elements = 0;
+ char *key;
+
+ json_rv = json_object_create();
+ key = xasprintf("%u", revalidator->id);
+ for (j = i; j < N_UMAPS; j += udpif->n_revalidators) {
+ elements += cmap_count(&udpif->ukeys[j].cmap);
+ }
+ json_object_put(json_rv, "keys", json_integer_create(elements));
+ json_object_put_nocopy(json_revalidators, key, json_rv);
+ }
+ json_object_put(json_udpif, "revalidators", json_revalidators);
+ json_object_put(json_udpif, "ufid-enabled",
+ json_boolean_create(ufid_enabled));
+
+ json_object_put(json_udpifs, dpif_name(udpif->dpif), json_udpif);
+ }
+ return json_udpifs;
+}
+
static void
-upcall_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
- const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
+upcall_unixctl_show_text(struct ds *ds)
{
- struct ds ds = DS_EMPTY_INITIALIZER;
uint64_t n_offloaded_flows;
struct udpif *udpif;
@@ -3176,23 +3231,23 @@ upcall_unixctl_show(struct unixctl_conn *conn, int argc
OVS_UNUSED,
atomic_read_relaxed(&udpif->flow_limit, &flow_limit);
ufid_enabled = udpif_use_ufid(udpif);
- ds_put_format(&ds, "%s:\n", dpif_name(udpif->dpif));
- ds_put_format(&ds, " flows : (current %lu)"
+ ds_put_format(ds, "%s:\n", dpif_name(udpif->dpif));
+ ds_put_format(ds, " flows : (current %lu)"
" (avg %u) (max %u) (limit %u)\n", udpif_get_n_flows(udpif),
udpif->avg_n_flows, udpif->max_n_flows, flow_limit);
n_offloaded_flows = dpif_offload_flow_count(udpif->dpif);
if (n_offloaded_flows) {
- ds_put_format(&ds, " offloaded flows : %"PRIu64"\n",
+ ds_put_format(ds, " offloaded flows : %"PRIu64"\n",
n_offloaded_flows);
}
- ds_put_format(&ds, " dump duration : %lldms\n", udpif->dump_duration);
- ds_put_format(&ds, " ufid enabled : ");
+ ds_put_format(ds, " dump duration : %lldms\n", udpif->dump_duration);
+ ds_put_format(ds, " ufid enabled : ");
if (ufid_enabled) {
- ds_put_format(&ds, "true\n");
+ ds_put_format(ds, "true\n");
} else {
- ds_put_format(&ds, "false\n");
+ ds_put_format(ds, "false\n");
}
- ds_put_char(&ds, '\n');
+ ds_put_char(ds, '\n');
for (i = 0; i < udpif->n_revalidators; i++) {
struct revalidator *revalidator = &udpif->revalidators[i];
@@ -3201,12 +3256,24 @@ upcall_unixctl_show(struct unixctl_conn *conn, int argc
OVS_UNUSED,
for (j = i; j < N_UMAPS; j += udpif->n_revalidators) {
elements += cmap_count(&udpif->ukeys[j].cmap);
}
- ds_put_format(&ds, " %u: (keys %d)\n", revalidator->id, elements);
+ ds_put_format(ds, " %u: (keys %d)\n", revalidator->id, elements);
}
}
+}
- unixctl_command_reply(conn, ds_cstr(&ds));
- ds_destroy(&ds);
+static void
+upcall_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
+{
+ if (unixctl_command_get_output_format(conn) == UNIXCTL_OUTPUT_FMT_JSON) {
+ unixctl_command_reply_json(conn, upcall_unixctl_show_json());
+ } else {
+ struct ds ds = DS_EMPTY_INITIALIZER;
+
+ upcall_unixctl_show_text(&ds);
+ unixctl_command_reply(conn, ds_cstr(&ds));
+ ds_destroy(&ds);
+ }
}
/* Disable using the megaflows.
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 207c61ad5..b7469bee2 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -13922,9 +13922,13 @@ AT_CLEANUP
AT_SETUP([ofproto-dpif - Cleanup missing datapath flows])
-OVS_VSWITCHD_START
+OVS_VSWITCHD_START([], [], [=override])
add_of_ports br0 1 2
+dnl Set to 1 revalidator thread early for deterministic output.
+AT_CHECK([ovs-vsctl set open_vswitch . other_config:n-revalidator-threads=1])
+OVS_WAIT_UNTIL([ovs-appctl upcall/show | grep -c '(keys' | grep -q '^1$'])
+
m4_define([ICMP_PKT], [m4_join([,],
[eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800)],
[ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=1,ttl=128,frag=no)],
@@ -13945,6 +13949,49 @@ dnl Make sure the ukey exists.
AT_CHECK([ovs-appctl upcall/show | grep '(keys' | awk '{print $3}' | \
grep -q '1)'], [0])
+dnl Add a second datapath to check the JSON output with multiple datapaths.
+AT_CHECK([ovs-vsctl add-br br1 -- set bridge br1 datapath-type=netdev])
+OVS_WAIT_UNTIL([test $(ovs-appctl upcall/show | grep -c '^[[a-z]]*@') = 2])
+
+dnl Check upcall/show JSON output has the expected structure.
+AT_CHECK([ovs-appctl --format json --pretty upcall/show | dnl
+ sed 's/"dump-duration-ms": [[0-9]][[0-9]]*/"dump-duration-ms":
<cleared>/g' | dnl
+ sed 's/"average": [[0-9]][[0-9]]*/"average": <cleared>/g' | dnl
+ sed 's/"current": [[0-9]][[0-9]]*/"current": <cleared>/g' | dnl
+ sed 's/"limit": [[0-9]][[0-9]]*/"limit": <cleared>/g' | dnl
+ sed 's/"maximum": [[0-9]][[0-9]]*/"maximum": <cleared>/g' | dnl
+ sed 's/"keys": [[0-9]][[0-9]]*/"keys": <cleared>/g' | dnl
+ sed 's/"[[0-9]][[0-9]]*": {/"<revalidator>": {/g'], [0], [dnl
+{
+ "dummy@ovs-dummy": {
+ "dump-duration-ms": <cleared>,
+ "flows": {
+ "average": <cleared>,
+ "current": <cleared>,
+ "limit": <cleared>,
+ "maximum": <cleared>,
+ "offloaded": 0},
+ "revalidators": {
+ "<revalidator>": {
+ "keys": <cleared>}},
+ "ufid-enabled": true},
+ "netdev@ovs-netdev": {
+ "dump-duration-ms": <cleared>,
+ "flows": {
+ "average": <cleared>,
+ "current": <cleared>,
+ "limit": <cleared>,
+ "maximum": <cleared>,
+ "offloaded": 0},
+ "revalidators": {
+ "<revalidator>": {
+ "keys": <cleared>}},
+ "ufid-enabled": true}}
+])
+
+AT_CHECK([ovs-vsctl del-br br1])
+OVS_WAIT_UNTIL([test $(ovs-appctl upcall/show | grep -c '^[[a-z]]*@') = 1])
+
dnl Delete all datapath flows, and make sure they are gone.
AT_CHECK([ovs-appctl dpctl/del-flows])
AT_CHECK([ovs-appctl dpctl/dump-flows --names ], [0], [])
--
2.55.0
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev