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]>
---
 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)
+{
+    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,
-- 
2.54.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to