@@ -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);
+}
@@ -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 */
@@ -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);
}
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(+)