summary_table = area->summary_router;
} else {
if (IS_OSPF6_DEBUG_ABR
- || IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX)) {
+ || IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX))
is_debug++;
+
+ if (route->type == OSPF6_DEST_TYPE_NETWORK &&
+ route->path.origin.type ==
+ htons(OSPF6_LSTYPE_INTER_PREFIX)) {
+ if (!CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST)) {
+ if (is_debug) {
+ inet_ntop(AF_INET,
+ &(ADV_ROUTER_IN_PREFIX(
+ &route->prefix)), buf,
+ sizeof(buf));
+ zlog_debug(
+ "%s: route %s with cost %u is not best, ignore."
+ , __PRETTY_FUNCTION__, buf,
+ route->path.cost);
+ }
+ return 0;
+ }
+ }
+
+ if (is_debug) {
prefix2str(&route->prefix, buf, sizeof(buf));
- zlog_debug("Originating summary in area %s for %s",
- area->name, buf);
+ zlog_debug("Originating summary in area %s for %s cost %u",
+ area->name, buf, route->path.cost);
}
summary_table = area->summary_prefix;
}
ospf6_route_delete(def);
}
+void ospf6_abr_old_path_update(struct ospf6_route *old_route,
+ struct ospf6_route *route,
+ struct ospf6_route_table *table)
+{
+ struct ospf6_path *o_path = NULL;
+ struct listnode *anode, *anext;
+ struct listnode *nnode, *rnode, *rnext;
+ struct ospf6_nexthop *nh, *rnh;
+
+ for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext, o_path)) {
+ if (o_path->area_id != route->path.area_id ||
+ (memcmp(&(o_path)->origin, &(route)->path.origin,
+ sizeof(struct ospf6_ls_origin)) != 0))
+ continue;
+
+ if ((o_path->cost == route->path.cost) &&
+ (o_path->u.cost_e2 == route->path.u.cost_e2))
+ continue;
+
+ 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);
+ }
+
+ }
+
+ listnode_delete(old_route->paths, o_path);
+ ospf6_path_free(o_path);
+
+ for (ALL_LIST_ELEMENTS(old_route->paths, anode,
+ anext, o_path)) {
+ ospf6_merge_nexthops(old_route->nh_list,
+ o_path->nh_list);
+ }
+
+ if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX))
+ zlog_debug("%s: paths %u nh %u", __PRETTY_FUNCTION__,
+ old_route->paths ?
+ listcount(old_route->paths) : 0,
+ old_route->nh_list ?
+ listcount(old_route->nh_list) : 0);
+
+ if (table->hook_add)
+ (*table->hook_add)(old_route);
+
+ if (old_route->path.origin.id == route->path.origin.id &&
+ old_route->path.origin.adv_router ==
+ route->path.origin.adv_router) {
+ struct ospf6_path *h_path;
+
+ h_path = (struct ospf6_path *)
+ listgetdata(listhead(old_route->paths));
+ old_route->path.origin.type = h_path->origin.type;
+ old_route->path.origin.id = h_path->origin.id;
+ old_route->path.origin.adv_router =
+ h_path->origin.adv_router;
+ }
+ }
+}
+
+void ospf6_abr_old_route_remove(struct ospf6_lsa *lsa,
+ struct ospf6_route *old,
+ struct ospf6_route_table *table)
+{
+ if (listcount(old->paths) > 1) {
+ struct listnode *anode, *anext, *nnode, *rnode, *rnext;
+ struct ospf6_path *o_path;
+ struct ospf6_nexthop *nh, *rnh;
+ bool nh_updated = false;
+ char buf[PREFIX2STR_BUFFER];
+
+ for (ALL_LIST_ELEMENTS(old->paths, anode, anext, o_path)) {
+ if (o_path->origin.adv_router != lsa->header->adv_router
+ && o_path->origin.id != lsa->header->id)
+ continue;
+ for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
+ for (ALL_LIST_ELEMENTS(old->nh_list,
+ rnode, rnext, rnh)) {
+ if (!ospf6_nexthop_is_same(rnh, nh))
+ continue;
+ listnode_delete(old->nh_list, rnh);
+ ospf6_nexthop_delete(rnh);
+ }
+ }
+ listnode_delete(old->paths, o_path);
+ ospf6_path_free(o_path);
+ nh_updated = true;
+ }
+
+ if (nh_updated) {
+ if (listcount(old->paths)) {
+ if (IS_OSPF6_DEBUG_ABR ||
+ IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX)) {
+ prefix2str(&old->prefix, buf,
+ sizeof(buf));
+ zlog_debug("%s: old %s updated nh %u",
+ __PRETTY_FUNCTION__, buf,
+ old->nh_list ?
+ listcount(old->nh_list) : 0);
+ }
+
+ if (table->hook_add)
+ (*table->hook_add)(old);
+
+ if ((old->path.origin.id == lsa->header->id) &&
+ (old->path.origin.adv_router
+ == lsa->header->adv_router)) {
+ struct ospf6_path *h_path;
+
+ h_path = (struct ospf6_path *)
+ listgetdata(
+ listhead(old->paths));
+ old->path.origin.type =
+ h_path->origin.type;
+ old->path.origin.id = h_path->origin.id;
+ old->path.origin.adv_router =
+ h_path->origin.adv_router;
+ }
+ } else
+ ospf6_route_remove(old, table);
+ }
+ } else
+ ospf6_route_remove(old, table);
+
+}
+
/* RFC 2328 16.2. Calculating the inter-area routes */
void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
{
struct ospf6_inter_prefix_lsa *prefix_lsa = NULL;
struct ospf6_inter_router_lsa *router_lsa = NULL;
bool old_entry_updated = false;
+ struct ospf6_path *path, *o_path, *ecmp_path;
+ struct listnode *anode;
+ char adv_router[16];
memset(&prefix, 0, sizeof(prefix));
while (route && ospf6_route_is_prefix(&prefix, route)) {
if (route->path.area_id == oa->area_id
&& route->path.origin.type == lsa->header->type
- && route->path.origin.id == lsa->header->id
- && route->path.origin.adv_router == lsa->header->adv_router
- && !CHECK_FLAG(route->flag, OSPF6_ROUTE_WAS_REMOVED))
- old = route;
+ && !CHECK_FLAG(route->flag, OSPF6_ROUTE_WAS_REMOVED)) {
+ /* LSA adv. router could be part of route's
+ * paths list. Find the existing path and set
+ * old as the route.
+ */
+ if (listcount(route->paths) > 1) {
+ struct listnode *anode;
+ struct ospf6_path *o_path;
+
+ for (ALL_LIST_ELEMENTS_RO(route->paths, anode,
+ o_path)) {
+ inet_ntop(AF_INET,
+ &o_path->origin.adv_router,
+ adv_router,
+ sizeof(adv_router));
+ if (o_path->origin.id == lsa->header->id
+ && o_path->origin.adv_router ==
+ lsa->header->adv_router) {
+ old = route;
+
+ if (is_debug)
+ zlog_debug("%s: old entry found in paths, adv_router %s",
+ __PRETTY_FUNCTION__,
+ adv_router);
+
+ break;
+ }
+ }
+ } else if (route->path.origin.id == lsa->header->id &&
+ route->path.origin.adv_router ==
+ lsa->header->adv_router)
+ old = route;
+ }
route = ospf6_route_next(route);
}
if (route)
if (is_debug)
zlog_debug("cost is LS_INFINITY, ignore");
if (old)
- ospf6_route_remove(old, table);
+ ospf6_abr_old_route_remove(lsa, old, table);
return;
}
if (OSPF6_LSA_IS_MAXAGE(lsa)) {
zlog_debug("%s: LSA %s is MaxAge, ignore",
__PRETTY_FUNCTION__, lsa->name);
if (old)
- ospf6_route_remove(old, table);
+ ospf6_abr_old_route_remove(lsa, old, table);
return;
}
/* (2) if the LSA is self-originated, ignore */
if (lsa->header->adv_router == oa->ospf6->router_id) {
if (is_debug)
- zlog_debug("LSA is self-originated, ignore");
+ zlog_debug("LSA %s is self-originated, ignore",
+ lsa->name);
if (old)
ospf6_route_remove(old, table);
return;
}
/* Check input prefix-list */
- if (PREFIX_LIST_IN(oa))
+ if (PREFIX_LIST_IN(oa)) {
if (prefix_list_apply(PREFIX_LIST_IN(oa), &prefix)
!= PREFIX_PERMIT) {
if (is_debug)
ospf6_route_remove(old, table);
return;
}
+ }
/* (5),(6): the path preference is handled by the sorting
in the routing table. Always install the path by substituting
old route (if any). */
- if (old)
- route = ospf6_route_copy(old);
- else
- route = ospf6_route_create();
+ route = ospf6_route_create();
route->type = type;
route->prefix = prefix;
route->path.type = OSPF6_PATH_TYPE_INTER;
route->path.cost = abr_entry->path.cost + cost;
- /* Inter abr_entry is same as brouter.
- * Avoid duplicate nexthops to brouter and its
- * learnt route. i.e. use merge nexthops.
- */
- ospf6_route_merge_nexthops(route, abr_entry);
+ /* copy brouter rechable nexthops into the route. */
+ 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
old_route->path.cost,
route->path.cost);
}
+
+ /* Check new route's adv. router is same in one of
+ * the paths with differed cost, if so remove the
+ * old path as later new route will be added.
+ */
+ if (listcount(old_route->paths) > 1)
+ ospf6_abr_old_path_update(old_route, route,
+ table);
continue;
}
+ ospf6_route_merge_nexthops(old_route, route);
old_entry_updated = true;
- ospf6_route_merge_nexthops(old, route);
+
+ for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
+ o_path)) {
+ if (o_path->area_id == route->path.area_id &&
+ (memcmp(&(o_path)->origin, &(route)->path.origin,
+ sizeof(struct ospf6_ls_origin)) == 0))
+ break;
+ }
+
+ /* New adv. router for a existing path add to paths 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);
+
+ /* Add the new path to route's path list */
+ listnode_add_sort(old_route->paths, ecmp_path);
+
+ if (is_debug) {
+ prefix2str(&route->prefix, buf, sizeof(buf));
+ inet_ntop(AF_INET,
+ &ecmp_path->origin.adv_router,
+ adv_router, sizeof(adv_router));
+ zlog_debug("%s: route %s cost %u another path %s added with nh %u, effective paths %u nh %u",
+ __PRETTY_FUNCTION__, buf,
+ old_route->path.cost,
+ adv_router,
+ listcount(ecmp_path->nh_list),
+ old_route->paths ?
+ listcount(old_route->paths) : 0,
+ listcount(old_route->nh_list));
+ }
+ } else {
+ /* adv. router exists in the list, update the nhs */
+ list_delete_all_node(o_path->nh_list);
+ ospf6_copy_nexthops(o_path->nh_list, route->nh_list);
+ }
+
if (is_debug)
- zlog_debug("%s: Update route: %s old cost %u new cost %u nh %u",
- __PRETTY_FUNCTION__,
- buf, old->path.cost, route->path.cost,
+ zlog_debug("%s: Update route: %s %p old cost %u new cost %u nh %u",
+ __PRETTY_FUNCTION__, buf, (void *)old_route,
+ old_route->path.cost, route->path.cost,
listcount(route->nh_list));
- /* Update RIB/FIB */
+ /* For Inter-Prefix route: Update RIB/FIB,
+ * For Inter-Router trigger summary update
+ */
if (table->hook_add)
- (*table->hook_add)(old);
+ (*table->hook_add)(old_route);
/* Delete new route */
ospf6_route_delete(route);
}
if (old_entry_updated == false) {
- if (is_debug)
- zlog_debug("%s: Install route: %s cost %u nh %u",
+ if (is_debug) {
+ inet_ntop(AF_INET, &route->path.origin.adv_router,
+ adv_router, sizeof(adv_router));
+ zlog_debug("%s: Install route: %s cost %u nh %u adv_router %s ",
__PRETTY_FUNCTION__, buf, route->path.cost,
- listcount(route->nh_list));
+ listcount(route->nh_list), adv_router);
+ }
+
+ path = ospf6_path_dup(&route->path);
+ ospf6_copy_nexthops(path->nh_list, abr_entry->nh_list);
+ listnode_add_sort(route->paths, path);
+
/* ospf6_ia_add_nw_route (table, &prefix, route); */
ospf6_route_add(route, table);
}