diff mbox series

[ovs-dev,v3,24/33] controller: Support receiving routes per iface.

Message ID 496124a894dd6651830dfbfc19326f691fcbc33f.1732630355.git.felix.huettner@stackit.cloud
State Changes Requested
Headers show
Series OVN Fabric integration | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success

Commit Message

Felix Huettner Nov. 26, 2024, 2:38 p.m. UTC
Previously we just assumed that if a LR had multiple LRPs bound to the
local chassis that all routes where valid for all of these LRPs.
This commit handles a previous option in ovn-nb that allowes the user to
specify the interface name that a route needs to use to be acceptable
for a given LRP.
The users can then have a 1:1 relationship between LRPs and interfaces
to allow ovn-controller to determine which route belongs to which LRP.

Signed-off-by: Felix Huettner <felix.huettner@stackit.cloud>
---
v3: newly introduced

 controller/route-exchange-netlink.c |  1 +
 controller/route-exchange-netlink.h |  2 ++
 controller/route-exchange.c         | 23 ++++++++++++++++-------
 controller/route.c                  | 12 +++++++++---
 controller/route.h                  |  6 ++++--
 tests/system-ovn.at                 | 11 +++++++++++
 6 files changed, 43 insertions(+), 12 deletions(-)
diff mbox series

Patch

diff --git a/controller/route-exchange-netlink.c b/controller/route-exchange-netlink.c
index eb2adb6d6..a30ecaeba 100644
--- a/controller/route-exchange-netlink.c
+++ b/controller/route-exchange-netlink.c
@@ -221,6 +221,7 @@  handle_route_msg_delete_routes(const struct route_table_msg *msg, void *data)
             rr->addr = rd->rta_dst;
             rr->plen = rd->plen;
             rr->nexthop = rd->nexthops[i].rta_gw;
+            memcpy(rr->ifname, rd->nexthops[i].ifname, IFNAMSIZ);
         }
         return;
     }
diff --git a/controller/route-exchange-netlink.h b/controller/route-exchange-netlink.h
index 566b38fde..fca2429e6 100644
--- a/controller/route-exchange-netlink.h
+++ b/controller/route-exchange-netlink.h
@@ -18,6 +18,7 @@ 
 #include <stdint.h>
 #include "openvswitch/hmap.h"
 #include <netinet/in.h>
+#include <net/if.h>
 
 /* This value is arbitrary but currently unused.
  * See https://github.com/iproute2/iproute2/blob/main/etc/iproute2/rt_protos */
@@ -31,6 +32,7 @@  struct re_nl_received_route_node {
     struct in6_addr addr;
     unsigned int plen;
     struct in6_addr nexthop;
+    char ifname[IFNAMSIZ];
 };
 
 int re_nl_create_vrf(const char *ifname, uint32_t table_id);
diff --git a/controller/route-exchange.c b/controller/route-exchange.c
index 4929cccb1..cc4a1af03 100644
--- a/controller/route-exchange.c
+++ b/controller/route-exchange.c
@@ -27,6 +27,7 @@ 
 #include "route.h"
 #include "route-exchange.h"
 #include "route-exchange-netlink.h"
+#include "simap.h"
 
 
 VLOG_DEFINE_THIS_MODULE(route_exchange);
