On 23/02/2025 9:54, Roi Dayan wrote:
> From: Dima Chumak <dchu...@nvidia.com>
>
> The 'fdb/show' command now supports machine-readable JSON output in
> addition to the plain-text output for humans. An example would be:
>
> ovs-appctl --format=json --pretty fdb/show br-phy
> [
> {
> "static": true,
> "mac": "e4:8c:07:08:00:02",
> "port": 2,
> "vlan": 0
> },
> {
> "age": 14,
> "mac": "e4:8c:07:08:00:03",
> "port": 3,
> "vlan": 0
> }
> ]
>
> Signed-off-by: Dima Chumak <dchu...@nvidia.com>
> Acked-by: Roi Dayan <r...@nvidia.com>
> ---
>
> Notes:
> v4
> - Make sure not to set more entries than allocated in json output.
> - Fix json output to have either boolean static or integer age and not
> mix the types.
>
> v3
> - Fix assert. No need to call json_destroy() after
> unixctl_command_reply_json() as it takes
> ownership of the allocated body.
>
> v2
> - Fix sparse check error.
> - Add case checking fdb/show json output.
>
> ofproto/ofproto-dpif.c | 90 ++++++++++++++++++++++++++++++++++--------
> tests/ofproto-dpif.at | 16 ++++++++
> 2 files changed, 90 insertions(+), 16 deletions(-)
>
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index bf43d5d4bc59..692c6508db0d 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -6151,20 +6151,12 @@ ofbundle_get_a_port(const struct ofbundle *bundle)
> }
>
> static void
> -ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
> - const char *argv[], void *aux OVS_UNUSED)
> +ofproto_unixctl_fdb_show_text(const struct ofproto_dpif *ofproto,
> + struct ds *ds)
> {
> - struct ds ds = DS_EMPTY_INITIALIZER;
> - const struct ofproto_dpif *ofproto;
> const struct mac_entry *e;
>
> - ofproto = ofproto_dpif_lookup_by_name(argv[1]);
> - if (!ofproto) {
> - unixctl_command_reply_error(conn, "no such bridge");
> - return;
> - }
> -
> - ds_put_cstr(&ds, " port VLAN MAC Age\n");
> + ds_put_cstr(ds, " port VLAN MAC Age\n");
> ovs_rwlock_rdlock(&ofproto->ml->rwlock);
> LIST_FOR_EACH (e, lru_node, &ofproto->ml->lrus) {
> struct ofbundle *bundle = mac_entry_get_port(ofproto->ml, e);
> @@ -6173,17 +6165,83 @@ ofproto_unixctl_fdb_show(struct unixctl_conn *conn,
> int argc OVS_UNUSED,
>
> ofputil_port_to_string(ofbundle_get_a_port(bundle)->up.ofp_port,
> NULL, name, sizeof name);
> - ds_put_format(&ds, "%5s %4d "ETH_ADDR_FMT" ",
> + ds_put_format(ds, "%5s %4d "ETH_ADDR_FMT" ",
> name, e->vlan, ETH_ADDR_ARGS(e->mac));
> if (MAC_ENTRY_AGE_STATIC_ENTRY == age) {
> - ds_put_format(&ds, "static\n");
> + ds_put_format(ds, "static\n");
> } else {
> - ds_put_format(&ds, "%3d\n", age);
> + ds_put_format(ds, "%3d\n", age);
> }
> }
> ovs_rwlock_unlock(&ofproto->ml->rwlock);
> - unixctl_command_reply(conn, ds_cstr(&ds));
> - ds_destroy(&ds);
> +}
> +
> +static void
> +ofproto_unixctl_fdb_show_json(const struct ofproto_dpif *ofproto,
> + struct json **fdb_entries)
> +{
> + size_t num_entries = hmap_count(&ofproto->ml->table);
> + struct json **json_entries = NULL;
> + const struct mac_entry *entry;
> + int i = 0;
> +
> + if (!num_entries) {
> + goto done;
> + }
> +
> + json_entries = xmalloc(num_entries * sizeof *json_entries);
> + ovs_rwlock_rdlock(&ofproto->ml->rwlock);
> + LIST_FOR_EACH (entry, lru_node, &ofproto->ml->lrus) {
> + struct ofbundle *bundle = mac_entry_get_port(ofproto->ml, entry);
> + struct json *json_entry = json_object_create();
> + int age = mac_entry_age(ofproto->ml, entry);
> + long long port;
> +
> + port = (OVS_FORCE long long)
> ofbundle_get_a_port(bundle)->up.ofp_port;
> + json_object_put(json_entry, "port", json_integer_create(port));
> + json_object_put(json_entry, "vlan",
> json_integer_create(entry->vlan));
> + json_object_put_format(json_entry, "mac", ETH_ADDR_FMT,
> + ETH_ADDR_ARGS(entry->mac));
> + if (MAC_ENTRY_AGE_STATIC_ENTRY == age) {
> + json_object_put_string(json_entry, "age", "static");
oops sorry forgot to remove the string when checked something. i'll send v5.
> + json_object_put(json_entry, "static", json_boolean_create(true));
> + } else {
> + json_object_put(json_entry, "age", json_integer_create(age));
> + }
> + json_entries[i++] = json_entry;
> +
> + if (i >= num_entries) {
> + break;
> + }
> + }
> + ovs_rwlock_unlock(&ofproto->ml->rwlock);
> +done:
> + *fdb_entries = json_array_create(json_entries, i);
> +}
> +
> +static void
> +ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
> + const char *argv[] OVS_UNUSED, void *aux
> OVS_UNUSED)
> +{
> + const struct ofproto_dpif *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_entries;
> +
> + ofproto_unixctl_fdb_show_json(ofproto, &fdb_entries);
> + unixctl_command_reply_json(conn, fdb_entries);
> + } else {
> + struct ds ds = DS_EMPTY_INITIALIZER;
> +
> + ofproto_unixctl_fdb_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 fa5f148b4c28..d184b05af90d 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -7100,6 +7100,22 @@ AT_CHECK_UNQUOTED([ovs-appctl fdb/show br0 | sed
> 's/[[0-9]]\{1,\}$/?/'], [0], [d
> 1 0 50:54:00:00:00:06 ?
> ])
>
> +dnl Check json output.
> +AT_CHECK([ovs-appctl --format json --pretty fdb/show br0 \
> + | sed 's/"age": [[0-9]]\+/"age": ?/g'], [0], [dnl
> +[[
> + {
> + "age": ?,
> + "mac": "50:54:00:00:00:05",
> + "port": 3,
> + "vlan": 0},
> + {
> + "age": ?,
> + "mac": "50:54:00:00:00:06",
> + "port": 1,
> + "vlan": 0}]]
> +])
> +
> # Trace a packet arrival that updates the first learned MAC entry.
> OFPROTO_TRACE(
> [ovs-dummy],
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev