We are currently maintaining a state for _maintained_route_tables
hashmap and _maintained_vrfs sset between route_exchange_run()
consecutive runs. This approach does not take into account possible
netlink failures. As a result OVN and kernel state can be not aligned.
Fix the problem retrying the failed VRF or route update in the next
route_exchange_run() iteration.
Moreover report operation result in re_nl_sync_routes.

Fixes: faf4df563f1d ("controller: Announce routes via route-exchange.")
Fixes: b344a5341da8 ("controller: Cleanup routes on stop.")
Acked-By: Felix Huettner <felix.huettner@stackit.cloud>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianc...@redhat.com>
---
 controller/route-exchange-netlink.c | 18 ++++++++++++++++--
 controller/route-exchange-netlink.h |  8 ++++----
 controller/route-exchange-stub.c    |  3 ++-
 controller/route-exchange.c         | 27 +++++++++++++++++++++------
 controller/route-exchange.h         |  4 ++--
 5 files changed, 45 insertions(+), 15 deletions(-)

diff --git a/controller/route-exchange-netlink.c 
b/controller/route-exchange-netlink.c
index 83deb13e6..7ee0d0829 100644
--- a/controller/route-exchange-netlink.c
+++ b/controller/route-exchange-netlink.c
@@ -194,6 +194,7 @@ struct route_msg_handle_data {
     struct hmapx *routes_to_advertise;
     struct vector *learned_routes;
     const struct hmap *routes;
+    int ret;
 };
 
 static void
@@ -247,6 +248,9 @@ handle_route_msg(const struct route_table_msg *msg, void 
*data)
     }
     err = re_nl_delete_route(rd->rta_table_id, &rd->rta_dst,
                              rd->rtm_dst_len, rd->rta_priority);
+    /* Report return value and number of deleted routes to the caller. */
+    handle_data->ret |= err;
+
     if (err) {
         char addr_s[INET6_ADDRSTRLEN + 1];
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
@@ -259,13 +263,14 @@ handle_route_msg(const struct route_table_msg *msg, void 
*data)
     }
 }
 
-void
+int
 re_nl_sync_routes(uint32_t table_id, const struct hmap *routes,
                   struct vector *learned_routes,
                   const struct sbrec_datapath_binding *db)
 {
     struct hmapx routes_to_advertise = HMAPX_INITIALIZER(&routes_to_advertise);
     struct advertise_route_entry *ar;
+    int ret;
 
     HMAP_FOR_EACH (ar, node, routes) {
         hmapx_add(&routes_to_advertise, ar);
@@ -281,6 +286,7 @@ re_nl_sync_routes(uint32_t table_id, const struct hmap 
*routes,
         .db = db,
     };
     route_table_dump_one_table(table_id, handle_route_msg, &data);
+    ret = data.ret;
 
     /* Add any remaining routes in the routes_to_advertise hmapx to the
      * system routing table. */
@@ -298,12 +304,18 @@ re_nl_sync_routes(uint32_t table_id, const struct hmap 
*routes,
                              addr_s, &ar->addr) ? addr_s : "(invalid)",
                          ar->plen,
                          ovs_strerror(err));
+            if (err != EEXIST) {
+                ret = err;
+                break;
+            }
         }
     }
     hmapx_destroy(&routes_to_advertise);
+
+    return ret;
 }
 
