]> git.proxmox.com Git - mirror_frr.git/commitdiff
ospf6d: Fix External routes ECMP
authorChirag Shah <chirag@cumulusnetworks.com>
Thu, 7 Dec 2017 02:20:48 +0000 (18:20 -0800)
committerChirag Shah <chirag@cumulusnetworks.com>
Tue, 2 Jan 2018 18:00:38 +0000 (10:00 -0800)
Handle RFC 2328 16.4 Calculating AS external routes with ECMP

For ASBR route, if it is learnt via new LSA and contains
different nexthop list. First lookup route in ospf6 route table
if it exists, merge nexthop list to existing and call the callback
to install into FIB (zebra). Delete created new route as it is
identical to existing entry in route table.

Ticket:CM-16139
Testing Done:
Run two ASBR with 2 ECMP paths from each
DUT neighbor receievs 4 ECMP path to a external route.
ospf6 installs all 4 ECMP path to FIB/RIB

Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
ospf6d/ospf6_abr.c
ospf6d/ospf6_area.c
ospf6d/ospf6_asbr.c
ospf6d/ospf6_asbr.h
ospf6d/ospf6_intra.c
ospf6d/ospf6_memory.c
ospf6d/ospf6_memory.h
ospf6d/ospf6_route.c
ospf6d/ospf6_route.h
ospf6d/ospf6_spf.c
ospf6d/ospf6_top.c

index d270b9547edc4360fc16cfe17cceaa787646f04c..8847611492b0333558122951af3930312df7025b 100644 (file)
@@ -901,6 +901,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
 
        ospf6_route_copy_nexthops(route, abr_entry);
 
+
        /* (7) If the routes are identical, copy the next hops over to existing
           route. ospf6's route table implementation will otherwise string both
           routes, but keep the older one as the best route since the routes
@@ -910,6 +911,12 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
 
        if (old && (ospf6_route_cmp(route, old) == 0)) {
                ospf6_route_merge_nexthops(old, route);
+
+               if (is_debug)
+                       zlog_debug("%s: Update route: %s nh count %u",
+                               __PRETTY_FUNCTION__,
+                               buf, listcount(route->nh_list));
+
                /* Update RIB/FIB */
                if (table->hook_add)
                        (*table->hook_add)(old);
@@ -918,7 +925,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                ospf6_route_delete(route);
        } else {
                if (is_debug)
-                       zlog_debug("Install route: %s", buf);
+                       zlog_debug("Install route: %s nh count %u",
+                                  buf, listcount(route->nh_list));
                /* ospf6_ia_add_nw_route (table, &prefix, route); */
                ospf6_route_add(route, table);
        }
index bd5e2bd1d35740e1d6ff6ce0bdcaaa5f29907df1..252e4a454549edacefec34a13611cf9d931fd3a2 100644 (file)
@@ -117,7 +117,9 @@ static void ospf6_area_lsdb_hook_remove(struct ospf6_lsa *lsa)
 
 static void ospf6_area_route_hook_add(struct ospf6_route *route)
 {
-       struct ospf6_route *copy = ospf6_route_copy(route);
+       struct ospf6_route *copy;
+
+       copy = ospf6_route_copy(route);
        ospf6_route_add(copy, ospf6->route_table);
 }
 
index 5fbf2dafa58e90859785dd59efff5b9d95b54ab9..745b87b890ed13f527557a19b37dd31a99e09f7d 100644 (file)
@@ -173,11 +173,136 @@ static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa)
        return ntohl(network_order);
 }
 