@@ -102,7 +103,7 @@  route_erase_entry(struct route_entry *route_e)
 static void
 sb_sync_learned_routes(const struct sbrec_datapath_binding *datapath,
                        const struct hmap *learned_routes,
-                       const struct sset *bound_ports,
+                       const struct smap *bound_ports,
                        struct ovsdb_idl_txn *ovnsb_idl_txn,
                        struct ovsdb_idl_index *sbrec_route_by_datapath)
 {
@@ -118,8 +119,9 @@  sb_sync_learned_routes(const struct sbrec_datapath_binding *datapath,
             continue;
         }
         /* If the port is not local we don't care about it.
-         * Some other ovn-controller will handle it. */
-        if (!sset_contains(bound_ports, sb_route->logical_port)) {
+         * Some other ovn-controller will handle it.
+         * We may not use smap_get since the value might be validly NULL. */
+        if (!smap_get_node(bound_ports, sb_route->logical_port)) {
             continue;
         }
         route_e = route_alloc_entry(&sync_routes,
@@ -138,16 +140,23 @@  sb_sync_learned_routes(const struct sbrec_datapath_binding *datapath,
                                                learned_route->plen);
         char *nexthop = normalize_v46(&learned_route->nexthop);
 
-        const char *logical_port;
-        SSET_FOR_EACH (logical_port, bound_ports) {
+        struct smap_node *port_node;
+        SMAP_FOR_EACH (port_node, bound_ports) {
+            /* The user specified an ifname, but we learned it on a different
+             * port. */
+            if (port_node->value && strcmp(port_node->value,
+                                           learned_route->ifname)) {
+                continue;
+            }
             route_e = route_lookup_or_add(&sync_routes,
                 datapath,
-                logical_port, ip_prefix, nexthop);
+                port_node->key, ip_prefix, nexthop);
             route_e->stale = false;
             if (!route_e->sb_route) {
                 sb_route = sbrec_route_insert(ovnsb_idl_txn);
                 sbrec_route_set_datapath(sb_route, datapath);
-                sbrec_route_set_logical_port(sb_route, logical_port);
+                sbrec_route_set_logical_port(sb_route,
+                                             port_node->key);
                 sbrec_route_set_ip_prefix(sb_route, ip_prefix);
                 sbrec_route_set_nexthop(sb_route, nexthop);
                 sbrec_route_set_type(sb_route, "receive");
diff --git a/controller/route.c b/controller/route.c
index 98618e46a..ad4e49eb1 100644
--- a/controller/route.c
+++ b/controller/route.c
@@ -75,7 +75,7 @@  advertise_datapath_cleanup(struct advertise_datapath_entry *ad)
         free(ar);
     }
     hmap_destroy(&ad->routes);
-    sset_destroy(&ad->bound_ports);
+    smap_destroy(&ad->bound_ports);
     free(ad);
 }
 
@@ -83,6 +83,8 @@  void
 route_run(struct route_ctx_in *r_ctx_in,
           struct route_ctx_out *r_ctx_out)
 {
+    tracked_datapaths_destroy(r_ctx_out->tracked_re_datapaths);
+
     const struct local_datapath *ld;
     HMAP_FOR_EACH (ld, hmap_node, r_ctx_in->local_datapaths) {
         if (!ld->n_peer_ports || ld->is_switch) {
@@ -94,7 +96,7 @@  route_run(struct route_ctx_in *r_ctx_in,
         ad->key = ld->datapath->tunnel_key;
         ad->db = ld->datapath;
         hmap_init(&ad->routes);
-        sset_init(&ad->bound_ports);
+        smap_init(&ad->bound_ports);
 
         /* This is a LR datapath, find LRPs with route exchange options
          * that are bound locally. */
@@ -114,8 +116,12 @@  route_run(struct route_ctx_in *r_ctx_in,
                                           "maintain-vrf", false);
             ad->use_netns |= smap_get_bool(&sb_crp->options,
                                        "use-netns", false);
+            char *ifname = nullable_xstrdup(
+                                    smap_get(&sb_crp->options,
+                                             "dynamic-routing-ifname"));
             relevant_datapath = true;
-            sset_add(&ad->bound_ports, local_peer->logical_port);
+            smap_add_nocopy(&ad->bound_ports,
+                            xstrdup(local_peer->logical_port), ifname);
         }
 
         if (!relevant_datapath) {
diff --git a/controller/route.h b/controller/route.h
index ca309c7be..74dd55543 100644
--- a/controller/route.h
+++ b/controller/route.h
@@ -19,6 +19,7 @@ 
 #include <netinet/in.h>
 #include "openvswitch/hmap.h"
 #include "sset.h"
+#include "smap.h"
 
 struct hmap;
 struct ovsdb_idl_index;
@@ -51,8 +52,9 @@  struct advertise_datapath_entry {
     bool use_netns;
     struct hmap routes;
     /* the name of the port bindings locally bound for this datapath and
-     * running route exchange logic. */
-    struct sset bound_ports;
+     * running route exchange logic.
+     * The key is the port name and the value is the ifname if set. */
+    struct smap bound_ports;
 };
 
 struct advertise_route_entry {
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index 1ad4248ce..9656e412b 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -14351,6 +14351,17 @@  AT_CHECK([ovn-sbctl --columns ip_prefix,nexthop,logical_port --bare find Route t
 internet-phys
 ])
 
+# by setting a learning interface filter we will now forget about this route
+check ovn-nbctl --wait=hv set Logical_Router_Port internet-phys \
+      options:dynamic-routing-ifname=thisdoesnotexist
+check_row_count Route 0 type=receive
+
+# chaning it to "lo" will allow us to learn the route again
+check ovn-nbctl --wait=hv set Logical_Router_Port internet-phys \
+      options:dynamic-routing-ifname=lo
+check_row_count Route 1 type=receive
+
+
 OVS_APP_EXIT_AND_WAIT([ovn-controller])
 
 as ovn-sb