When --format json is passed to ovs-appctl, upcall/show returns a JSON
array containing one object per udpif instance.  Each object includes
flow counts, dump duration, UFID support flag, and a revalidator array.
The offloaded_flows field is always present (even when zero) to provide
a consistent schema for consumers.

Example output:
  [{"dump_duration_ms":1,"flows_avg":0,"flows_current":0,
    "flows_limit":10000,"flows_max":0,"name":"ovs-system",
    "offloaded_flows":0,"revalidators":[{"id":4,"keys":0}],
    "ufid_enabled":true}]

Signed-off-by: Timothy Redaelli <[email protected]>
---
 ofproto/ofproto-dpif-upcall.c | 123 ++++++++++++++++++++++++----------
 tests/ofproto-dpif.at         |   5 ++
 2 files changed, 94 insertions(+), 34 deletions(-)

diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 8e4897202..c99bf4b69 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -26,6 +26,7 @@
 #include "dpif.h"
 #include "dpif-offload.h"
 #include "openvswitch/dynamic-string.h"
+#include "openvswitch/json.h"
 #include "fail-open.h"
 #include "guarded-list.h"
 #include "latch.h"
@@ -3164,49 +3165,103 @@ static void
 upcall_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
                     const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
 {
-    struct ds ds = DS_EMPTY_INITIALIZER;
-    uint64_t n_offloaded_flows;
     struct udpif *udpif;
 
-    LIST_FOR_EACH (udpif, list_node, &all_udpifs) {
-        unsigned int flow_limit;
-        bool ufid_enabled;
-        size_t i;
+    if (unixctl_command_get_output_format(conn) == UNIXCTL_OUTPUT_FMT_JSON) {
+        struct json *json_udpifs = json_array_create_empty();
 
-        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)"
-            " (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",
-                          n_offloaded_flows);
-        }
-        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");
-        } else {
-            ds_put_format(&ds, "false\n");
+        LIST_FOR_EACH (udpif, list_node, &all_udpifs) {
+            struct json *json_udpif = json_object_create();
+            struct json *json_revalidators = json_array_create_empty();
+            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_string(json_udpif, "name", dpif_name(udpif->dpif));
+            json_object_put(json_udpif, "flows_current",
+                            json_integer_create(udpif_get_n_flows(udpif)));
+            json_object_put(json_udpif, "flows_avg",
+                            json_integer_create(udpif->avg_n_flows));
+            json_object_put(json_udpif, "flows_max",
+                            json_integer_create(udpif->max_n_flows));
+            json_object_put(json_udpif, "flows_limit",
+                            json_integer_create(flow_limit));
+            json_object_put(json_udpif, "offloaded_flows",
+                            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, "ufid_enabled",
+                            json_boolean_create(ufid_enabled));
+
+            for (i = 0; i < udpif->n_revalidators; i++) {
+                struct revalidator *revalidator = &udpif->revalidators[i];
+                struct json *json_rv = json_object_create();
+                int j, elements = 0;
+
+                for (j = i; j < N_UMAPS; j += udpif->n_revalidators) {
+                    elements += cmap_count(&udpif->ukeys[j].cmap);
+                }
+                json_object_put(json_rv, "id",
+                                json_integer_create(revalidator->id));
+                json_object_put(json_rv, "keys",
+                                json_integer_create(elements));
+                json_array_add(json_revalidators, json_rv);
+            }
+            json_object_put(json_udpif, "revalidators", json_revalidators);
+            json_array_add(json_udpifs, json_udpif);
         }
-        ds_put_char(&ds, '\n');
+        unixctl_command_reply_json(conn, json_udpifs);
+    } else {
+        struct ds ds = DS_EMPTY_INITIALIZER;
+        uint64_t n_offloaded_flows;
 
-        for (i = 0; i < udpif->n_revalidators; i++) {
-            struct revalidator *revalidator = &udpif->revalidators[i];
-            int j, elements = 0;
+        LIST_FOR_EACH (udpif, list_node, &all_udpifs) {
+            unsigned int flow_limit;
+            bool ufid_enabled;
+            size_t i;
 
-            for (j = i; j < N_UMAPS; j += udpif->n_revalidators) {
-                elements += cmap_count(&udpif->ukeys[j].cmap);
+            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)"
+                " (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",
+                              n_offloaded_flows);
+            }
+            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");
+            } else {
+                ds_put_format(&ds, "false\n");
+            }
+            ds_put_char(&ds, '\n');
+
+            for (i = 0; i < udpif->n_revalidators; i++) {
+                struct revalidator *revalidator = &udpif->revalidators[i];
+                int j, elements = 0;
+
+                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);
+        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 9dfdfe29b..911609ed5 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -13617,6 +13617,11 @@ dnl Make sure the ukey exists.
 AT_CHECK([ovs-appctl upcall/show | grep '(keys' | awk '{print $3}' | \
             grep -q '1)'], [0])
 
+dnl Check upcall/show JSON output.
+AT_CHECK([ovs-appctl --format json upcall/show | dnl
+          grep '"name"' | grep '"flows_limit"' | dnl
+          grep '"ufid_enabled"' | grep '"revalidators"'], [0], [ignore])
+
 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.53.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to