+void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
+                                      struct ospf6_route *route)
+{
+       struct ospf6_route *old_route;
+       struct ospf6_path *ecmp_path, *o_path = NULL;
+       struct listnode *anode;
+       struct listnode *nnode, *rnode, *rnext;
+       struct ospf6_nexthop *nh, *rnh;
+       char buf[PREFIX2STR_BUFFER];
+       bool route_found = false;
+
+       for (old_route = old; old_route; old_route = old_route->next) {
+               if (ospf6_route_is_same(old_route, route) &&
+                       (old_route->path.type == route->path.type) &&
+                       (old_route->path.cost == route->path.cost) &&
+                       (old_route->path.u.cost_e2 == route->path.u.cost_e2)) {
+
+                       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                               prefix2str(&old_route->prefix, buf,
+                                          sizeof(buf));
+                               zlog_debug("%s: old route %s path  cost %u [%u]",
+                                          __PRETTY_FUNCTION__, buf,
+                                          old_route->path.cost,
+                                          ospf6_route_is_same(old_route,
+                                                              route));
+                       }
+                       route_found = true;
+                       /* check if this path exists already in
+                        * route->paths list, if so, replace nh_list
+                        * from asbr_entry.
+                        */
+                       for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
+                                                 o_path)) {
+                               if ((o_path->origin.id == route->path.origin.id)
+                                       && (o_path->origin.adv_router ==
+                                               route->path.origin.adv_router))
+                                       break;
+                       }
+                       /* If path is not found in old_route paths's list,
+                        * add a new path to route paths list and merge
+                        * nexthops in route->path->nh_list.
+                        * Otherwise replace existing path's nh_list.
+                        */
+                       if (o_path == NULL) {
+                               ecmp_path = ospf6_path_dup(&route->path);
+
+                               /* Add a nh_list to new ecmp path */
+                               ospf6_copy_nexthops(ecmp_path->nh_list,
+                                                   route->nh_list);
+                               /* Merge nexthop to existing route's nh_list */
+                               ospf6_route_merge_nexthops(old_route, route);
+
+                               /* Update RIB/FIB */
+                               if (ospf6->route_table->hook_add)
+                                       (*ospf6->route_table->hook_add)
+                                               (old_route);
+
+                               /* Add the new path to route's path list */
+                               listnode_add_sort(old_route->paths, ecmp_path);
+
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                                       prefix2str(&route->prefix, buf,
+                                                  sizeof(buf));
+                                       zlog_debug("%s: route %s another path added with nh %u, Paths %u",
+                                               __PRETTY_FUNCTION__, buf,
+                                               listcount(ecmp_path->nh_list),
+                                               old_route->paths ?
+                                               listcount(old_route->paths)
+                                               : 0);
+                               }
+                       } else {
+                               for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
+                                                         nnode, nh)) {
+                                       for (ALL_LIST_ELEMENTS(
+                                                       old_route->nh_list,
+                                                       rnode, rnext, rnh)) {
+                                               if (!ospf6_nexthop_is_same(rnh,
+                                                                          nh))
+                                                       continue;
+
+                                               listnode_delete(
+                                                       old_route->nh_list,
+                                                       rnh);
+                                               ospf6_nexthop_delete(rnh);
+                                       }
+                               }
+                               list_delete_all_node(o_path->nh_list);
+                               ospf6_copy_nexthops(o_path->nh_list,
+                                           route->nh_list);
+
+                               /* Merge nexthop to existing route's nh_list */
+                               ospf6_route_merge_nexthops(old_route,
+                                                          route);
+
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                                       prefix2str(&route->prefix,
+                                                  buf, sizeof(buf));
+                                       zlog_debug("%s: existing route %s with effective nh count %u",
+                                                  __PRETTY_FUNCTION__, buf,
+                                                  old_route->nh_list ?
+                                                  listcount(old_route->nh_list)
+                                                  : 0);
+                               }
+
+                               /* Update RIB/FIB */
+                               if (ospf6->route_table->hook_add)
+                                       (*ospf6->route_table->hook_add)
+                                               (old_route);
+
+                       }
+                       /* Delete the new route its info added to existing
+                        * route.
+                        */
+                       ospf6_route_delete(route);
+                       break;
+               }
+       }
+
+       if (!route_found) {
+               /* Add new route to existing node in ospf6 route table. */
+               ospf6_route_add(route, ospf6->route_table);
+       }
+}
+
 void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
 {
        struct ospf6_as_external_lsa *external;
        struct prefix asbr_id;
-       struct ospf6_route *asbr_entry, *route;
+       struct ospf6_route *asbr_entry, *route, *old;
+       struct ospf6_path *path;
        char buf[PREFIX2STR_BUFFER];
 
        external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
@@ -245,12 +370,34 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
 
        ospf6_route_copy_nexthops(route, asbr_entry);
 
+       path = ospf6_path_dup(&route->path);
+       ospf6_copy_nexthops(path->nh_list, asbr_entry->nh_list);
+       listnode_add_sort(route->paths, path);
+
+
        if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
                prefix2str(&route->prefix, buf, sizeof(buf));
-               zlog_debug("AS-External route add: %s", buf);
+               zlog_debug("%s: AS-External %u route add %s cost %u(%u) nh %u",
+                          __PRETTY_FUNCTION__,
+                          (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1)
+                          ? 1 : 2, buf, route->path.cost,
+                          route->path.u.cost_e2,
+                          listcount(route->nh_list));
+       }
+
+       old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
+       if (!old) {
+               /* Add the new route to ospf6 instance route table. */
+               ospf6_route_add(route, ospf6->route_table);
+       } else {
+               /* RFC 2328 16.4 (6)
+                * ECMP: Keep new equal preference path in current
+                * route's path list, update zebra with new effective
+                * list along with addition of ECMP path.
+                */
+               ospf6_asbr_update_route_ecmp_path(old, route);
        }
 
