On 4/2/26 11:19 AM, Eelco Chaudron via dev wrote:
> 
> 
> On 13 Mar 2026, at 21:50, Timothy Redaelli via dev wrote:
> 
>> When --format json is passed to ovs-appctl, fdb/stats-show returns a
>> flat JSON object with the bridge name and all counters from the MAC
>> learning table rather than the existing text representation.
>>
>> Example output:
>>   {"bridge":"br0","current_entries":17,"max_entries":8192,
>>    "static_entries":17,"total_expired":0,"total_evicted":0,
>>    "total_learned":17,"total_moved":0}

General note for all patches in the set:

1. Don't use underscores in JSON output.  Always use dashes.

2. Not applicable to this patch, but in other patches, use full words
   whenever possible, i.e. s/pkts/packets/, except for some things
   like 'ms' for milliseconds, which are acceptable short names.
   There is no point in seving a little bit of space in JSON.

3. All of the patches need a NEW entry.

>>
>> Reported-at: https://issues.redhat.com/browse/FDP-2444
>> Signed-off-by: Timothy Redaelli <[email protected]>
> 
> Hi Timothy,
> 
> Thanks for the series. I have a few comments on this patch below.
> 
> Cheers,
> 
> 
> Eelco
> 
>> ---
>>  ofproto/ofproto-dpif.c | 52 +++++++++++++++++++++++++++++++-----------
>>  tests/ofproto-dpif.at  |  9 ++++++++
>>  2 files changed, 48 insertions(+), 13 deletions(-)
>>
>> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
>> index a02afe8ef..add77ca4c 100644
>> --- a/ofproto/ofproto-dpif.c
>> +++ b/ofproto/ofproto-dpif.c
>> @@ -6388,7 +6388,6 @@ static void
>>  ofproto_unixctl_fdb_stats_show(struct unixctl_conn *conn, int argc 
>> OVS_UNUSED,
>>                                 const char *argv[], void *aux OVS_UNUSED)
>>  {
>> -    struct ds ds = DS_EMPTY_INITIALIZER;
>>      const struct ofproto_dpif *ofproto;
>>      ofproto = ofproto_dpif_lookup_by_name(argv[1]);
>>      if (!ofproto) {
>> @@ -6396,27 +6395,54 @@ ofproto_unixctl_fdb_stats_show(struct unixctl_conn 
>> *conn, int argc OVS_UNUSED,
>>          return;
>>      }
>>
>> -    ds_put_format(&ds, "Statistics for bridge \"%s\":\n", argv[1]);
>>      ovs_rwlock_rdlock(&ofproto->ml->rwlock);
>> +    if (unixctl_command_get_output_format(conn) == UNIXCTL_OUTPUT_FMT_JSON) 
>> {
> 
> 
> The current output looks like this:
> 
> {
>   "bridge": "br0",
>   "current_entries": 17,
>   "max_entries": 8192,
>   "static_entries": 17,
>   "total_evicted": 0,
>   "total_expired": 0,
>   "total_learned": 18,
>   "total_moved": 0}
> 
> Where it should look something like this, this clearly shows the data is 
> related to br0:
> 
>   "br0": {
>     "current_entries": 17,
>     "max_entries": 8192,
>     "static_entries": 17,
>     "total_evicted": 0,
>     "total_expired": 0,
>     "total_learned": 18,
>     "total_moved": 0}}
> 
> 
> In addition can we split up the functions, rather than inlining it.
> It's cleaner this way. Here's a quick diff:
> 
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index add77ca4c..f62bff605 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -6385,68 +6385,87 @@ 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_text(const struct ofproto_dpif *ofproto,
> +                               struct ds *ds)
>  {
> -    const struct ofproto_dpif *ofproto;
> -    ofproto = ofproto_dpif_lookup_by_name(argv[1]);
> -    if (!ofproto) {
> -        unixctl_command_reply_error(conn, "no such bridge");
> -        return;
> -    }
> -
>      ovs_rwlock_rdlock(&ofproto->ml->rwlock);
> -    if (unixctl_command_get_output_format(conn) == UNIXCTL_OUTPUT_FMT_JSON) {
> -        struct json *json = json_object_create();
> -
> -        json_object_put_string(json, "bridge", argv[1]);
> -        json_object_put(json, "current_entries",
> -                        json_integer_create(
> -                            hmap_count(&ofproto->ml->table)));
> -        json_object_put(json, "max_entries",
> -                        json_integer_create(ofproto->ml->max_entries));
> -        json_object_put(json, "static_entries",
> -                        json_integer_create(ofproto->ml->static_entries));
> -        json_object_put(json, "total_learned",
> -                        json_integer_create(ofproto->ml->total_learned));
> -        json_object_put(json, "total_expired",
> -                        json_integer_create(ofproto->ml->total_expired));
> -        json_object_put(json, "total_evicted",
> -                        json_integer_create(ofproto->ml->total_evicted));
> -        json_object_put(json, "total_moved",
> -                        json_integer_create(ofproto->ml->total_moved));
> -
> -        ovs_rwlock_unlock(&ofproto->ml->rwlock);
> -        unixctl_command_reply_json(conn, json);
> -        return;
> -    }
> 
> -    struct ds ds = DS_EMPTY_INITIALIZER;
> -
> -    ds_put_format(&ds, "Statistics for bridge \"%s\":\n", argv[1]);
> -    ds_put_format(&ds, "  Current/maximum MAC entries in the table: %"
> +    ds_put_format(ds, "Statistics for bridge \"%s\":\n", ofproto->up.name);
> +    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 void
> +ofproto_unixctl_fdb_stats_json(const struct ofproto_dpif *ofproto,
> +                               struct json *fdb_stats)
> +{
> +
> +    struct json *json = json_object_create();
> +
> +    json_object_put(fdb_stats, ofproto->up.name, json);
> +
> +    ovs_rwlock_rdlock(&ofproto->ml->rwlock);
> +
> +    json_object_put(json, "current_entries",
> +                    json_integer_create(hmap_count(&ofproto->ml->table)));
> +    json_object_put(json, "max_entries",
> +                    json_integer_create(ofproto->ml->max_entries));
> +    json_object_put(json, "static_entries",
> +                    json_integer_create(ofproto->ml->static_entries));
> +    json_object_put(json, "total_learned",
> +                    json_integer_create(ofproto->ml->total_learned));
> +    json_object_put(json, "total_expired",
> +                    json_integer_create(ofproto->ml->total_expired));
> +    json_object_put(json, "total_evicted",
> +                    json_integer_create(ofproto->ml->total_evicted));
> +    json_object_put(json, "total_moved",
> +                    json_integer_create(ofproto->ml->total_moved));
> +
> +    ovs_rwlock_unlock(&ofproto->ml->rwlock);
> +}
> +
> +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 *fdb_stats = json_object_create();
> +
> +        ofproto_unixctl_fdb_stats_json(ofproto, fdb_stats);
> +        unixctl_command_reply_json(conn, fdb_stats);
> +    } else {
> +        struct ds ds = DS_EMPTY_INITIALIZER;
> +
> +        ofproto_unixctl_fdb_stats_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 9dfdfe29b..b66938212 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -8249,12 +8249,16 @@ AT_CHECK_UNQUOTED([ovs-appctl fdb/stats-show br0 | 
> grep static], [0], [dnl
>  ])
> 
>  dnl Check JSON output.
> -AT_CHECK([ovs-appctl --format json --pretty fdb/stats-show br0 | dnl
> -          grep '"bridge"\|entries'], [0], [dnl
> -  "bridge": "br0",
> -  "current_entries": 17,
> -  "max_entries": 8192,
> -  "static_entries": 17,
> +AT_CHECK([ovs-appctl --format json --pretty fdb/stats-show br0], [0], [dnl
> +{
> +  "br0": {
> +    "current_entries": 17,
> +    "max_entries": 8192,
> +    "static_entries": 17,
> +    "total_evicted": 0,
> +    "total_expired": 0,
> +    "total_learned": 18,
> +    "total_moved": 0}}
>  ])
> 
>  OVS_VSWITCHD_STOP
> 
>> +        struct json *json = json_object_create();
>> +
>> +        json_object_put_string(json, "bridge", argv[1]);
>> +        json_object_put(json, "current_entries",
>> +                        json_integer_create(
>> +                            hmap_count(&ofproto->ml->table)));
>> +        json_object_put(json, "max_entries",
>> +                        json_integer_create(ofproto->ml->max_entries));
>> +        json_object_put(json, "static_entries",
>> +                        json_integer_create(ofproto->ml->static_entries));
>> +        json_object_put(json, "total_learned",
>> +                        json_integer_create(ofproto->ml->total_learned));
>> +        json_object_put(json, "total_expired",
>> +                        json_integer_create(ofproto->ml->total_expired));
>> +        json_object_put(json, "total_evicted",
>> +                        json_integer_create(ofproto->ml->total_evicted));
>> +        json_object_put(json, "total_moved",
>> +                        json_integer_create(ofproto->ml->total_moved));
>> +
>> +        ovs_rwlock_unlock(&ofproto->ml->rwlock);
>> +        unixctl_command_reply_json(conn, json);
>> +        return;
>> +    }
>>
>> +    struct ds ds = DS_EMPTY_INITIALIZER;
>> +
>> +    ds_put_format(&ds, "Statistics for bridge \"%s\":\n", argv[1]);
>>      ds_put_format(&ds, "  Current/maximum MAC entries in the table: %"
>>                    PRIuSIZE"/%"PRIuSIZE"\n",
>> -                  hmap_count(&ofproto->ml->table), 
>> ofproto->ml->max_entries);
>> +                  hmap_count(&ofproto->ml->table),
>> +                  ofproto->ml->max_entries);
>>      ds_put_format(&ds,
>> -                  "  Current static MAC entries in the table : 
>> %"PRIuSIZE"\n",
>> -                  ofproto->ml->static_entries);
>> +                  "  Current static MAC entries in the table : %"
>> +                  PRIuSIZE"\n", ofproto->ml->static_entries);
>>      ds_put_format(&ds,
>> -                  "  Total number of learned MAC entries     : %"PRIu64"\n",
>> -                  ofproto->ml->total_learned);
>> +                  "  Total number of learned MAC entries     : %"
>> +                  PRIu64"\n", ofproto->ml->total_learned);
>>      ds_put_format(&ds,
>> -                  "  Total number of expired MAC entries     : %"PRIu64"\n",
>> -                  ofproto->ml->total_expired);
>> +                  "  Total number of expired MAC entries     : %"
>> +                  PRIu64"\n", ofproto->ml->total_expired);
>>      ds_put_format(&ds,
>> -                  "  Total number of evicted MAC entries     : %"PRIu64"\n",
>> -                  ofproto->ml->total_evicted);
>> +                  "  Total number of evicted MAC entries     : %"
>> +                  PRIu64"\n", ofproto->ml->total_evicted);
>>      ds_put_format(&ds,
>> -                  "  Total number of port moved MAC entries  : %"PRIu64"\n",
>> -                  ofproto->ml->total_moved);
>> +                  "  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));
>> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
>> index 39e43d376..9dfdfe29b 100644
>> --- a/tests/ofproto-dpif.at
>> +++ b/tests/ofproto-dpif.at
>> @@ -8248,6 +8248,15 @@ 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 | dnl
>> +          grep '"bridge"\|entries'], [0], [dnl
> 
> I would not re-format the output here, just use the raw output of the 
> --pretty option.
> 
> AT_CHECK([ovs-appctl --format json --pretty fdb/stats-show br0], [0], [dnl
> {
>   "br0": {
>     "current_entries": 17,
>     "max_entries": 8192,
>     "static_entries": 17,
>     "total_evicted": 0,
>     "total_expired": 0,
>     "total_learned": 18,
>     "total_moved": 0}}
> ])
> 
> Looking at the naming, I think static_entries should be renamed to 
> current_static_entries to make
> its meaning clearer. Thoughts?

Not sure about that particular point, but I'd suggest we group the stats
here into two separate blocks:

"br0": {
  "entries": {
    "current": 17,
    "max": 8192,
    "static": 17
  },
  "events": {
    "evicted": 0,
    "expired": 0,
    "learned": 18,
    "moved": 0
  }
}

WDYT?

> 
> 
> The unfiltered output and split of the show functions should be true for all 
> other patches also.
> 
>> +  "bridge": "br0",
>> +  "current_entries": 17,
>> +  "max_entries": 8192,
>> +  "static_entries": 17,
>> +])
>> +
>>  OVS_VSWITCHD_STOP
>>  AT_CLEANUP
>>
>> -- 
>> 2.53.0
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to