-void
+int
 re_nl_cleanup_routes(uint32_t table_id)
 {
     /* Remove routes from the system that are not in the host_routes hmap and
@@ -314,4 +326,6 @@ re_nl_cleanup_routes(uint32_t table_id)
         .learned_routes = NULL,
     };
     route_table_dump_one_table(table_id, handle_route_msg, &data);
+
+    return data.ret;
 }
diff --git a/controller/route-exchange-netlink.h 
b/controller/route-exchange-netlink.h
index e37cfe711..e6142c1ff 100644
--- a/controller/route-exchange-netlink.h
+++ b/controller/route-exchange-netlink.h
@@ -51,10 +51,10 @@ int re_nl_delete_route(uint32_t table_id, const struct 
in6_addr *dst,
 
 void re_nl_dump(uint32_t table_id);
 
-void re_nl_sync_routes(uint32_t table_id, const struct hmap *routes,
-                       struct vector *learned_routes,
-                       const struct sbrec_datapath_binding *db);
+int re_nl_sync_routes(uint32_t table_id, const struct hmap *routes,
+                      struct vector *learned_routes,
+                      const struct sbrec_datapath_binding *db);
 
-void re_nl_cleanup_routes(uint32_t table_id);
+int re_nl_cleanup_routes(uint32_t table_id);
 
 #endif /* route-exchange-netlink.h */
diff --git a/controller/route-exchange-stub.c b/controller/route-exchange-stub.c
index 27827df1d..5dff0c0fb 100644
--- a/controller/route-exchange-stub.c
+++ b/controller/route-exchange-stub.c
@@ -20,10 +20,11 @@
 #include "openvswitch/compiler.h"
 #include "route-exchange.h"
 
-void
+int
 route_exchange_run(const struct route_exchange_ctx_in *r_ctx_in OVS_UNUSED,
                    struct route_exchange_ctx_out *r_ctx_out OVS_UNUSED)
 {
+    return 0;
 }
 
 void
diff --git a/controller/route-exchange.c b/controller/route-exchange.c
index 79a046f60..f5b0a2527 100644
--- a/controller/route-exchange.c
+++ b/controller/route-exchange.c
@@ -204,7 +204,7 @@ sb_sync_learned_routes(const struct vector *learned_routes,
     hmap_destroy(&sync_routes);
 }
 
-void
+int
 route_exchange_run(const struct route_exchange_ctx_in *r_ctx_in,
                    struct route_exchange_ctx_out *r_ctx_out)
 {
@@ -213,6 +213,7 @@ route_exchange_run(const struct route_exchange_ctx_in 
*r_ctx_in,
     struct hmap old_maintained_route_table =
         HMAP_INITIALIZER(&old_maintained_route_table);
     hmap_swap(&_maintained_route_tables, &old_maintained_route_table);
+    int error, ret = 0;
 
     const struct advertise_datapath_entry *ad;
     HMAP_FOR_EACH (ad, node, r_ctx_in->announce_routes) {
@@ -220,13 +221,14 @@ route_exchange_run(const struct route_exchange_ctx_in 
*r_ctx_in,
 
         if (ad->maintain_vrf) {
             if (!sset_contains(&old_maintained_vrfs, ad->vrf_name)) {
-                int error = re_nl_create_vrf(ad->vrf_name, table_id);
+                error = re_nl_create_vrf(ad->vrf_name, table_id);
                 if (error && error != EEXIST) {
                     VLOG_WARN_RL(&rl,
                                  "Unable to create VRF %s for datapath "
                                  "%"PRIi32": %s.",
                                  ad->vrf_name, table_id,
                                  ovs_strerror(error));
+                    ret = ret ? ret : error;
                     continue;
                 }
             }
@@ -243,8 +245,9 @@ route_exchange_run(const struct route_exchange_ctx_in 
*r_ctx_in,
         struct vector received_routes =
             VECTOR_EMPTY_INITIALIZER(struct re_nl_received_route_node);
 
-        re_nl_sync_routes(ad->db->tunnel_key, &ad->routes,
-                          &received_routes, ad->db);
+        error = re_nl_sync_routes(ad->db->tunnel_key, &ad->routes,
+                                  &received_routes, ad->db);
+        ret = ret ? ret : error;
 
         sb_sync_learned_routes(&received_routes, ad->db,
                                &ad->bound_ports, r_ctx_in->ovnsb_idl_txn,
@@ -261,7 +264,12 @@ route_exchange_run(const struct route_exchange_ctx_in 
*r_ctx_in,
     struct maintained_route_table_entry *mrt;
     HMAP_FOR_EACH_POP (mrt, node, &old_maintained_route_table) {
         if (!maintained_route_table_contains(mrt->table_id)) {
-            re_nl_cleanup_routes(mrt->table_id);
+            error = re_nl_cleanup_routes(mrt->table_id);
+            if (error) {
+                /* If netlink transaction fails, we will retry next time. */
+                maintained_route_table_add(mrt->table_id);
+                ret = ret ? ret : error;
+            }
         }
         free(mrt);
     }
@@ -271,11 +279,18 @@ route_exchange_run(const struct route_exchange_ctx_in 
*r_ctx_in,
     const char *vrf_name;
     SSET_FOR_EACH_SAFE (vrf_name, &old_maintained_vrfs) {
         if (!sset_contains(&_maintained_vrfs, vrf_name)) {
-            re_nl_delete_vrf(vrf_name);
+            error = re_nl_delete_vrf(vrf_name);
+            if (error) {
+                /* If netlink transaction fails, we will retry next time. */
+                sset_add(&_maintained_vrfs, vrf_name);
+                ret = ret ? ret : error;
+            }
         }
         sset_delete(&old_maintained_vrfs, SSET_NODE_FROM_NAME(vrf_name));
     }
     sset_destroy(&old_maintained_vrfs);
+
+    return ret;
 }
 
 void
diff --git a/controller/route-exchange.h b/controller/route-exchange.h
index 0d6772df5..7adae0adb 100644
--- a/controller/route-exchange.h
+++ b/controller/route-exchange.h
@@ -33,8 +33,8 @@ struct route_exchange_ctx_out {
     struct hmap route_table_watches;
 };
 
-void route_exchange_run(const struct route_exchange_ctx_in *,
-                        struct route_exchange_ctx_out *);
+int route_exchange_run(const struct route_exchange_ctx_in *,
+                       struct route_exchange_ctx_out *);
 void route_exchange_cleanup_vrfs(void);
 void route_exchange_destroy(void);
 
-- 
2.49.0

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to