-       ospf6_route_add(route, ospf6->route_table);
 }
 
 void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
@@ -291,16 +438,126 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
                nroute = ospf6_route_next(route);
                if (route->type != OSPF6_DEST_TYPE_NETWORK)
                        continue;
-               if (route->path.origin.type != lsa->header->type)
-                       continue;
-               if (route->path.origin.id != lsa->header->id)
-                       continue;
-               if (route->path.origin.adv_router != lsa->header->adv_router)
+
+               /* Route has multiple ECMP paths remove,
+                * matching path and update effective route's  nh list.
+                */
+               if (listcount(route->paths) > 1) {
+                       struct listnode *anode, *anext;
+                       struct listnode *nnode, *rnode, *rnext;
+                       struct ospf6_nexthop *nh, *rnh;
+                       struct ospf6_path *o_path;
+                       bool nh_updated = false;
+
+                       /* Iterate all paths of route to find maching with LSA
+                        * remove from route path list. If route->path is same,
+                        * replace from paths list.
+                        */
+                       for (ALL_LIST_ELEMENTS(route->paths, anode, anext,
+                                                 o_path)) {
+                               if (o_path->origin.type != lsa->header->type)
+                                       continue;
+                               if (o_path->origin.id != lsa->header->id)
+                                       continue;
+                               if (o_path->origin.adv_router !=
+                                       lsa->header->adv_router)
+                                       continue;
+
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))  {
+                                       prefix2str(&prefix, buf, sizeof(buf));
+                                       zlog_debug(
+                                               "%s: route %s path found with nh %u",
+                                               __PRETTY_FUNCTION__, buf,
+                                               listcount(o_path->nh_list));
+                               }
+
+                               /* Remove found path's nh_list from
+                                * the route's nh_list.
+                                */
+                               for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
+                                                         nnode, nh)) {
+                                       for (ALL_LIST_ELEMENTS(route->nh_list,
+                                                       rnode, rnext, rnh)) {
+                                               if (!ospf6_nexthop_is_same(rnh,
+                                                               nh))
+                                                       continue;
+                                               listnode_delete(route->nh_list,
+                                                               rnh);
+                                               ospf6_nexthop_delete(rnh);
+                                       }
+                               }
+                               /* Delete the path from route's path list */
+                               listnode_delete(route->paths, o_path);
+                               ospf6_path_free(o_path);
+                               nh_updated = true;
+                       }
+
+                       if (nh_updated) {
+                               /* Iterate all paths and merge nexthop,
+                                * unlesss any of the nexthop similar to
+                                * ones deleted as part of path deletion.
+                                */
+
+                               for (ALL_LIST_ELEMENTS(route->paths, anode,
+                                                      anext, o_path)) {
+                                       ospf6_merge_nexthops(route->nh_list,
+                                                            o_path->nh_list);
+                               }
+
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                                       prefix2str(&route->prefix, buf,
+                                                  sizeof(buf));
+                                       zlog_debug("%s: AS-External %u route %s update paths %u nh %u"
+                                                  , __PRETTY_FUNCTION__,
+                                                  (route->path.type ==
+                                                  OSPF6_PATH_TYPE_EXTERNAL1)
+                                                  ? 1 : 2, buf,
+                                                  listcount(route->paths),
+                                                  listcount(route->nh_list));
+                               }
+
+                               /* Update RIB/FIB w/ effective nh_list */
+                               if (ospf6->route_table->hook_add)
+                                       (*ospf6->route_table->hook_add)(route);
+
+                               /* route's path is similar to lsa header,
+                                * replace route's path with route's
+                                * paths list head.
+                                */
+                               if (route->path.origin.id == lsa->header->id &&
+                                   route->path.origin.adv_router ==
+                                               lsa->header->adv_router) {
+                                       struct ospf6_path *h_path;
+
+                                       h_path = (struct ospf6_path *)
+                                       listgetdata(listhead(route->paths));
+                                       route->path.origin.type =
+                                               h_path->origin.type;
+                                       route->path.origin.id =
+                                               h_path->origin.id;
+                                       route->path.origin.adv_router =
+                                               h_path->origin.adv_router;
+                               }
+                       }
                        continue;
 
