On Tue, Apr 14, 2026 at 1:04 PM Takeru Hayasaka <[email protected]>
wrote:

> Previously fdb/show required exactly one bridge argument.  This
> change allows specifying multiple bridge names in a single call,
> reducing the number of unixctl round-trips for clients that need
> to poll FDB entries across many bridges (e.g. EVPN agents managing
> multiple VNIs).
>
> For text output, each bridge's output is prefixed with a
> "bridge <name>" header line when multiple bridges are specified.
> Single-bridge output remains unchanged for backward compatibility.
>
> For JSON output, multiple bridges produce an array of objects
> with "bridge" and "entries" keys.  Single-bridge output remains
> a flat array of FDB entries.
>
> Signed-off-by: Takeru Hayasaka <[email protected]>
> ---
>  NEWS                   |  5 +++-
>  ofproto/ofproto-dpif.c | 57 ++++++++++++++++++++++++++++++++++--------
>  tests/ofproto-dpif.at  | 32 ++++++++++++++++++++++++
>  3 files changed, 82 insertions(+), 12 deletions(-)
>
> diff --git a/NEWS b/NEWS
> index 1a3044cbfb2f..88d3ac7dad97 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -3,7 +3,10 @@ Post-v3.7.0
>     - Userspace datapath:
>       * ARP/ND lookups for native tunnel are now rate limited. The holdout
>         timer can be configured with 'tnl/neigh/retrans_time'.
> -
> +   - ovs-appctl:
> +     * "fdb/show" now accepts multiple bridge names in a single call,
> +       reducing the number of unixctl round-trips for clients that poll
> +       FDB entries across many bridges.
>
>  v3.7.0 - 16 Feb 2026
>  --------------------
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index a02afe8ef335..ff3fe2cf9ee5 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -6242,25 +6242,60 @@ done_unlock:
>  }
>
>  static void
> -ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
> -                          const char *argv[] OVS_UNUSED, void *aux
> OVS_UNUSED)
> +ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc,
> +                          const char *argv[], void *aux OVS_UNUSED)
>  {
> -    const struct ofproto_dpif *ofproto =
> ofproto_dpif_lookup_by_name(argv[1]);
> +    bool multi = argc > 2;
>
> -    if (!ofproto) {
> -        unixctl_command_reply_error(conn, "no such bridge");
> -        return;
> +    /* Validate all bridge names up front. */
> +    for (int i = 1; i < argc; i++) {
> +        if (!ofproto_dpif_lookup_by_name(argv[i])) {
> +            unixctl_command_reply_error(conn, "no such bridge");
> +            return;
> +        }
>      }
>
>      if (unixctl_command_get_output_format(conn) ==
> UNIXCTL_OUTPUT_FMT_JSON) {
> -        struct json *fdb_entries;
> +        struct json **bridge_entries = xmalloc((argc - 1)
> +                                               * sizeof *bridge_entries);
> +
> +        for (int i = 1; i < argc; i++) {
> +            const struct ofproto_dpif *ofproto =
> +                ofproto_dpif_lookup_by_name(argv[i]);
> +            struct json *fdb_entries;
> +
> +            ofproto_unixctl_fdb_show_json(ofproto, &fdb_entries);
> +            if (multi) {
> +                struct json *obj = json_object_create();
>
> -        ofproto_unixctl_fdb_show_json(ofproto, &fdb_entries);
> -        unixctl_command_reply_json(conn, fdb_entries);
> +                json_object_put_string(obj, "bridge", argv[i]);
> +                json_object_put(obj, "entries", fdb_entries);
>

Why not just add the bridge name in ofproto_unixctl_fdb_show_json? It would
simplify this patch and also might simplify parsing of the output.


> +                bridge_entries[i - 1] = obj;
> +            } else {
> +                bridge_entries[i - 1] = fdb_entries;
> +            }
> +        }
> +
> +        if (multi) {
> +            unixctl_command_reply_json(
> +                conn, json_array_create(bridge_entries, argc - 1));
> +        } else {
> +            unixctl_command_reply_json(conn, bridge_entries[0]);
> +            free(bridge_entries);
> +        }
>      } else {
>          struct ds ds = DS_EMPTY_INITIALIZER;
>
> -        ofproto_unixctl_fdb_show_text(ofproto, &ds);
> +        for (int i = 1; i < argc; i++) {
> +            const struct ofproto_dpif *ofproto =
> +                ofproto_dpif_lookup_by_name(argv[i]);
> +
> +            if (multi) {
>

Why not just always output the bridge name? It would be more consistent and
could move the change to ofproto_unixctl_fdb_show_text. Both of these
suggested changes moves the output formatting into a single function.

Cheers,
M



> +                ds_put_format(&ds, "bridge %s\n", argv[i]);
> +            }
> +            ofproto_unixctl_fdb_show_text(ofproto, &ds);
> +        }
> +
>          unixctl_command_reply(conn, ds_cstr(&ds));
>          ds_destroy(&ds);
>      }
> @@ -7131,7 +7166,7 @@ ofproto_unixctl_init(void)
>                               ofproto_unixctl_fdb_delete, NULL);
>      unixctl_command_register("fdb/flush", "[bridge]", 0, 1,
>                               ofproto_unixctl_fdb_flush, NULL);
> -    unixctl_command_register("fdb/show", "bridge", 1, 1,
> +    unixctl_command_register("fdb/show", "bridge [bridge2] ...", 1,
> INT_MAX,
>                               ofproto_unixctl_fdb_show, NULL);
>      unixctl_command_register("fdb/stats-clear", "[bridge]", 0, 1,
>                               ofproto_unixctl_fdb_stats_clear, NULL);
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index 39e43d376849..3d8c5fa1e2f4 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -7639,6 +7639,38 @@ AT_CHECK_UNQUOTED([ovs-appctl fdb/show br1 | sed
> 's/[[0-9]]\{1,\}$/?/'], [0], [d
>      5     0  50:54:00:00:00:07    ?
>  ])
>
> +# Test fdb/show with multiple bridges.
> +AT_CHECK_UNQUOTED([ovs-appctl fdb/show br0 br1 | sed '/^
> /s/[[0-9]]\{1,\}$/?/'], [0], [dnl
> +bridge br0
> + port  VLAN  MAC                Age
> +    2     0  50:54:00:00:00:05    ?
> +bridge br1
> + port  VLAN  MAC                Age
> +    5     0  50:54:00:00:00:07    ?
> +])
> +
> +dnl Check json output with multiple bridges.
> +AT_CHECK([ovs-appctl --format json --pretty fdb/show br0 br1 \
> +          | sed 's/"age": [[0-9]]*/"age": ?/g'], [0], [dnl
> +[[
> +  {
> +    "bridge": "br0",
> +    "entries": [
> +      {
> +        "age": ?,
> +        "mac": "50:54:00:00:00:05",
> +        "port": 2,
> +        "vlan": 0}]},
> +  {
> +    "bridge": "br1",
> +    "entries": [
> +      {
> +        "age": ?,
> +        "mac": "50:54:00:00:00:07",
> +        "port": 5,
> +        "vlan": 0}]}]]
> +])
> +
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
>
> --
> 2.43.0
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to