summaryrefslogtreecommitdiffstats
path: root/ospf6d
diff options
context:
space:
mode:
authorChirag Shah <chirag@cumulusnetworks.com>2017-12-07 03:20:48 +0100
committerChirag Shah <chirag@cumulusnetworks.com>2018-01-02 19:00:38 +0100
commit064d4355ca82c924ec928c67150f243f17f56139 (patch)
tree33a399b265a4668270a6a857baf46b226aaaa29d /ospf6d
parentMerge pull request #1584 from donaldsharp/1575_fix (diff)
downloadfrr-064d4355ca82c924ec928c67150f243f17f56139.tar.xz
frr-064d4355ca82c924ec928c67150f243f17f56139.zip
ospf6d: Fix External routes ECMP
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>
Diffstat (limited to 'ospf6d')
-rw-r--r--ospf6d/ospf6_abr.c10
-rw-r--r--ospf6d/ospf6_area.c4
-rw-r--r--ospf6d/ospf6_asbr.c275
-rw-r--r--ospf6d/ospf6_asbr.h2
-rw-r--r--ospf6d/ospf6_intra.c3
-rw-r--r--ospf6d/ospf6_memory.c1
-rw-r--r--ospf6d/ospf6_memory.h1
-rw-r--r--ospf6d/ospf6_route.c50
-rw-r--r--ospf6d/ospf6_route.h9
-rw-r--r--ospf6d/ospf6_spf.c1
-rw-r--r--ospf6d/ospf6_top.c14
11 files changed, 354 insertions, 16 deletions
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index d270b9547..884761149 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -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);
}
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
index bd5e2bd1d..252e4a454 100644
--- a/ospf6d/ospf6_area.c
+++ b/ospf6d/ospf6_area.c
@@ -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);
}
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 5fbf2dafa..745b87b89 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -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);
}
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index 73053452e..7f4665ac2 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -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 */
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index b1d940952..77653ea33 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -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);
diff --git a/ospf6d/ospf6_memory.c b/ospf6d/ospf6_memory.c
index 56c232d6d..1c3523b43 100644
--- a/ospf6d/ospf6_memory.c
+++ b/ospf6d/ospf6_memory.c
@@ -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")
diff --git a/ospf6d/ospf6_memory.h b/ospf6d/ospf6_memory.h
index fe72ee366..548af5e32 100644
--- a/ospf6d/ospf6_memory.h
+++ b/ospf6d/ospf6_memory.h
@@ -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 */
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index 281757222..735b28a69 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -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");
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
index 9eacadbdb..b759828c3 100644
--- a/ospf6d/ospf6_route.h
+++ b/ospf6d/ospf6_route.h
@@ -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 */
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
index 340d90159..6e6d8a7f0 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -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;
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index e0844765d..5d1144335 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -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);