+               } else {
+                       if (route->path.origin.type != lsa->header->type)
+                               continue;
+                       if (route->path.origin.id != lsa->header->id)
+                               continue;
+                       if (route->path.origin.adv_router !=
+                                       lsa->header->adv_router)
+                               continue;
+               }
                if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
                        prefix2str(&route->prefix, buf, sizeof(buf));
-                       zlog_debug("AS-External route remove: %s", buf);
+                       zlog_debug("%s: AS-External %u route remove %s cost %u(%u) nh %u",
+                                  __PRETTY_FUNCTION__,
+                                  route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
+                                  ? 1 : 2, buf, route->path.cost,
+                                  route->path.u.cost_e2,
+                                  listcount(route->nh_list));
                }
                ospf6_route_remove(route, ospf6->route_table);
        }
index 73053452e6a22ac0e838d3dbd604af7e071875a1..7f4665ac2b501645831f610dbbdd2bbb1efba7d2 100644 (file)
@@ -93,5 +93,7 @@ extern void ospf6_asbr_send_externals_to_area(struct ospf6_area *);
 
 extern int config_write_ospf6_debug_asbr(struct vty *vty);
 extern void install_element_ospf6_debug_asbr(void);
+extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
+                                             struct ospf6_route *route);
 
 #endif /* OSPF6_ASBR_H */
index b1d940952ca09019b8cffe6b69e2f214729e56dc..77653ea33fa80f9dc5f42ed0a08677eae209f3b5 100644 (file)
@@ -1404,7 +1404,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
 
                if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
                        prefix2str(&route->prefix, buf, sizeof(buf));
-                       zlog_debug("  route %s add", buf);
+                       zlog_debug("  route %s add with nh count %u", buf,
+                                  listcount(route->nh_list));
                }
 
                ospf6_route_add(route, oa->route_table);
index 56c232d6da98bbb90c07f2cef085e5fec8e56ca6..1c3523b43d327fa76a4a21d0cded83a6b13967bd 100644 (file)
@@ -41,4 +41,5 @@ DEFINE_MTYPE(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex")
 DEFINE_MTYPE(OSPF6D, OSPF6_SPFTREE, "OSPF6 SPF tree")
 DEFINE_MTYPE(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop")
 DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info")
+DEFINE_MTYPE(OSPF6D, OSPF6_PATH, "OSPF6 Path")
 DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other")
index fe72ee3669763e89cdd4fe490bdb446dc90864e8..548af5e321e7767ae7c60187b0ff977454cf9a8e 100644 (file)
@@ -40,6 +40,7 @@ DECLARE_MTYPE(OSPF6_VERTEX)
 DECLARE_MTYPE(OSPF6_SPFTREE)
 DECLARE_MTYPE(OSPF6_NEXTHOP)
 DECLARE_MTYPE(OSPF6_EXTERNAL_INFO)
+DECLARE_MTYPE(OSPF6_PATH)
 DECLARE_MTYPE(OSPF6_OTHER)
 
 #endif /* _QUAGGA_OSPF6_MEMORY_H */
index 281757222dd1d1b595ef7083af19a4144ab84062..735b28a69330ce37c635b0770266d44af28210ab 100644 (file)
@@ -215,7 +215,7 @@ void ospf6_copy_nexthops(struct list *dst, struct list *src)
                        if (ospf6_nexthop_is_set(nh)) {
                                nh_new = ospf6_nexthop_create();
                                ospf6_nexthop_copy(nh_new, nh);
-                               listnode_add(dst, nh_new);
+                               listnode_add_sort(dst, nh_new);
                        }
                }
        }
@@ -231,7 +231,7 @@ void ospf6_merge_nexthops(struct list *dst, struct list *src)
                        if (!ospf6_route_find_nexthop(dst, nh)) {
                                nh_new = ospf6_nexthop_create();
                                ospf6_nexthop_copy(nh_new, nh);
-                               listnode_add(dst, nh_new);
+                               listnode_add_sort(dst, nh_new);
                        }
                }
        }
@@ -338,7 +338,7 @@ int ospf6_route_get_first_nh_index(struct ospf6_route *route)
        return (-1);
 }
 
-static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
+int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
 {
        if (a->ifindex < b->ifindex)
                return -1;
@@ -351,6 +351,36 @@ static int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
        return 0;
 }
 
+static int ospf6_path_cmp(struct ospf6_path *a, struct ospf6_path *b)
+{
+       if (a->origin.adv_router < b->origin.adv_router)
+               return -1;
+       else if (a->origin.adv_router > b->origin.adv_router)
+               return 1;
+       else
+               return 0;
+}
+
+void ospf6_path_free(struct ospf6_path *op)
+{
+       if (op->nh_list)
+               list_delete_and_null(&op->nh_list);
+       XFREE(MTYPE_OSPF6_PATH, op);
+}
+
+struct ospf6_path *ospf6_path_dup(struct ospf6_path *path)
+{
+       struct ospf6_path *new;
+
+       new = XCALLOC(MTYPE_OSPF6_PATH, sizeof(struct ospf6_path));
+       memcpy(new, path, sizeof(struct ospf6_path));
+       new->nh_list = list_new();
+       new->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
+       new->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
+
+       return new;
+}
+
 struct ospf6_route *ospf6_route_create(void)
 {
        struct ospf6_route *route;
@@ -358,6 +388,9 @@ struct ospf6_route *ospf6_route_create(void)
        route->nh_list = list_new();
        route->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
        route->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
+       route->paths = list_new();
+       route->paths->cmp = (int (*)(void *, void *))ospf6_path_cmp;
+       route->paths->del =  (void (*)(void *))ospf6_path_free;
        return route;
 }
 
@@ -366,6 +399,8 @@ void ospf6_route_delete(struct ospf6_route *route)
        if (route) {
                if (route->nh_list)
                        list_delete_and_null(&route->nh_list);
+               if (route->paths)
+                       list_delete_and_null(&route->paths);
                XFREE(MTYPE_OSPF6_ROUTE, route);
        }
 }
