On Mon, Oct 19, 2026 at 2:25 PM Srikar Tati via dev
<[email protected]> wrote:
>
> From: Srikar Tati <[email protected]>
>
> Static routes choose the fields that their ECMP group hashes on with
> the "selection_fields" column. The following patches let learned
> routes and EVPN FDB entries take the same fields from a string option.
>
> Add ovn_ecmp_selection_fields_parse() to parse such an option with the
> fields that "selection_fields" accepts, and move the static route
> handling of tp_src and tp_dst to ovn_ecmp_selection_fields_add(), so
> that every user adds ip_proto in the same way.
>
> Assisted-by: Claude Opus 5.5, Claude Code
> Signed-off-by: Srikar Tati <[email protected]>
Hi Srikar,
Thanks for the patches. A few minor comments below.
Thanks
Numan
> ---
> lib/ovn-util.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++
> lib/ovn-util.h | 5 +++++
> northd/northd.c | 17 +++--------------
> 3 files changed, 59 insertions(+), 14 deletions(-)
>
> diff --git a/lib/ovn-util.c b/lib/ovn-util.c
> index eb1fa8a06..4ec648318 100644
> --- a/lib/ovn-util.c
> +++ b/lib/ovn-util.c
> @@ -1634,6 +1634,57 @@ ovn_is_valid_vni(int64_t vni)
> return vni >= 0 && (vni <= (1 << 24) - 1);
> }
>
> +/* Adds 'field' to the ECMP 'selection_fields'. If 'field' is tp_src or
> + * tp_dst, also adds ip_proto: the protocol specific port fields are only
> + * valid with a match on the protocol. */
> +void
> +ovn_ecmp_selection_fields_add(struct sset *selection_fields,
> + const char *field)
Since 'selection_fields' is an output param, let's make it the last param.
i.e change the signature to
void
ovn_ecmp_selection_fields_add(const char *field, struct sset *selection_fields)
> +{
> + if (!strcmp(field, "tp_src") || !strcmp(field, "tp_dst")) {
> + sset_add(selection_fields, "ip_proto");
> + }
> + sset_add(selection_fields, field);
> +}
> +
> +/* Parses 'fields_s', a comma separated list of the fields that the
> + * Logical_Router_Static_Route selection_fields column accepts, into
> + * 'selection_fields'. Returns false, and leaves 'selection_fields'
> + * empty, if 'fields_s' contains a field that is not supported. */
> +bool
> +ovn_ecmp_selection_fields_parse(const char *fields_s,
> + struct sset *selection_fields)
> +{
> + static const char *const supported[] = {
> + "eth_src", "eth_dst", "ip_proto", "ip_src", "ip_dst",
> + "ipv6_src", "ipv6_dst", "tp_src", "tp_dst",
> + };
> +
> + char *tokstr = xstrdup(fields_s);
> + char *save_ptr = NULL;
> + bool ok = true;
> + for (char *field = strtok_r(tokstr, ",", &save_ptr); field;
> + field = strtok_r(NULL, ",", &save_ptr)) {
> + size_t i;
> + for (i = 0; i < ARRAY_SIZE(supported); i++) {
> + if (!strcmp(field, supported[i])) {
> + break;
> + }
> + }
> + if (i == ARRAY_SIZE(supported)) {
> + ok = false;
> + break;
> + }
> + ovn_ecmp_selection_fields_add(selection_fields, field);
> + }
> + free(tokstr);
> +
> + if (!ok) {
> + sset_clear(selection_fields);
> + }
> + return ok;
> +}
> +
> struct sset *
> lrp_network_sset(const char **networks, int n_networks)
> {
> diff --git a/lib/ovn-util.h b/lib/ovn-util.h
> index 01d21d282..fc88bf6d6 100644
> --- a/lib/ovn-util.h
> +++ b/lib/ovn-util.h
> @@ -735,6 +735,11 @@ void ovn_debug_commands_register(void);
>
> bool ovn_is_valid_vni(int64_t vni);
>
> +void ovn_ecmp_selection_fields_add(struct sset *selection_fields,
> + const char *field);
> +bool ovn_ecmp_selection_fields_parse(const char *fields_s,
> + struct sset *selection_fields);
> +
> const struct sbrec_port_binding *lport_lookup_by_name(
> struct ovsdb_idl_index *sbrec_port_binding_by_name,
> const char *name);
> diff --git a/northd/northd.c b/northd/northd.c
> index 7c4cb5a62..824c90c89 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -13036,20 +13036,9 @@ parsed_routes_add_static(const struct ovn_datapath
> *od,
>
> struct sset ecmp_selection_fields =
> SSET_INITIALIZER(&ecmp_selection_fields);
> -
> - /* If tp_src or tp_dst is included in the selection_fields, implicitly
> - * include match on ip_proto. */
> - if (route->n_selection_fields) {
> - struct sset field_set = SSET_INITIALIZER(&field_set);
> - for (size_t i = 0; i < route->n_selection_fields; i++) {
> - char *field = route->selection_fields[i];
> - if (!strcmp(field, "tp_src") || !strcmp(field, "tp_dst")) {
> - sset_add(&field_set, "ip_proto");
> - }
> - sset_add(&field_set, field);
> - }
> - sset_clone(&ecmp_selection_fields, &field_set);
> - sset_destroy(&field_set);
> + for (size_t i = 0; i < route->n_selection_fields; i++) {
> + ovn_ecmp_selection_fields_add(&ecmp_selection_fields,
> + route->selection_fields[i]);
> }
>
> uint32_t route_table_id = get_route_table_id(route_tables,
> --
Just a small nit: I see that no one is using the util function
'ovn_ecmp_selection_fields_parse()' in this patch.
But it is used in the next patch. I'd suggest moving this function to
the next patch.
With my comments addressed:
Acked-by: Numan Siddique <[email protected]>
Numan
> 2.54.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