When --format json is passed to ovs-appctl, fdb/stats-show returns a
JSON object keyed by bridge name.  Each bridge contains two sub-objects:
"entries" (with "current", "maximum", and "static" counts) and "events"
(with "evicted", "expired", "learned", and "moved" counters).

The output is keyed by bridge name even though the command accepts only
one bridge.  This matches fdb/show, dpif/show and dpif/offload/show,
which all use entity names as top-level keys, and the format does not
need to change if the command ever reports more than one bridge.

The implementation is split into separate text and JSON helper functions
to keep the main handler simple.

Example output:
  {"br0": {"entries": {"current": 17, "maximum": 8192, "static": 17},
           "events":  {"evicted": 0, "expired": 0,
                       "learned": 17, "moved": 0}}}

Reported-at: https://issues.redhat.com/browse/FDP-2444
Signed-off-by: Timothy Redaelli <[email protected]>
---
 NEWS                   |  2 +
 ofproto/ofproto-dpif.c | 85 ++++++++++++++++++++++++++++++++----------
 tests/ofproto-dpif.at  | 15 ++++++++
 3 files changed, 83 insertions(+), 19 deletions(-)

diff --git a/NEWS b/NEWS
index de1a030ad..0153fa0cb 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,7 @@
 Post-v4.0.0
 --------------------
+   - ovs-appctl:
+     * Added JSON output support (--format json) for 'fdb/stats-show'.
 
 
 v4.0.0 - 17 Aug 2026
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 443de8708..412554cdf 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -6438,42 +6438,89 @@ ofproto_unixctl_fdb_stats_clear(struct unixctl_conn 
*conn, int argc,
 }
 
 static void
-ofproto_unixctl_fdb_stats_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
-                               const char *argv[], void *aux OVS_UNUSED)
+ofproto_unixctl_fdb_stats_show_text(const struct ofproto_dpif *ofproto,
+                                    struct ds *ds)
 {
-    struct ds ds = DS_EMPTY_INITIALIZER;
-    const struct ofproto_dpif *ofproto;
-    ofproto = ofproto_dpif_lookup_by_name(argv[1]);
-    if (!ofproto) {
-        unixctl_command_reply_error(conn, "no such bridge");
-        return;
-    }
-
-    ds_put_format(&ds, "Statistics for bridge \"%s\":\n", argv[1]);
+    ds_put_format(ds, "Statistics for bridge \"%s\":\n", ofproto->up.name);
     ovs_rwlock_rdlock(&ofproto->ml->rwlock);
 
-    ds_put_format(&ds, "  Current/maximum MAC entries in the table: %"
+    ds_put_format(ds, "  Current/maximum MAC entries in the table: %"
                   PRIuSIZE"/%"PRIuSIZE"\n",
                   hmap_count(&ofproto->ml->table), ofproto->ml->max_entries);
-    ds_put_format(&ds,
+    ds_put_format(ds,
                   "  Current static MAC entries in the table : %"PRIuSIZE"\n",
                   ofproto->ml->static_entries);
-    ds_put_format(&ds,
+    ds_put_format(ds,
                   "  Total number of learned MAC entries     : %"PRIu64"\n",
                   ofproto->ml->total_learned);
-    ds_put_format(&ds,
+    ds_put_format(ds,
                   "  Total number of expired MAC entries     : %"PRIu64"\n",
                   ofproto->ml->total_expired);
-    ds_put_format(&ds,
+    ds_put_format(ds,
                   "  Total number of evicted MAC entries     : %"PRIu64"\n",
                   ofproto->ml->total_evicted);
-    ds_put_format(&ds,
+    ds_put_format(ds,
                   "  Total number of port moved MAC entries  : %"PRIu64"\n",
                   ofproto->ml->total_moved);
 
     ovs_rwlock_unlock(&ofproto->ml->rwlock);
-    unixctl_command_reply(conn, ds_cstr(&ds));
-    ds_destroy(&ds);
+}
+
+static struct json *
+ofproto_unixctl_fdb_stats_show_json(const struct ofproto_dpif *ofproto)
+{
+    struct json *entries = json_object_create();
+    struct json *events = json_object_create();
+    struct json *bridge = json_object_create();
+    struct json *json = json_object_create();
+
+    ovs_rwlock_rdlock(&ofproto->ml->rwlock);
+    json_object_put(entries, "current",
+                    json_integer_create(hmap_count(&ofproto->ml->table)));
+    json_object_put(entries, "maximum",
+                    json_integer_create(ofproto->ml->max_entries));
+    json_object_put(entries, "static",
+                    json_integer_create(ofproto->ml->static_entries));
+    json_object_put(bridge, "entries", entries);
+
+    json_object_put(events, "evicted",
+                    json_integer_create(ofproto->ml->total_evicted));
+    json_object_put(events, "expired",
+                    json_integer_create(ofproto->ml->total_expired));
+    json_object_put(events, "learned",
+                    json_integer_create(ofproto->ml->total_learned));
+    json_object_put(events, "moved",
+                    json_integer_create(ofproto->ml->total_moved));
+    json_object_put(bridge, "events", events);
+    ovs_rwlock_unlock(&ofproto->ml->rwlock);
+
+    json_object_put(json, ofproto->up.name, bridge);
+    return json;
+}
+
+static void
+ofproto_unixctl_fdb_stats_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                               const char *argv[], void *aux OVS_UNUSED)
+{
+    const struct ofproto_dpif *ofproto;
+
+    ofproto = ofproto_dpif_lookup_by_name(argv[1]);
+    if (!ofproto) {
+        unixctl_command_reply_error(conn, "no such bridge");
+        return;
+    }
+
+    if (unixctl_command_get_output_format(conn) == UNIXCTL_OUTPUT_FMT_JSON) {
+        struct json *json = ofproto_unixctl_fdb_stats_show_json(ofproto);
+
+        unixctl_command_reply_json(conn, json);
+    } else {
+        struct ds ds = DS_EMPTY_INITIALIZER;
+
+        ofproto_unixctl_fdb_stats_show_text(ofproto, &ds);
+        unixctl_command_reply(conn, ds_cstr(&ds));
+        ds_destroy(&ds);
+    }
 }
 
 static void
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index e50d77216..778f83a8c 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -8338,6 +8338,21 @@ AT_CHECK_UNQUOTED([ovs-appctl fdb/stats-show br0 | grep 
static], [0], [dnl
   Current static MAC entries in the table : 17
 ])
 
+dnl Check JSON output.
+AT_CHECK([ovs-appctl --format json --pretty fdb/stats-show br0], [0], [dnl
+{
+  "br0": {
+    "entries": {
+      "current": 17,
+      "maximum": 8192,
+      "static": 17},
+    "events": {
+      "evicted": 0,
+      "expired": 0,
+      "learned": 18,
+      "moved": 0}}}
+])
+
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
-- 
2.56.0

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

Reply via email to