]> git.puffer.fish Git - mirror/frr.git/commitdiff
ospf6d: fix infinite loop when adding ASBR route 12389/head
authorRenato Westphal <renato@opensourcerouting.org>
Thu, 24 Nov 2022 01:14:51 +0000 (22:14 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Thu, 24 Nov 2022 16:08:26 +0000 (13:08 -0300)
Commit 8f359e1593c414322 removed a check that prevented the same route
from being added twice. In certain topologies, that change resulted in
the following infinite loop when adding an ASBR route:

ospf6_route_add
 ospf6_top_brouter_hook_add
  ospf6_abr_examin_brouter
   ospf6_abr_examin_summary
    ospf6_route_add
     (repeat until stack overflow)

Revert the offending commit and update `ospf6_route_is_identical()` to
not do comparison using `memcmp()`.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
ospf6d/ospf6_route.c
ospf6d/ospf6_route.h

index db94b85b1b5bef5193c534ae69379d9af8079a45..1cc1fcb47b39c4966c9decf4c97b5b04d1b97bc3 100644 (file)
@@ -702,6 +702,27 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
        }
 
        if (old) {
+               /* if route does not actually change, return unchanged */
+               if (ospf6_route_is_identical(old, route)) {
+                       if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
+                               zlog_debug(
+                                       "%s %p: route add %p: needless update of %p old cost %u",
+                                       ospf6_route_table_name(table),
+                                       (void *)table, (void *)route,
+                                       (void *)old, old->path.cost);
+                       else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
+                               zlog_debug("%s: route add: needless update",
+                                          ospf6_route_table_name(table));
+
+                       ospf6_route_delete(route);
+                       SET_FLAG(old->flag, OSPF6_ROUTE_ADD);
+                       ospf6_route_table_assert(table);
+
+                       /* to free the lookup lock */
+                       route_unlock_node(node);
+                       return old;
+               }
+
                if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
                        zlog_debug(
                                "%s %p: route add %p cost %u paths %u nh %u: update of %p cost %u paths %u nh %u",
index bb5827a1766fbc5760141df6478f106faccecf8e..c8411c015f86bf833fd816663aaec54658cf8eb8 100644 (file)
@@ -297,6 +297,14 @@ extern const char *const ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX];
         && (ra)->path.origin.type == (rb)->path.origin.type                   \
         && (ra)->path.origin.id == (rb)->path.origin.id                       \
         && (ra)->path.origin.adv_router == (rb)->path.origin.adv_router)
+#define ospf6_route_is_identical(ra, rb)                                       \
+       ((ra)->type == (rb)->type &&                                           \
+        prefix_same(&(ra)->prefix, &(rb)->prefix) &&                          \
+        (ra)->path.type == (rb)->path.type &&                                 \
+        (ra)->path.cost == (rb)->path.cost &&                                 \
+        (ra)->path.u.cost_e2 == (rb)->path.u.cost_e2 &&                       \
+        listcount(ra->paths) == listcount(rb->paths) &&                       \
+        ospf6_route_cmp_nexthops(ra, rb) == 0)
 
 #define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST))