diff options
| author | Donald Sharp <sharpd@cumulusnetworks.com> | 2015-05-19 18:03:39 -0700 |
|---|---|---|
| committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2015-05-19 18:03:39 -0700 |
| commit | c3c0ac8395502d7e84e94e0281cb72fa37a236c4 (patch) | |
| tree | 7975560428f010d143f48ad83f7b1099fa471d39 /ospf6d/ospf6_abr.c | |
| parent | 60e42c52d6c9f3204f4b90c44413b1c392cd3b6c (diff) | |
ospf6d: ospfv3-abr-ecmp-support.patch
OSPFv3: Add ABR support and make ECMP > 4.
Signed-off-by: Dinesh G Dutt <ddutt at cumulusnetworks.com>
Signed-off-by: Pradosh Mohapatra <pmohapat at cumulusnetworks.com>
Diffstat (limited to 'ospf6d/ospf6_abr.c')
| -rw-r--r-- | ospf6d/ospf6_abr.c | 405 |
1 files changed, 279 insertions, 126 deletions
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index bb79900e5d..f975ce8427 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -38,6 +38,7 @@ #include "ospf6_route.h" #include "ospf6_lsdb.h" #include "ospf6_message.h" +#include "ospf6_zebra.h" #include "ospf6_top.h" #include "ospf6_area.h" @@ -67,6 +68,33 @@ ospf6_is_router_abr (struct ospf6 *o) return 0; } +static int +ospf6_abr_nexthops_belong_to_area (struct ospf6_route *route, + struct ospf6_area *area) +{ + struct ospf6_interface *oi; + + oi = ospf6_interface_lookup_by_ifindex (ospf6_route_get_first_nh_index(route)); + if (oi && oi->area && oi->area == area) + return 1; + else + return 0; +} + +static void +ospf6_abr_delete_route (struct ospf6_route *range, struct ospf6_route *summary, + struct ospf6_route_table *summary_table, + struct ospf6_lsa *old) +{ + if (summary) + { + ospf6_route_remove (summary, summary_table); + } + + if (old) + ospf6_lsa_purge (old); +} + void ospf6_abr_enable_area (struct ospf6_area *area) { @@ -139,12 +167,11 @@ ospf6_abr_disable_area (struct ospf6_area *area) } /* RFC 2328 12.4.3. Summary-LSAs */ -void +int ospf6_abr_originate_summary_to_area (struct ospf6_route *route, struct ospf6_area *area) { struct ospf6_lsa *lsa, *old = NULL; - struct ospf6_interface *oi; struct ospf6_route *summary, *range = NULL; struct ospf6_area *route_area; char buffer[OSPF6_MAX_LSASIZE]; @@ -157,6 +184,54 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, char buf[64]; int is_debug = 0; + /* Only destination type network, range or ASBR are considered */ + if (route->type != OSPF6_DEST_TYPE_NETWORK && + route->type != OSPF6_DEST_TYPE_RANGE && + ((route->type != OSPF6_DEST_TYPE_ROUTER) || + !CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E))) + { + if (is_debug) + zlog_debug ("Route type is none of network, range nor ASBR, ignore"); + return 0; + } + + /* AS External routes are never considered */ + if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || + route->path.type == OSPF6_PATH_TYPE_EXTERNAL2) + { + if (is_debug) + zlog_debug ("Path type is external, skip"); + return 0; + } + + /* do not generate if the path's area is the same as target area */ + if (route->path.area_id == area->area_id) + { + if (is_debug) + zlog_debug ("The route is in the area itself, ignore"); + return 0; + } + + /* do not generate if the nexthops belongs to the target area */ + if (ospf6_abr_nexthops_belong_to_area (route, area)) + { + if (is_debug) + zlog_debug ("The route's nexthop is in the same area, ignore"); + return 0; + } + + if (route->type == OSPF6_DEST_TYPE_ROUTER) + { + if (ADV_ROUTER_IN_PREFIX (&route->prefix) == area->ospf6->router_id) + { + inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf, + sizeof (buf)); + zlog_debug ("%s: Skipping ASBR announcement for ABR (%s)", __func__, + buf); + return 0; + } + } + if (route->type == OSPF6_DEST_TYPE_ROUTER) { if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_ROUTER)) @@ -192,76 +267,53 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, { if (is_debug) zlog_debug ("The route has just removed, purge previous LSA"); - if (summary) - ospf6_route_remove (summary, summary_table); - if (old) - ospf6_lsa_purge (old); - return; - } - /* Only destination type network, range or ASBR are considered */ - if (route->type != OSPF6_DEST_TYPE_NETWORK && - route->type != OSPF6_DEST_TYPE_RANGE && - (route->type != OSPF6_DEST_TYPE_ROUTER || - ! CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E))) - { - if (is_debug) - zlog_debug ("Route type is none of network, range nor ASBR, withdraw"); - if (summary) - ospf6_route_remove (summary, summary_table); - if (old) - ospf6_lsa_purge (old); - return; - } + if (route->type == OSPF6_DEST_TYPE_RANGE) + { + /* Whether the route have active longer prefix */ + if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) + { + if (is_debug) + zlog_debug ("The range is not active. withdraw"); + + ospf6_abr_delete_route (route, summary, summary_table, old); + } + } + else + if (old) + ospf6_lsa_purge (old); - /* AS External routes are never considered */ - if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || - route->path.type == OSPF6_PATH_TYPE_EXTERNAL2) - { - if (is_debug) - zlog_debug ("Path type is external, withdraw"); - if (summary) - ospf6_route_remove (summary, summary_table); - if (old) - ospf6_lsa_purge (old); - return; + return 0; } - /* do not generate if the path's area is the same as target area */ - if (route->path.area_id == area->area_id) + if ((route->type == OSPF6_DEST_TYPE_ROUTER) && IS_AREA_STUB(area)) { if (is_debug) - zlog_debug ("The route is in the area itself, ignore"); - if (summary) - ospf6_route_remove (summary, summary_table); - if (old) - ospf6_lsa_purge (old); - return; - } + zlog_debug ("Area has been stubbed, purge Inter-Router LSA"); - /* do not generate if the nexthops belongs to the target area */ - oi = ospf6_interface_lookup_by_ifindex (route->nexthop[0].ifindex); - if (oi && oi->area && oi->area == area) - { - if (is_debug) - zlog_debug ("The route's nexthop is in the same area, ignore"); - if (summary) - ospf6_route_remove (summary, summary_table); - if (old) - ospf6_lsa_purge (old); - return; + ospf6_abr_delete_route (route, summary, summary_table, old); + return 0; } /* do not generate if the route cost is greater or equal to LSInfinity */ if (route->path.cost >= OSPF_LS_INFINITY) { - if (is_debug) - zlog_debug ("The cost exceeds LSInfinity, withdraw"); - if (summary) - ospf6_route_remove (summary, summary_table); - if (old) - ospf6_lsa_purge (old); - return; + /* When we're clearing the range route because all active prefixes + * under the range are gone, we set the range's cost to + * OSPF_AREA_RANGE_COST_UNSPEC, which is > OSPF_LS_INFINITY. We + * don't want to trigger the code here for that. This code is for + * handling routes that have gone to infinity. The range removal happens + * elsewhere. + */ + if ((route->type != OSPF6_DEST_TYPE_RANGE) && + (route->path.cost != OSPF_AREA_RANGE_COST_UNSPEC)) + { + if (is_debug) + zlog_debug ("The cost exceeds LSInfinity, withdraw"); + if (old) + ospf6_lsa_purge (old); + return 0; + } } /* if this is a route to ASBR */ @@ -272,11 +324,8 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, { if (is_debug) zlog_debug ("This is the secondary path to the ASBR, ignore"); - if (summary) - ospf6_route_remove (summary, summary_table); - if (old) - ospf6_lsa_purge (old); - return; + ospf6_abr_delete_route (route, summary, summary_table, old); + return 0; } /* Do not generate if the area is stub */ @@ -305,12 +354,8 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, zlog_debug ("Suppressed by range %s of area %s", buf, route_area->name); } - - if (summary) - ospf6_route_remove (summary, summary_table); - if (old) - ospf6_lsa_purge (old); - return; + ospf6_abr_delete_route (route, summary, summary_table, old); + return 0; } } @@ -322,23 +367,17 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, { if (is_debug) zlog_debug ("This is the range with DoNotAdvertise set. ignore"); - if (summary) - ospf6_route_remove (summary, summary_table); - if (old) - ospf6_lsa_purge (old); - return; + ospf6_abr_delete_route (route, summary, summary_table, old); + return 0; } - /* Whether the route have active longer prefix */ + /* If there are no active prefixes in this range, remove */ if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) { if (is_debug) zlog_debug ("The range is not active. withdraw"); - if (summary) - ospf6_route_remove (summary, summary_table); - if (old) - ospf6_lsa_purge (old); - return; + ospf6_abr_delete_route (route, summary, summary_table, old); + return 0; } } @@ -359,7 +398,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, buf, sizeof(buf)); zlog_debug ("prefix %s was denied by export list", buf); } - return; + return 0; } } @@ -380,7 +419,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, buf, sizeof (buf)); zlog_debug ("prefix %s was denied by filter-list out", buf); } - return; + return 0; } } @@ -388,16 +427,25 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, if (summary == NULL) { summary = ospf6_route_copy (route); - if (route->type == OSPF6_DEST_TYPE_NETWORK || - route->type == OSPF6_DEST_TYPE_RANGE) - summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX); - else - summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER); summary->path.origin.adv_router = area->ospf6->router_id; - summary->path.origin.id = - ospf6_new_ls_id (summary->path.origin.type, - summary->path.origin.adv_router, area->lsdb); + + if (route->type == OSPF6_DEST_TYPE_ROUTER) + { + summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER); + summary->path.origin.id = ADV_ROUTER_IN_PREFIX (&route->prefix); + } + else + { + summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX); + if (route->type == OSPF6_DEST_TYPE_RANGE) + summary->path.origin.id = route->linkstate_id; + else + summary->path.origin.id = + ospf6_new_ls_id (summary->path.origin.type, + summary->path.origin.adv_router, area->lsdb); + } summary = ospf6_route_add (summary, summary_table); + } else { @@ -413,7 +461,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, summary->path.area_id = area->area_id; summary->path.type = OSPF6_PATH_TYPE_INTER; summary->path.cost = route->path.cost; - summary->nexthop[0] = route->nexthop[0]; + /* summary->nexthop[0] = route->nexthop[0]; */ /* prepare buffer */ memset (buffer, 0, sizeof (buffer)); @@ -470,35 +518,100 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, /* Originate */ ospf6_lsa_originate_area (lsa, area); + + return 1; } -static void +void ospf6_abr_range_update (struct ospf6_route *range) { u_int32_t cost = 0; struct ospf6_route *ro; + int gen_range_summary = 0; + char buf[INET6_ADDRSTRLEN]; assert (range->type == OSPF6_DEST_TYPE_RANGE); + prefix2str (&range->prefix, buf, sizeof (buf)); - /* update range's cost and active flag */ - for (ro = ospf6_route_match_head (&range->prefix, ospf6->route_table); - ro; ro = ospf6_route_match_next (&range->prefix, ro)) + if (CHECK_FLAG(range->flag, OSPF6_ROUTE_REMOVE)) { - if (ro->path.area_id == range->path.area_id && - ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE)) - cost = MAX (cost, ro->path.cost); + UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); + gen_range_summary = 1; } - - if (range->path.cost != cost) + else { - range->path.cost = cost; + /* update range's cost and active flag */ + for (ro = ospf6_route_match_head (&range->prefix, ospf6->route_table); + ro; ro = ospf6_route_match_next (&range->prefix, ro)) + { + if (ro->path.area_id == range->path.area_id && + (ro->path.type == OSPF6_PATH_TYPE_INTRA) && + ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE)) + cost = MAX (cost, ro->path.cost); + } + } - if (range->path.cost) - SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); + /* Non-zero cost is a proxy for active longer prefixes in this range. + * If there are active routes covered by this range AND either the configured + * cost has changed or the summarized cost has changed then redo summaries. + * Alternately, if there are no longer active prefixes and there are + * summary announcements, withdraw those announcements. + * + * The don't advertise code relies on the path.cost being set to UNSPEC to + * work the first time. Subsequent times the path.cost is not 0 anyway if there + * were active ranges. + */ + if (CHECK_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) + { + if (range->path.cost != 0) + { + range->path.cost = 0; + gen_range_summary = 1; + } + } + else if (cost && + (((range->path.u.cost_config != OSPF_AREA_RANGE_COST_UNSPEC) && + (range->path.cost != range->path.u.cost_config)) || + ((range->path.u.cost_config == OSPF_AREA_RANGE_COST_UNSPEC) && + (range->path.cost != cost)))) + { + if (range->path.u.cost_config == OSPF_AREA_RANGE_COST_UNSPEC) + { + range->path.cost = cost; + } else - UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); + { + range->path.cost = range->path.u.cost_config; + } + SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); + gen_range_summary = 1; + } + else if (!cost && CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) + { + UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); + range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC; + gen_range_summary = 1; + } + + if (gen_range_summary) + { ospf6_abr_originate_summary (range); + + if (CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) + { + if (IS_OSPF6_DEBUG_ABR) + zlog_debug ("Add discard route"); + + ospf6_zebra_add_discard (range); + } + else + { + if (IS_OSPF6_DEBUG_ABR) + zlog_debug ("Delete discard route"); + + ospf6_zebra_delete_discard (range); + } } } @@ -514,7 +627,9 @@ ospf6_abr_originate_summary (struct ospf6_route *route) oa = ospf6_area_lookup (route->path.area_id, ospf6); range = ospf6_route_lookup_bestmatch (&route->prefix, oa->range_table); if (range) - ospf6_abr_range_update (range); + { + ospf6_abr_range_update (range); + } } for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa)) @@ -534,7 +649,6 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) u_int8_t prefix_options = 0; u_int32_t cost = 0; u_char router_bits = 0; - int i; char buf[64]; int is_debug = 0; struct ospf6_inter_prefix_lsa *prefix_lsa = NULL; @@ -575,6 +689,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) ospf6_linkstate_prefix (router_lsa->router_id, htonl (0), &prefix); if (is_debug) inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf)); + table = oa->ospf6->brouter_table; type = OSPF6_DEST_TYPE_ROUTER; options[0] = router_lsa->options[0]; @@ -600,6 +715,8 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) old = route; route = ospf6_route_next (route); } + if (route) + ospf6_route_unlock (route); /* (1) if cost == LSInfinity or if the LSA is MaxAge */ if (cost == OSPF_LS_INFINITY) @@ -666,8 +783,22 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) zlog_debug ("Prefix has NU/LA bit set, ignore"); if (old) ospf6_route_remove (old, table); + return; } + /* Avoid infinite recursion if someone has maliciously announced an + Inter-Router LSA for an ABR + */ + if (lsa->header->adv_router == router_lsa->router_id) + { + if (is_debug) + zlog_debug ("Ignorning Inter-Router LSA for an ABR (%s)", + buf); + if (old) + ospf6_route_remove (old, table); + + return; + } } /* (4) if the routing table entry for the ABR does not exist */ @@ -718,7 +849,7 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) } } - /* (5),(6),(7) the path preference is handled by the sorting + /* (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) @@ -739,12 +870,33 @@ ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) route->path.area_id = oa->area_id; route->path.type = OSPF6_PATH_TYPE_INTER; route->path.cost = abr_entry->path.cost + cost; - for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) - route->nexthop[i] = abr_entry->nexthop[i]; - if (is_debug) - zlog_debug ("Install route: %s", buf); - ospf6_route_add (route, table); + 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 + are identical. + */ + old = ospf6_route_lookup (&prefix, table); + + if (old && (ospf6_route_cmp (route, old) == 0)) + { + ospf6_route_merge_nexthops (old, route); + /* Update RIB/FIB */ + if (table->hook_add) + (*table->hook_add) (old); + + /* Delete new route */ + ospf6_route_delete (route); + } + else + { + if (is_debug) + zlog_debug ("Install route: %s", buf); + /* ospf6_ia_add_nw_route (table, &prefix, route); */ + ospf6_route_add (route, table); + } } void @@ -752,21 +904,22 @@ ospf6_abr_examin_brouter (u_int32_t router_id) { struct ospf6_lsa *lsa; struct ospf6_area *oa; - struct listnode *node, *nnode; u_int16_t type; - for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa)) - { - type = htons (OSPF6_LSTYPE_INTER_ROUTER); - for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa; - lsa = ospf6_lsdb_type_router_next (type, router_id, lsa)) - ospf6_abr_examin_summary (lsa, oa); + if (ospf6_is_router_abr (ospf6)) + oa = ospf6->backbone; + else + oa = listgetdata(listhead(ospf6->area_list)); - type = htons (OSPF6_LSTYPE_INTER_PREFIX); - for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa; - lsa = ospf6_lsdb_type_router_next (type, router_id, lsa)) - ospf6_abr_examin_summary (lsa, oa); - } + type = htons (OSPF6_LSTYPE_INTER_ROUTER); + for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa; + lsa = ospf6_lsdb_type_router_next (type, router_id, lsa)) + ospf6_abr_examin_summary (lsa, oa); + + type = htons (OSPF6_LSTYPE_INTER_PREFIX); + for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa; + lsa = ospf6_lsdb_type_router_next (type, router_id, lsa)) + ospf6_abr_examin_summary (lsa, oa); } void |
