]> git.puffer.fish Git - mirror/frr.git/commitdiff
ospf6d: missing ECMP NHs in certain topologies 13307/head
authorlynne <lynne@voltanet.io>
Wed, 23 Jun 2021 17:15:17 +0000 (13:15 -0400)
committerMergify <37929162+mergify[bot]@users.noreply.github.com>
Fri, 14 Apr 2023 13:09:47 +0000 (13:09 +0000)
When ospf6 is started up and SPF is run depending on which route is
selected as the parent route we could miss adding a NH.   If one
possible parent route has two equal cost paths and the second possible
parent route has only one depending on which one is selected first
determines if we have have one or two NHs.

In the network below when creating a route 2001:db8:3:4::/64 in R2.
When SPF is run there are two possible parent routes R3 and R4.

     2001:db8:1:2  +-----+   2001:db8:2:5
    +--------------+  2  +---------------+
    |          ::2 |     | ::2           |
    |              +-----+               |
    |                                    |
 ::1|                                    |
+-----+                                  |::5
|  1  |2001:db8:1:3+-----+2001:db8:3:5+-----+2001:db8:5:6+-----+
|     +------------+  3  +------------+  5  +------------+  6  |
+-----+ ::1    ::3 |     |::3     ::5 |     |::5      ::6|     |
 ::1|              +-----+            +-----+            +-----+
    |                 |::3
    |                 | 2001:db8:3:4
    |                 |
    |                 |::4
    | 2001:db8:1:4 +-----+
    +--------------+  4  |
               ::4 |     |
                   +-----+

The problem was if we first created the route to 2001:db8:3:4::/64 with R3
as the parent route all is fine.  The code was merging the NH from the parent
route and R3 has 2 NH, one pointing to R1 and one to R5.   But if route
2001:db8:3:4::/64 was first created with parent as R4, it has only one NH
pointing to R1, and then later a new vertex was created pointing to R3 the
code would only copy the nhs from the vertex not from the parent route.   The
vertex always has just one NH.   But the parent route could have more.  So
when we would bringup this setup one time we would see one NH for
2001:db8:3:4::/64 and the next time we would see two NHs.  The code has been
modified so that it behaves the same when the route is first created, or when
a vertex is created, it selects the NHs from the parent route.

Signed-off-by: Lynne Morrison <lynne@voltanet.io>
(cherry picked from commit 637e6f293b84c8c21d91224267a85ced30e9f8cf)

ospf6d/ospf6_spf.c
ospf6d/ospf6_spf.h

index aac371ebbbafe805ecec46b1b0b04bca980c14ee..87aab2c760c869936ed87bdd9fc309149d450ba3 100644 (file)
@@ -325,7 +325,7 @@ static void ospf6_nexthop_calc(struct ospf6_vertex *w, struct ospf6_vertex *v,
 static int ospf6_spf_install(struct ospf6_vertex *v,
                             struct ospf6_route_table *result_table)
 {
-       struct ospf6_route *route, *parent_route;
+       struct ospf6_route *route;
        struct ospf6_vertex *prev;
 
        if (IS_OSPF6_DEBUG_SPF(PROCESS))
@@ -345,7 +345,12 @@ static int ospf6_spf_install(struct ospf6_vertex *v,
                        zlog_debug(
                                "  another path found to route %pFX lsa %s, merge",
                                &route->prefix, v->lsa->name);
-               ospf6_spf_merge_nexthops_to_route(route, v);
+
+               /* merging the parent's nexthop information to the child's
+                * if the parent is not the root of the tree.
+                */
+               if (!ospf6_merge_parents_nh_to_child(v, route, result_table))
+                       ospf6_spf_merge_nexthops_to_route(route, v);
 
                prev = (struct ospf6_vertex *)route->route_option;
                assert(prev->hops <= v->hops);
@@ -411,13 +416,7 @@ static int ospf6_spf_install(struct ospf6_vertex *v,
         * installed,
         * its parent's route's nexthops have already been installed.
         */
-       if (v->parent && v->parent->hops) {
-               parent_route =
-                       ospf6_route_lookup(&v->parent->vertex_id, result_table);
-               if (parent_route) {
-                       ospf6_route_merge_nexthops(route, parent_route);
-               }
-       }
+       ospf6_merge_parents_nh_to_child(v, route, result_table);
 
        if (v->parent)
                listnode_add_sort(v->parent->child_list, v);
@@ -1290,3 +1289,20 @@ void ospf6_ase_calculate_timer_add(struct ospf6 *ospf6)
        thread_add_timer(master, ospf6_ase_calculate_timer, ospf6,
                         OSPF6_ASE_CALC_INTERVAL, &ospf6->t_ase_calc);
 }
+
+bool ospf6_merge_parents_nh_to_child(struct ospf6_vertex *v,
+                                    struct ospf6_route *route,
+                                    struct ospf6_route_table *result_table)
+{
+       struct ospf6_route *parent_route;
+
+       if (v->parent && v->parent->hops) {
+               parent_route =
+                       ospf6_route_lookup(&v->parent->vertex_id, result_table);
+               if (parent_route) {
+                       ospf6_route_merge_nexthops(route, parent_route);
+                       return true;
+               }
+       }
+       return false;
+}
index cc52d168614e8086dda7c53a3c5ababe01101b37..4137e790dce03d23f68e0fb3c4a26e02f1536934 100644 (file)
@@ -167,4 +167,8 @@ extern void ospf6_remove_temp_router_lsa(struct ospf6_area *area);
 extern void ospf6_ase_calculate_timer_add(struct ospf6 *ospf6);
 extern int ospf6_ase_calculate_route(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
                                     struct ospf6_area *area);
+extern bool
+ospf6_merge_parents_nh_to_child(struct ospf6_vertex *v,
+                               struct ospf6_route *route,
+                               struct ospf6_route_table *result_table);
 #endif /* OSPF6_SPF_H */