@@ -464,7 +499,13 @@ ospf6_route_lookup_identical(struct ospf6_route *route,
 
        for (target = ospf6_route_lookup(&route->prefix, table); target;
             target = target->next) {
-               if (ospf6_route_is_identical(target, route))
+               if (target->type == route->type &&
+                   (memcmp(&target->prefix, &route->prefix,
+                          sizeof(struct prefix)) == 0) &&
+                   target->path.type == route->path.type &&
+                   target->path.cost == route->path.cost &&
+                   target->path.u.cost_e2 == route->path.u.cost_e2 &&
+                   ospf6_route_cmp_nexthops(target, route) == 0)
                        return target;
        }
        return NULL;
@@ -1083,6 +1124,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route)
        vty_out(vty, "Metric: %d (%d)\n", route->path.cost,
                route->path.u.cost_e2);
 
+       vty_out(vty, "Paths count: %u\n", route->paths->count);
        vty_out(vty, "Nexthop count: %u\n", route->nh_list->count);
        /* Nexthops */
        vty_out(vty, "Nexthop:\n");
index 9eacadbdb7dee68e0254b84230965d369beb1b72..b759828c39a81371cf82621a0563d7926a65389a 100644 (file)
@@ -96,6 +96,9 @@ struct ospf6_path {
                u_int32_t cost_config;
        } u;
        u_int32_t tag;
+
+       /* nh list for this path */
+       struct list *nh_list;
 };
 
 #define OSPF6_PATH_TYPE_NONE         0
@@ -149,6 +152,9 @@ struct ospf6_route {
        /* path */
        struct ospf6_path path;
 
+       /* List of Paths. */
+       struct list *paths;
+
        /* nexthop */
        struct list *nh_list;
 };
@@ -256,6 +262,7 @@ extern void ospf6_linkstate_prefix2str(struct prefix *prefix, char *buf,
                                       int size);
 
 extern struct ospf6_nexthop *ospf6_nexthop_create(void);
+extern int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b);
 extern void ospf6_nexthop_delete(struct ospf6_nexthop *nh);
 extern void ospf6_clear_nexthops(struct list *nh_list);
 extern int ospf6_num_nexthops(struct list *nh_list);
@@ -331,5 +338,7 @@ extern int config_write_ospf6_debug_route(struct vty *vty);
 extern void install_element_ospf6_debug_route(void);
 extern void ospf6_route_init(void);
 extern void ospf6_clean(void);
+extern void ospf6_path_free(struct ospf6_path *op);
+extern struct ospf6_path *ospf6_path_dup(struct ospf6_path *path);
 
 #endif /* OSPF6_ROUTE_H */
index 340d90159ff8d2d539a0d154d507c1b3ae5aba85..6e6d8a7f009756a54234a72acf5edb840ba1be56 100644 (file)
@@ -145,6 +145,7 @@ static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa)
        v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END(lsa->header) + 3);
 
        v->nh_list = list_new();
+       v->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp;
        v->nh_list->del = (void (*) (void *))ospf6_nexthop_delete;
 
        v->parent = NULL;
index e0844765d3e423d83cd1184b47bd38aa9c74a703..5d1144335be4c27b55d1f6a4bdf96f0017e59167 100644 (file)
@@ -95,6 +95,13 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route)
 
 static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
 {
+       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+               char buf[PREFIX2STR_BUFFER];
+
+               prefix2str(&route->prefix, buf, sizeof(buf));
+               zlog_debug("%s: brouter %s add with nh count %u",
+                          __PRETTY_FUNCTION__, buf, listcount(route->nh_list));
+       }
        ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
        ospf6_asbr_lsentry_add(route);
        ospf6_abr_originate_summary(route);
@@ -102,6 +109,13 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
 
 static void ospf6_top_brouter_hook_remove(struct ospf6_route *route)
 {
+       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+               char buf[PREFIX2STR_BUFFER];
+
+               prefix2str(&route->prefix, buf, sizeof(buf));
+               zlog_debug("%s: brouter %s del with nh count %u",
+                          __PRETTY_FUNCTION__, buf, listcount(route->nh_list));
+       }
        route->flag |= OSPF6_ROUTE_REMOVE;
        ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
        ospf6_asbr_lsentry_remove(route);