On 6/18/25 12:08 PM, Mairtin O'Loingsigh via dev wrote:
> Add support for using ovn-nbctl to list ports in a port group
>
> pg-get-ports: Get logical switch ports of a port group
>
> Reported-at: https://issues.redhat.com/browse/FDP-1463
> Signed-off-by: Mairtin O'Loingsigh <[email protected]>
> ---
Hi Mairtin,
Thanks for the patch! To me it looks correct from a functional
perspective. I left a bunch of minor comments below though.
> tests/ovn-nbctl.at | 10 +++++++-
> utilities/ovn-nbctl.c | 56 +++++++++++++++++++++++++++++++++++++++++++
Nit: we probably need to add a NEWS entry mentioning this new command.
Please also update the ovn-nbctl man page (ovn-nbctl.8.xml) and document
this new get command.
> 2 files changed, 65 insertions(+), 1 deletion(-)
>
> diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at
> index 447a0666f..b2f0b7df8 100644
> --- a/tests/ovn-nbctl.at
> +++ b/tests/ovn-nbctl.at
> @@ -2798,15 +2798,23 @@ pg1
> AT_CHECK_UNQUOTED([ovn-nbctl --bare --columns=ports list port_group pg1],
> [0], [dnl
> $SW1P1
> ])
> +AT_CHECK([ovn-nbctl pg-get-ports pg1],[0], [dnl
> +sw1-p1
> +])
>
> AT_CHECK([ovn-nbctl pg-set-ports pg1 sw1-p2], [0], [ignore])
> AT_CHECK_UNQUOTED([ovn-nbctl --bare --columns=ports list port_group pg1],
> [0], [dnl
> $SW1P2
> ])
> +AT_CHECK([ovn-nbctl pg-get-ports pg1],[0], [dnl
> +sw1-p2
> +])
>
> AT_CHECK([ovn-nbctl pg-del pg1], [0], [ignore])
> AT_CHECK([ovn-nbctl list port_group], [0], [])
> -])
> +AT_CHECK([ovn-nbctl pg-get-ports pg1], [1], [],
> + [ovn-nbctl: pg1: port group name not found
> +])])
Thanks for adding tests! But, for completeness, can we also add a test
that configures port groups with more than one port in them? That'd
also test the sorting part.
> dnl ---------------------------------------------------------------------
>
> OVN_NBCTL_TEST([ovn_nbctl_fwd_groups], [fwd groups], [
> diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
> index 33e789523..b3c9b89fb 100644
> --- a/utilities/ovn-nbctl.c
> +++ b/utilities/ovn-nbctl.c
> @@ -483,6 +483,7 @@ Port group commands:\n\
> pg-add PG [PORTS] Create port group PG with optional PORTS\n\
> pg-set-ports PG PORTS Set PORTS on port group PG\n\
> pg-del PG Delete port group PG\n\
> + pg-get-ports PG List port group PG\n\
Maybe "Get PORTS on port group PG" is slightly more accurate?
> HA chassis group commands:\n\
> ha-chassis-group-add GRP Create an HA chassis group GRP\n\
> ha-chassis-group-del GRP Delete the HA chassis group GRP\n\
> @@ -7489,6 +7490,59 @@ cmd_pg_del(struct ctl_context *ctx)
> nbrec_port_group_delete(pg);
> }
>
> +static void
> +cmd_pre_pg_get_ports(struct ctl_context *ctx)
Nit: This is identical to cmd_pre_pg_set_ports() and given that I think
we always want to "get" back exactly the same information we can "set"
it might make sense to just rename it to cmd_pre_pg_set_get_ports() and
avoid duplicating the code.
> +{
> + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_switch_port_col_name);
> + ovsdb_idl_add_column(ctx->idl, &nbrec_port_group_col_name);
> + ovsdb_idl_add_column(ctx->idl, &nbrec_port_group_col_ports);
> +}
> +
> +static int
> +port_name_cmp(const void *s1_, const void *s2_)
> +{
> + const char *s1 = *(char **) s1_, *s2 = *(char **) s2_;
I think I'd rewrite this as:
const char *s1 = *(const char **) s1_;
const char *s2 = *(const char **) s2_;
> + return strcmp(s1, s2);
> +}
> +
> +static void
> +cmd_pg_get_ports(struct ctl_context *ctx)
> +{
> + const struct nbrec_port_group *pg;
> + struct nbrec_logical_switch_port **ports;
> + size_t i;
> + char **port_names;
> + char *error;
> +
> + error = pg_by_name_or_uuid(ctx, ctx->argv[1], true, &pg);
In this case I think we'd prefer to define the variable here directly
(as close to where it's used), i.e.:
char *error = pg_by_name_or_uuid(...);
> + if (error) {
> + ctx->error = error;
> + return;
> + }
> +
> + ports = pg->ports;
> + if (pg->n_ports == 0) {
> + return;
> + }
> +
> + port_names = xmalloc(sizeof(char *) * pg->n_ports);
Per our coding guidelines this should be "sizeof *port_names":
https://github.com/ovn-org/ovn/blob/main/Documentation/internals/contributing/coding-style.rst#expressions
> + for (i = 0; i < pg->n_ports; i++) {
> + port_names[i] = ports[i]->name;
I'd just use pg->ports here instead of having the new local 'ports'.
> + }
> +
> + qsort(port_names, pg->n_ports, sizeof(char *), port_name_cmp);
Same here, "sizeof *port_names".
> + ds_put_format(&ctx->output, "%s", port_names[0]);
> + for (i = 1; i < pg->n_ports; i++) {
> + ds_put_format(&ctx->output, " %s", port_names[i]);
> + }
> +
'i' is always > 0 here, isn't it?
Which means we can just always limit the scope of the 'i' variable to
the loop it's used in. That is we can do this in both loops above:
for (size_t i = ...)
> + if (i > 0) {
> + ds_put_cstr(&ctx->output, "\n");
> + }
> +
> + free(port_names);
> +}
> +
> static const struct nbrec_ha_chassis_group*
> ha_chassis_group_by_name_or_uuid(struct ctl_context *ctx, const char *id,
> bool must_exist)
> @@ -8420,6 +8474,8 @@ static const struct ctl_command_syntax nbctl_commands[]
> = {
> {"pg-set-ports", 2, INT_MAX, "", cmd_pre_pg_set_ports, cmd_pg_set_ports,
> NULL, "", RW },
> {"pg-del", 1, 1, "", cmd_pre_pg_del, cmd_pg_del, NULL, "", RW },
> + {"pg-get-ports", 1, 1, "", cmd_pre_pg_get_ports, cmd_pg_get_ports,
"ovn-nbctl pg-get-ports" expects exactly one argument. The third field
of the 'struct ctl_command_syntax' structure is:
/* Names that roughly describe the arguments that the command
* uses. These should be similar to the names displayed in the
* man page or in the help output. */
const char *arguments;
We should probably change this to:
{ "pg-get-ports", 1, 1, "", "PORT_GROUP", ...
> + NULL, "", RO },
>
> /* HA chassis group commands. */
> {"ha-chassis-group-add", 1, 1, "[CHASSIS GROUP]",
Regards,
Dumitru
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev