diff mbox series

[ovs-dev,v2,27/32] controller: Cleanup routes on stop.

Message ID eb4345e333d918c53a3dc48fe6c9c40e4c59e6de.1730713432.git.felix.huettner@stackit.cloud
State Superseded
Headers show
Series OVN Fabric integration | expand

Checks

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

Commit Message

Felix Huettner Nov. 4, 2024, 11:04 a.m. UTC
When we stop ovn-controller without immediately restarting it we now
cleanup routes.
This allows the routing agents to stop advertising this chassis to the
fabric.

Signed-off-by: Felix Huettner <felix.huettner@stackit.cloud>
---
 controller/route-exchange-netlink.c | 50 +++++++++++++++++++++
 controller/route-exchange-netlink.h |  2 +
 controller/route-exchange.c         | 70 +++++++++++++++++++++++++++++
 3 files changed, 122 insertions(+)
diff mbox series

Patch

diff --git a/controller/route-exchange-netlink.c b/controller/route-exchange-netlink.c
index 284161144..832c62686 100644
--- a/controller/route-exchange-netlink.c
+++ b/controller/route-exchange-netlink.c
@@ -307,3 +307,53 @@  re_nl_sync_routes(uint32_t table_id,
     }
     free(netns);
 }
+
+static void
+handle_route_msg_delete_all_our_routes(const struct route_table_msg *msg,
+                                       void *data)
+{
+    const struct route_data *rd = &msg->rd;
+    struct route_msg_handle_data *handle_data = data;
+    int err;
+
+    /* This route is not from us, so not interesting. */
+    if (rd->rtm_protocol != RTPROT_OVN) {
+        return;
+    }
+
+    err = re_nl_delete_route(handle_data->netns,
+                             rd->rta_table_id, &rd->rta_dst,
+                             rd->plen, rd->rta_priority);
+    if (err) {
+        char addr_s[INET6_ADDRSTRLEN + 1];
+        VLOG_WARN_RL(&rl, "Delete route table_id=%"PRIu32" dst=%s plen=%d: %s",
+                     rd->rta_table_id,
+                     ipv6_string_mapped(
+                         addr_s, &rd->rta_dst) ? addr_s : "(invalid)",
+                     rd->plen,
+                     ovs_strerror(err));
+    }
+}
+
+void
+re_nl_cleanup_routes(uint32_t table_id, bool use_netns)
+{
+    char * netns = NULL;
+    if (use_netns) {
+        netns = re_nl_get_netns_name(table_id);
+        table_id = RT_TABLE_MAIN;
+    }
+
+    /* Remove routes from the system that are not in the host_routes hmap and
+     * remove entries from host_routes hmap that match routes already installed
+     * in the system. */
+    struct route_msg_handle_data data = {
+        .routes = NULL,
+        .learned_routes = NULL,
+        .netns = netns,
+    };
+    route_table_dump_one_table(netns, table_id,
+                               handle_route_msg_delete_all_our_routes,
+                               &data);
+    free(netns);
+}
diff --git a/controller/route-exchange-netlink.h b/controller/route-exchange-netlink.h
index 5d48cbfd7..f3059e5af 100644
--- a/controller/route-exchange-netlink.h
+++ b/controller/route-exchange-netlink.h
@@ -54,4 +54,6 @@  void re_nl_sync_routes(uint32_t table_id,
                        struct hmap *learned_routes,
                        bool use_netns);
 
+void re_nl_cleanup_routes(uint32_t table_id, bool use_netns);
+
 #endif /* route-exchange-netlink.h */
diff --git a/controller/route-exchange.c b/controller/route-exchange.c
index 12204e42a..2eeabb5ec 100644
--- a/controller/route-exchange.c
+++ b/controller/route-exchange.c
@@ -16,6 +16,7 @@ 
 
 #include <errno.h>
 #include <net/if.h>
+#include <stdbool.h>
 
 #include "openvswitch/vlog.h"
 
@@ -33,6 +34,14 @@ 
 VLOG_DEFINE_THIS_MODULE(route_exchange);
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
 
+struct maintained_route_table_entry {
+    struct hmap_node node;
+    uint32_t table_id;
+    bool is_netns;
+};
+
+static struct hmap _maintained_route_tables = HMAP_INITIALIZER(
+    &_maintained_route_tables);
 static struct sset _maintained_vrfs = SSET_INITIALIZER(&_maintained_vrfs);
 
 struct route_entry {
@@ -47,6 +56,39 @@  struct route_entry {
     bool stale;
 };
 
+static uint32_t
+maintained_route_table_hash(uint32_t table_id, bool is_netns)
+{
+    return hash_boolean(is_netns, hash_int(table_id, 0));
+}
+
+static bool
+maintained_route_table_contains(uint32_t table_id, bool is_netns)
+{
+    uint32_t hash = maintained_route_table_hash(table_id, is_netns);
+    struct maintained_route_table_entry *mrt;
+    HMAP_FOR_EACH_WITH_HASH (mrt, node, hash,
+                             &_maintained_route_tables) {
+        if (mrt->table_id == table_id && mrt->is_netns == is_netns) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static void
+maintained_route_table_add(uint32_t table_id, bool is_netns)
+{
+    if (maintained_route_table_contains(table_id, is_netns)) {
+        return;
+    }
+    uint32_t hash = maintained_route_table_hash(table_id, is_netns);
+    struct maintained_route_table_entry *mrt = xzalloc(sizeof(*mrt));
+    mrt->table_id = table_id;
+    mrt->is_netns = is_netns;
+    hmap_insert(&_maintained_route_tables, &mrt->node, hash);
+}
+
 static struct route_entry *
 route_alloc_entry(struct hmap *routes,
                   const struct sbrec_datapath_binding *sb_db,
@@ -174,6 +216,9 @@  route_exchange_run(struct route_exchange_ctx_in *r_ctx_in,
 {
     struct sset old_maintained_vrfs = SSET_INITIALIZER(&old_maintained_vrfs);
     sset_swap(&_maintained_vrfs, &old_maintained_vrfs);
+    struct hmap old_maintained_route_table = HMAP_INITIALIZER(
+        &old_maintained_route_table);
+    hmap_swap(&_maintained_route_tables, &old_maintained_route_table);
 
     const struct advertise_datapath_entry *ad;
     HMAP_FOR_EACH (ad, node, r_ctx_in->announce_routes) {
@@ -196,6 +241,8 @@  route_exchange_run(struct route_exchange_ctx_in *r_ctx_in,
             sset_add(&_maintained_vrfs, vrf_name);
         }
 
+        maintained_route_table_add(ad->key, ad->use_netns);
+
         re_nl_sync_routes(ad->key,
                           &ad->routes, &received_routes, ad->use_netns);
 
@@ -214,6 +261,17 @@  out:
         re_nl_received_routes_destroy(&received_routes);
     }
 
+    /* Remove routes in tables previousl maintained by us. */
+    struct maintained_route_table_entry *mrt;
+    HMAP_FOR_EACH_SAFE (mrt, node, &old_maintained_route_table) {
+        if (!maintained_route_table_contains(mrt->table_id, mrt->is_netns)) {
+            re_nl_cleanup_routes(mrt->table_id, mrt->is_netns);
+        }
+        hmap_remove(&old_maintained_route_table, &mrt->node);
+        free(mrt);
+    }
+    hmap_destroy(&old_maintained_route_table);
+
     /* Remove VRFs previously maintained by us not found in the above loop. */
     const char *vrf_name;
     SSET_FOR_EACH_SAFE (vrf_name, &old_maintained_vrfs) {
@@ -228,6 +286,11 @@  out:
 void
 route_exchange_cleanup(void)
 {
+    struct maintained_route_table_entry *mrt;
+    HMAP_FOR_EACH_SAFE (mrt, node, &_maintained_route_tables) {
+        re_nl_cleanup_routes(mrt->table_id, mrt->is_netns);
+    }
+
     const char *vrf_name;
     SSET_FOR_EACH_SAFE (vrf_name, &_maintained_vrfs) {
         re_nl_delete_vrf(vrf_name);
@@ -237,10 +300,17 @@  route_exchange_cleanup(void)
 void
 route_exchange_destroy(void)
 {
+    struct maintained_route_table_entry *mrt;
+    HMAP_FOR_EACH_SAFE (mrt, node, &_maintained_route_tables) {
+        hmap_remove(&_maintained_route_tables, &mrt->node);
+        free(mrt);
+    }
+
     const char *vrf_name;
     SSET_FOR_EACH_SAFE (vrf_name, &_maintained_vrfs) {
         sset_delete(&_maintained_vrfs, SSET_NODE_FROM_NAME(vrf_name));
     }
 
     sset_destroy(&_maintained_vrfs);
+    hmap_destroy(&_maintained_route_tables);
 }