diff options
Diffstat (limited to 'ospf6d')
-rw-r--r-- | ospf6d/ospf6_abr.c | 553 | ||||
-rw-r--r-- | ospf6d/ospf6_abr.h | 7 | ||||
-rw-r--r-- | ospf6d/ospf6_area.c | 323 | ||||
-rw-r--r-- | ospf6d/ospf6_area.h | 7 | ||||
-rw-r--r-- | ospf6d/ospf6_asbr.c | 92 | ||||
-rw-r--r-- | ospf6d/ospf6_asbr.h | 1 | ||||
-rw-r--r-- | ospf6d/ospf6_flood.c | 5 | ||||
-rw-r--r-- | ospf6d/ospf6_flood.h | 2 | ||||
-rw-r--r-- | ospf6d/ospf6_interface.c | 78 | ||||
-rw-r--r-- | ospf6d/ospf6_interface.h | 8 | ||||
-rw-r--r-- | ospf6d/ospf6_intra.c | 142 | ||||
-rw-r--r-- | ospf6d/ospf6_lsa.h | 1 | ||||
-rw-r--r-- | ospf6d/ospf6_lsdb.c | 35 | ||||
-rw-r--r-- | ospf6d/ospf6_lsdb.h | 4 | ||||
-rw-r--r-- | ospf6d/ospf6_main.c | 4 | ||||
-rw-r--r-- | ospf6d/ospf6_message.c | 14 | ||||
-rw-r--r-- | ospf6d/ospf6_network.c | 10 | ||||
-rw-r--r-- | ospf6d/ospf6_network.h | 2 | ||||
-rw-r--r-- | ospf6d/ospf6_route.c | 291 | ||||
-rw-r--r-- | ospf6d/ospf6_route.h | 56 | ||||
-rw-r--r-- | ospf6d/ospf6_spf.c | 154 | ||||
-rw-r--r-- | ospf6d/ospf6_spf.h | 6 | ||||
-rw-r--r-- | ospf6d/ospf6_top.c | 10 | ||||
-rw-r--r-- | ospf6d/ospf6_zebra.c | 109 | ||||
-rw-r--r-- | ospf6d/ospf6_zebra.h | 2 | ||||
-rw-r--r-- | ospf6d/ospf6d.c | 8 |
26 files changed, 1506 insertions, 418 deletions
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index bb79900e..33299f48 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,53 +68,56 @@ 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_IS_MAXAGE (old)) + ospf6_lsa_purge (old); +} + void ospf6_abr_enable_area (struct ospf6_area *area) { struct ospf6_area *oa; - struct ospf6_route *ro; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (area->ospf6->area_list, node, nnode, oa)) - { - /* update B bit for each area */ - OSPF6_ROUTER_LSA_SCHEDULE (oa); - - /* install other area's configured address range */ - if (oa != area) - { - for (ro = ospf6_route_head (oa->range_table); ro; - ro = ospf6_route_next (ro)) - { - if (CHECK_FLAG (ro->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) - ospf6_abr_originate_summary_to_area (ro, area); - } - } - } - - /* install calculated routes to border routers */ - for (ro = ospf6_route_head (area->ospf6->brouter_table); ro; - ro = ospf6_route_next (ro)) - ospf6_abr_originate_summary_to_area (ro, area); - - /* install calculated routes to network (may be rejected by ranges) */ - for (ro = ospf6_route_head (area->ospf6->route_table); ro; - ro = ospf6_route_next (ro)) - ospf6_abr_originate_summary_to_area (ro, area); + /* update B bit for each area */ + OSPF6_ROUTER_LSA_SCHEDULE (oa); } void ospf6_abr_disable_area (struct ospf6_area *area) { struct ospf6_area *oa; - struct ospf6_route *ro; + struct ospf6_route *ro, *nro; struct ospf6_lsa *old; struct listnode *node, *nnode; /* Withdraw all summary prefixes previously originated */ - for (ro = ospf6_route_head (area->summary_prefix); ro; - ro = ospf6_route_next (ro)) + for (ro = ospf6_route_head (area->summary_prefix); ro; ro = nro) { + nro = ospf6_route_next (ro); old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, area->ospf6->router_id, area->lsdb); if (old) @@ -122,9 +126,9 @@ ospf6_abr_disable_area (struct ospf6_area *area) } /* Withdraw all summary router-routes previously originated */ - for (ro = ospf6_route_head (area->summary_router); ro; - ro = ospf6_route_next (ro)) + for (ro = ospf6_route_head (area->summary_router); ro; ro = nro) { + nro = ospf6_route_next (ro); old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, area->ospf6->router_id, area->lsdb); if (old) @@ -139,12 +143,13 @@ ospf6_abr_disable_area (struct ospf6_area *area) } /* RFC 2328 12.4.3. Summary-LSAs */ -void +/* Returns 1 if a summary LSA has been generated for the area */ +/* This is used by the area/range logic to add/remove blackhole routes */ +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 +162,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 +245,62 @@ 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"); + + ospf6_abr_delete_route (route, summary, summary_table, old); + return 0; } - /* 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 (area->no_summary && (route->path.subtype != OSPF6_PATH_SUBTYPE_DEFAULT_RT)) { 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; + zlog_debug ("Area has been stubbed, purge prefix LSA"); + + 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 +311,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 +341,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 +354,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 +385,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 +406,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,15 +414,23 @@ 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 @@ -412,8 +446,9 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, summary->path.prefix_options = route->path.prefix_options; summary->path.area_id = area->area_id; summary->path.type = OSPF6_PATH_TYPE_INTER; + summary->path.subtype = route->path.subtype; 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 +505,138 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route, /* Originate */ ospf6_lsa_originate_area (lsa, area); + + return 1; +} + +void +ospf6_abr_range_reset_cost (struct ospf6 *ospf6) +{ + struct listnode *node, *nnode; + struct ospf6_area *oa; + struct ospf6_route *range; + + for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa)) + for (range = ospf6_route_head (oa->range_table); range; + range = ospf6_route_next (range)) + OSPF6_ABR_RANGE_CLEAR_COST(range); +} + +static inline u_int32_t +ospf6_abr_range_compute_cost (struct ospf6_route *range, struct ospf6 *o) +{ + struct ospf6_route *ro; + u_int32_t cost = 0; + + for (ro = ospf6_route_match_head (&range->prefix, o->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); + } + + return cost; +} + +static inline int +ospf6_abr_range_summary_needs_update (struct ospf6_route *range, + u_int32_t cost) +{ + int redo_summary = 0; + + if (CHECK_FLAG(range->flag, OSPF6_ROUTE_REMOVE)) + { + UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); + redo_summary = 1; + } + else if (CHECK_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) + { + if (range->path.cost != 0) + { + range->path.cost = 0; + redo_summary = 1; + } + } + else if (cost) + { + if ((OSPF6_PATH_COST_IS_CONFIGURED(range->path) && + range->path.cost != range->path.u.cost_config)) + { + range->path.cost = range->path.u.cost_config; + SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); + redo_summary = 1; + } + else if (!OSPF6_PATH_COST_IS_CONFIGURED(range->path) && + range->path.cost != cost) + { + range->path.cost = cost; + SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); + redo_summary = 1; + } + } + else if (CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) + { + /* Cost is zero, meaning no active range */ + UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); + range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC; + redo_summary = 1; + } + + return (redo_summary); } static void ospf6_abr_range_update (struct ospf6_route *range) { u_int32_t cost = 0; - struct ospf6_route *ro; + struct listnode *node, *nnode; + struct ospf6_area *oa; + int summary_orig = 0; assert (range->type == OSPF6_DEST_TYPE_RANGE); /* 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)) + cost = ospf6_abr_range_compute_cost (range, ospf6); + + /* 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 (ospf6_abr_range_summary_needs_update (range, cost)) { - if (ro->path.area_id == range->path.area_id && - ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE)) - cost = MAX (cost, ro->path.cost); - } + for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa)) + summary_orig += ospf6_abr_originate_summary_to_area (range, oa); - if (range->path.cost != cost) - { - range->path.cost = cost; + if (CHECK_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY) && summary_orig) + { + if (! CHECK_FLAG (range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) + { + if (IS_OSPF6_DEBUG_ABR) + zlog_debug ("Add discard route"); - if (range->path.cost) - SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); + ospf6_zebra_add_discard (range); + } + } else - UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); - - ospf6_abr_originate_summary (range); + { + /* Summary removed or no summary generated as no specifics exist */ + if (CHECK_FLAG (range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) + { + if (IS_OSPF6_DEBUG_ABR) + zlog_debug ("Delete discard route"); + + ospf6_zebra_delete_discard (range); + } + } } } @@ -514,13 +652,63 @@ 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)) ospf6_abr_originate_summary_to_area (route, oa); } +void +ospf6_abr_defaults_to_stub (struct ospf6 *o) +{ + struct listnode *node, *nnode; + struct ospf6_area *oa; + struct ospf6_route *def, *route; + + if (!o->backbone) + return; + + def = ospf6_route_create(); + def->type = OSPF6_DEST_TYPE_NETWORK; + def->prefix.family = AF_INET6; + def->prefix.prefixlen = 0; + memset (&def->prefix.u.prefix6, 0, sizeof(struct in6_addr)); + def->type = OSPF6_DEST_TYPE_NETWORK; + def->path.type = OSPF6_PATH_TYPE_INTER; + def->path.subtype = OSPF6_PATH_SUBTYPE_DEFAULT_RT; + def->path.area_id = o->backbone->area_id; + + for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa)) + { + if (!IS_AREA_STUB (oa)) + { + /* withdraw defaults when an area switches from stub to non-stub */ + route = ospf6_route_lookup (&def->prefix, oa->summary_prefix); + if (route && (route->path.subtype == def->path.subtype)) + { + if (IS_OSPF6_DEBUG_ABR) + zlog_debug ("Withdrawing default route from non-stubby area %s", + oa->name); + SET_FLAG (def->flag, OSPF6_ROUTE_REMOVE); + ospf6_abr_originate_summary_to_area (def, oa); + } + } + else + { + /* announce defaults to stubby areas */ + if (IS_OSPF6_DEBUG_ABR) + zlog_debug ("Announcing default route into stubby area %s", + oa->name); + UNSET_FLAG (def->flag, OSPF6_ROUTE_REMOVE); + ospf6_abr_originate_summary_to_area (def, oa); + } + } + ospf6_route_delete (def); +} + /* RFC 2328 16.2. Calculating the inter-area routes */ void ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) @@ -534,7 +722,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 +762,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 +788,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 +856,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 +922,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 +943,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 +977,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 @@ -786,6 +1012,21 @@ ospf6_abr_reimport (struct ospf6_area *oa) ospf6_abr_examin_summary (lsa, oa); } +void +ospf6_abr_prefix_resummarize (struct ospf6 *o) +{ + struct ospf6_route *route; + + if (IS_OSPF6_DEBUG_ABR) + zlog_debug ("Re-examining Inter-Prefix Summaries"); + + for (route = ospf6_route_head (o->route_table); route; + route = ospf6_route_next (route)) + ospf6_abr_originate_summary(route); + + if (IS_OSPF6_DEBUG_ABR) + zlog_debug ("Finished re-examining Inter-Prefix Summaries"); +} /* Display functions */ diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h index e5e2660b..5bc2469e 100644 --- a/ospf6d/ospf6_abr.h +++ b/ospf6d/ospf6_abr.h @@ -59,17 +59,22 @@ struct ospf6_inter_router_lsa { (E)->metric &= htonl (0x00000000); \ (E)->metric |= htonl (0x00ffffff) & htonl (C); } +#define OSPF6_ABR_RANGE_CLEAR_COST(range) (range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC) + extern int ospf6_is_router_abr (struct ospf6 *o); extern void ospf6_abr_enable_area (struct ospf6_area *oa); extern void ospf6_abr_disable_area (struct ospf6_area *oa); -extern void ospf6_abr_originate_summary_to_area (struct ospf6_route *route, +extern int ospf6_abr_originate_summary_to_area (struct ospf6_route *route, struct ospf6_area *area); extern void ospf6_abr_originate_summary (struct ospf6_route *route); extern void ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa); +extern void ospf6_abr_defaults_to_stub (struct ospf6 *); extern void ospf6_abr_examin_brouter (u_int32_t router_id); extern void ospf6_abr_reimport (struct ospf6_area *oa); +extern void ospf6_abr_range_reset_cost (struct ospf6 *ospf6); +extern void ospf6_abr_prefix_resummarize (struct ospf6 *ospf6); extern int config_write_ospf6_debug_abr (struct vty *vty); extern void install_element_ospf6_debug_abr (void); diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 9b704221..71787541 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -43,6 +43,7 @@ #include "ospf6_interface.h" #include "ospf6_intra.h" #include "ospf6_abr.h" +#include "ospf6_asbr.h" #include "ospf6d.h" int @@ -133,12 +134,82 @@ ospf6_area_route_hook_remove (struct ospf6_route *route) ospf6_route_remove (copy, ospf6->route_table); } +static void +ospf6_area_stub_update (struct ospf6_area *area) +{ + + if (IS_AREA_STUB (area)) + { + if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER)) + zlog_debug ("Stubbing out area for if %s\n", area->name); + OSPF6_OPT_CLEAR (area->options, OSPF6_OPT_E); + } + else if (IS_AREA_ENABLED (area)) + { + if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER)) + zlog_debug ("Normal area for if %s\n", area->name); + OSPF6_OPT_SET (area->options, OSPF6_OPT_E); + ospf6_asbr_send_externals_to_area (area); + } + + OSPF6_ROUTER_LSA_SCHEDULE(area); +} + +static int +ospf6_area_stub_set (struct ospf6 *ospf6, struct ospf6_area *area) +{ + if (!IS_AREA_STUB(area)) + { + SET_FLAG (area->flag, OSPF6_AREA_STUB); + ospf6_area_stub_update (area); + } + + return (1); +} + +static void +ospf6_area_stub_unset (struct ospf6 *ospf6, struct ospf6_area *area) +{ + if (IS_AREA_STUB (area)) + { + UNSET_FLAG (area->flag, OSPF6_AREA_STUB); + ospf6_area_stub_update (area); + } +} + +static void +ospf6_area_no_summary_set (struct ospf6 *ospf6, struct ospf6_area *area) +{ + if (area) + { + if (!area->no_summary) + { + area->no_summary = 1; + ospf6_abr_range_reset_cost (ospf6); + ospf6_abr_prefix_resummarize (ospf6); + } + } +} + +static void +ospf6_area_no_summary_unset (struct ospf6 *ospf6, struct ospf6_area *area) +{ + if (area) + { + if (area->no_summary) + { + area->no_summary = 0; + ospf6_abr_range_reset_cost (ospf6); + ospf6_abr_prefix_resummarize (ospf6); + } + } +} + /* Make new area structure */ struct ospf6_area * ospf6_area_create (u_int32_t area_id, struct ospf6 *o) { struct ospf6_area *oa; - struct ospf6_route *route; oa = XCALLOC (MTYPE_OSPF6_AREA, sizeof (struct ospf6_area)); @@ -160,6 +231,7 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o) oa->range_table = OSPF6_ROUTE_TABLE_CREATE (AREA, PREFIX_RANGES); oa->range_table->scope = oa; + bf_init(oa->range_table->idspace, 32); oa->summary_prefix = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_PREFIXES); oa->summary_prefix->scope = oa; oa->summary_router = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_ROUTERS); @@ -179,13 +251,16 @@ ospf6_area_create (u_int32_t area_id, struct ospf6 *o) OSPF6_OPT_SET (oa->options, OSPF6_OPT_E); + SET_FLAG (oa->flag, OSPF6_AREA_ACTIVE); + SET_FLAG (oa->flag, OSPF6_AREA_ENABLE); + oa->ospf6 = o; listnode_add_sort (o->area_list, oa); - /* import athoer area's routes as inter-area routes */ - for (route = ospf6_route_head (o->route_table); route; - route = ospf6_route_next (route)) - ospf6_abr_originate_summary_to_area (route, oa); + if (area_id == OSPF_AREA_BACKBONE) + { + o->backbone = oa; + } return oa; } @@ -196,10 +271,6 @@ ospf6_area_delete (struct ospf6_area *oa) struct listnode *n; struct ospf6_interface *oi; - ospf6_route_table_delete (oa->range_table); - ospf6_route_table_delete (oa->summary_prefix); - ospf6_route_table_delete (oa->summary_router); - /* The ospf6_interface structs store configuration * information which should not be lost/reset when * deleting an area. @@ -217,8 +288,9 @@ ospf6_area_delete (struct ospf6_area *oa) ospf6_route_table_delete (oa->spf_table); ospf6_route_table_delete (oa->route_table); - THREAD_OFF (oa->thread_spf_calculation); - THREAD_OFF (oa->thread_route_calculation); + ospf6_route_table_delete (oa->range_table); + ospf6_route_table_delete (oa->summary_prefix); + ospf6_route_table_delete (oa->summary_router); listnode_delete (oa->ospf6->area_list, oa); oa->ospf6 = NULL; @@ -281,9 +353,6 @@ ospf6_area_disable (struct ospf6_area *oa) ospf6_spf_table_finish(oa->spf_table); ospf6_route_remove_all(oa->route_table); - THREAD_OFF (oa->thread_spf_calculation); - THREAD_OFF (oa->thread_route_calculation); - THREAD_OFF (oa->thread_router_lsa); THREAD_OFF (oa->thread_intra_prefix_lsa); } @@ -294,16 +363,46 @@ ospf6_area_show (struct vty *vty, struct ospf6_area *oa) { struct listnode *i; struct ospf6_interface *oi; + unsigned long result; - vty_out (vty, " Area %s%s", oa->name, VNL); + if (!IS_AREA_STUB (oa)) + vty_out (vty, " Area %s%s", oa->name, VNL); + else + { + if (oa->no_summary) + { + vty_out (vty, " Area %s[Stub, No Summary]%s", oa->name, VNL); + } + else + { + vty_out (vty, " Area %s[Stub]%s", oa->name, VNL); + } + } vty_out (vty, " Number of Area scoped LSAs is %u%s", oa->lsdb->count, VNL); vty_out (vty, " Interface attached to this area:"); for (ALL_LIST_ELEMENTS_RO (oa->if_list, i, oi)) vty_out (vty, " %s", oi->interface->name); - vty_out (vty, "%s", VNL); + + if (oa->ts_spf.tv_sec || oa->ts_spf.tv_usec) + { + result = timeval_elapsed (recent_relative_time (), oa->ts_spf); + if (result/TIMER_SECOND_MICRO > 0) + { + vty_out (vty, "SPF last executed %ld.%lds ago%s", + result/TIMER_SECOND_MICRO, + result%TIMER_SECOND_MICRO, VTY_NEWLINE); + } + else + { + vty_out (vty, "SPF last executed %ldus ago%s", + result, VTY_NEWLINE); + } + } + else + vty_out (vty, "SPF has not been run%s", VTY_NEWLINE); } @@ -347,19 +446,16 @@ DEFUN (area_range, struct ospf6_area *oa; struct prefix prefix; struct ospf6_route *range; + u_int32_t cost = OSPF_AREA_RANGE_COST_UNSPEC; OSPF6_CMD_AREA_GET (argv[0], oa); - argc--; - argv++; - ret = str2prefix (argv[0], &prefix); + ret = str2prefix (argv[1], &prefix); if (ret != 1 || prefix.family != AF_INET6) { - vty_out (vty, "Malformed argument: %s%s", argv[0], VNL); + vty_out (vty, "Malformed argument: %s%s", argv[1], VNL); return CMD_SUCCESS; } - argc--; - argv++; range = ospf6_route_lookup (&prefix, oa->range_table); if (range == NULL) @@ -367,23 +463,43 @@ DEFUN (area_range, range = ospf6_route_create (); range->type = OSPF6_DEST_TYPE_RANGE; range->prefix = prefix; + range->path.area_id = oa->area_id; + range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC; + range->linkstate_id = + (u_int32_t) htonl(ospf6_new_range_ls_id (oa->range_table)); } - if (argc) + if (argc > 2) { - if (! strcmp (argv[0], "not-advertise")) - SET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE); - else if (! strcmp (argv[0], "advertise")) - UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE); + if (strcmp (argv[2], "not-advertise") == 0) + { + SET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE); + } + else if (strcmp (argv[2], "advertise") == 0) + { + UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE); + } + else + { + VTY_GET_INTEGER_RANGE ("cost", cost, argv[2], 0, OSPF_LS_INFINITY); + UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE); + } } - if (range->rnode) + range->path.u.cost_config = cost; + + zlog_debug ("%s: for prefix %s, flag = %x\n", __func__, argv[1], range->flag); + if (range->rnode == NULL) { - vty_out (vty, "Range already defined: %s%s", argv[-1], VNL); - return CMD_WARNING; + ospf6_route_add (range, oa->range_table); + } + + if (ospf6_is_router_abr (ospf6)) + { + /* Redo summaries if required */ + ospf6_abr_prefix_resummarize (ospf6); } - ospf6_route_add (range, oa->range_table); return CMD_SUCCESS; } @@ -396,6 +512,26 @@ ALIAS (area_range, "Specify IPv6 prefix\n" ) +ALIAS (area_range, + area_range_cost_cmd, + "area (A.B.C.D|<0-4294967295>) range X:X::X:X/M cost <0-16777215>", + "OSPF area parameters\n" + OSPF6_AREA_ID_STR + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "User specified metric for this range\n" + "Advertised metric for this range\n") + +ALIAS (area_range, + area_range_advertise_cost_cmd, + "area (A.B.C.D|<0-4294967295>) range X:X::X:X/M advertise cost <0-16777215>", + "OSPF area parameters\n" + OSPF6_AREA_ID_STR + "Summarize routes matching address/mask (border routers only)\n" + "Area range prefix\n" + "User specified metric for this range\n" + "Advertised metric for this range\n") + DEFUN (no_area_range, no_area_range_cmd, "no area A.B.C.D range X:X::X:X/M", @@ -408,7 +544,7 @@ DEFUN (no_area_range, int ret; struct ospf6_area *oa; struct prefix prefix; - struct ospf6_route *range; + struct ospf6_route *range, *route; OSPF6_CMD_AREA_GET (argv[0], oa); argc--; @@ -428,6 +564,21 @@ DEFUN (no_area_range, return CMD_SUCCESS; } + if (ospf6_is_router_abr(oa->ospf6)) + { + /* Blow away the aggregated LSA and route */ + SET_FLAG (range->flag, OSPF6_ROUTE_REMOVE); + + /* Redo summaries if required */ + for (route = ospf6_route_head (ospf6->route_table); route; + route = ospf6_route_next (route)) + ospf6_abr_originate_summary(route); + + /* purge the old aggregated summary LSA */ + ospf6_abr_originate_summary(range); + } + ospf6_release_range_ls_id(oa->range_table, + (u_int32_t) ntohl(range->linkstate_id)); ospf6_route_remove (range, oa->range_table); return CMD_SUCCESS; @@ -449,6 +600,13 @@ ospf6_area_config_write (struct vty *vty) prefix2str (&range->prefix, buf, sizeof (buf)); vty_out (vty, " area %s range %s%s", oa->name, buf, VNL); } + if (IS_AREA_STUB (oa)) + { + if (oa->no_summary) + vty_out (vty, " area %s stub no-summary%s", oa->name, VNL); + else + vty_out (vty, " area %s stub%s", oa->name, VNL); + } if (PREFIX_NAME_IN (oa)) vty_out (vty, " area %s filter-list prefix %s in%s", oa->name, PREFIX_NAME_IN (oa), VNL); @@ -666,6 +824,8 @@ DEFUN (show_ipv6_ospf6_spf_tree, struct ospf6_route *route; struct prefix prefix; + OSPF6_CMD_CHECK_RUNNING (); + ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) @@ -701,6 +861,8 @@ DEFUN (show_ipv6_ospf6_area_spf_tree, struct ospf6_route *route; struct prefix prefix; + OSPF6_CMD_CHECK_RUNNING (); + ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix); if (inet_pton (AF_INET, argv[0], &area_id) != 1) @@ -747,6 +909,8 @@ DEFUN (show_ipv6_ospf6_simulate_spf_tree_root, struct ospf6_route_table *spf_table; unsigned char tmp_debug_ospf6_spf = 0; + OSPF6_CMD_CHECK_RUNNING (); + inet_pton (AF_INET, argv[0], &router_id); ospf6_linkstate_prefix (router_id, htonl (0), &prefix); @@ -786,6 +950,94 @@ DEFUN (show_ipv6_ospf6_simulate_spf_tree_root, return CMD_SUCCESS; } +DEFUN (ospf6_area_stub, + ospf6_area_stub_cmd, + "area (A.B.C.D|<0-4294967295>) stub", + "OSPF6 area parameters\n" + "OSPF6 area ID in IP address format\n" + "OSPF6 area ID as a decimal value\n" + "Configure OSPF6 area as stub\n") +{ + struct ospf6_area *area; + + OSPF6_CMD_AREA_GET(argv[0], area); + + if (!ospf6_area_stub_set (ospf6, area)) + { + vty_out (vty, "First deconfigure all virtual link through this area%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ospf6_area_no_summary_unset (ospf6, area); + + return CMD_SUCCESS; +} + +DEFUN (ospf6_area_stub_no_summary, + ospf6_area_stub_no_summary_cmd, + "area (A.B.C.D|<0-4294967295>) stub no-summary", + "OSPF6 stub parameters\n" + "OSPF6 area ID in IP address format\n" + "OSPF6 area ID as a decimal value\n" + "Configure OSPF6 area as stub\n" + "Do not inject inter-area routes into stub\n") +{ + struct ospf6_area *area; + + OSPF6_CMD_AREA_GET(argv[0], area); + + if (!ospf6_area_stub_set (ospf6, area)) + { + vty_out (vty, "First deconfigure all virtual link through this area%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + ospf6_area_no_summary_set (ospf6, area); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_area_stub, + no_ospf6_area_stub_cmd, + "no area (A.B.C.D|<0-4294967295>) stub", + NO_STR + "OSPF6 area parameters\n" + "OSPF6 area ID in IP address format\n" + "OSPF6 area ID as a decimal value\n" + "Configure OSPF6 area as stub\n") +{ + struct ospf6_area *area; + + OSPF6_CMD_AREA_GET(argv[0], area); + + ospf6_area_stub_unset (ospf6, area); + ospf6_area_no_summary_unset (ospf6, area); + + return CMD_SUCCESS; +} + +DEFUN (no_ospf6_area_stub_no_summary, + no_ospf6_area_stub_no_summary_cmd, + "no area (A.B.C.D|<0-4294967295>) stub no-summary", + NO_STR + "OSPF6 area parameters\n" + "OSPF6 area ID in IP address format\n" + "OSPF6 area ID as a decimal value\n" + "Configure OSPF6 area as stub\n" + "Do not inject inter-area routes into area\n") +{ + struct ospf6_area *area; + + OSPF6_CMD_AREA_GET(argv[0], area); + + ospf6_area_stub_unset (ospf6, area); + ospf6_area_no_summary_unset (ospf6, area); + + return CMD_SUCCESS; +} + void ospf6_area_init (void) { @@ -799,7 +1051,14 @@ ospf6_area_init (void) install_element (OSPF6_NODE, &area_range_cmd); install_element (OSPF6_NODE, &area_range_advertise_cmd); + install_element (OSPF6_NODE, &area_range_cost_cmd); + install_element (OSPF6_NODE, &area_range_advertise_cost_cmd); install_element (OSPF6_NODE, &no_area_range_cmd); + install_element (OSPF6_NODE, &ospf6_area_stub_no_summary_cmd); + install_element (OSPF6_NODE, &ospf6_area_stub_cmd); + install_element (OSPF6_NODE, &no_ospf6_area_stub_no_summary_cmd); + install_element (OSPF6_NODE, &no_ospf6_area_stub_cmd); + install_element (OSPF6_NODE, &area_import_list_cmd); install_element (OSPF6_NODE, &no_area_import_list_cmd); diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index 655967a9..3b752d94 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -46,6 +46,9 @@ struct ospf6_area struct ospf6_route_table *summary_prefix; struct ospf6_route_table *summary_router; + /* Area type */ + int no_summary; + /* OSPF interface list */ struct list *if_list; @@ -55,8 +58,6 @@ struct ospf6_area struct ospf6_route_table *spf_table; struct ospf6_route_table *route_table; - struct thread *thread_spf_calculation; - struct thread *thread_route_calculation; u_int32_t spf_calculation; /* SPF calculation count */ struct thread *thread_router_lsa; @@ -98,6 +99,8 @@ struct ospf6_area #define PREFIX_NAME_OUT(A) (A)->plist_out.name #define PREFIX_LIST_OUT(A) (A)->plist_out.list + /* Time stamps. */ + struct timeval ts_spf; /* SPF calculation time stamp. */ }; #define OSPF6_AREA_ENABLE 0x01 diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 6eca142d..136824bc 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -154,7 +154,6 @@ ospf6_asbr_lsa_add (struct ospf6_lsa *lsa) struct prefix asbr_id; struct ospf6_route *asbr_entry, *route; char buf[64]; - int i; external = (struct ospf6_as_external_lsa *) OSPF6_LSA_HEADER_END (lsa->header); @@ -213,18 +212,17 @@ ospf6_asbr_lsa_add (struct ospf6_lsa *lsa) route->path.type = OSPF6_PATH_TYPE_EXTERNAL2; route->path.metric_type = 2; route->path.cost = asbr_entry->path.cost; - route->path.cost_e2 = OSPF6_ASBR_METRIC (external); + route->path.u.cost_e2 = OSPF6_ASBR_METRIC (external); } else { route->path.type = OSPF6_PATH_TYPE_EXTERNAL1; route->path.metric_type = 1; route->path.cost = asbr_entry->path.cost + OSPF6_ASBR_METRIC (external); - route->path.cost_e2 = 0; + route->path.u.cost_e2 = 0; } - for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) - ospf6_nexthop_copy (&route->nexthop[i], &asbr_entry->nexthop[i]); + ospf6_route_copy_nexthops (route, asbr_entry); if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) { @@ -240,7 +238,7 @@ ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; struct prefix prefix; - struct ospf6_route *route; + struct ospf6_route *route, *nroute; char buf[64]; external = (struct ospf6_as_external_lsa *) @@ -274,8 +272,9 @@ ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa) for (ospf6_route_lock (route); route && ospf6_route_is_prefix (&prefix, route); - route = ospf6_route_next (route)) + route = nroute) { + nroute = ospf6_route_next (route); if (route->type != OSPF6_DEST_TYPE_NETWORK) continue; if (route->path.origin.type != lsa->header->type) @@ -403,13 +402,29 @@ ospf6_asbr_redistribute_unset (int type) if (info->type != type) continue; - ospf6_asbr_redistribute_remove (info->type, route->nexthop[0].ifindex, - &route->prefix); + ospf6_asbr_redistribute_remove (info->type, 0, &route->prefix); } ospf6_asbr_routemap_unset (type); } +/* When an area is unstubified, flood all the external LSAs in the area */ +void +ospf6_asbr_send_externals_to_area (struct ospf6_area *oa) +{ + struct ospf6_lsa *lsa; + + for (lsa = ospf6_lsdb_head (oa->ospf6->lsdb); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + if (ntohs (lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) + { + zlog_debug ("%s: Flooding AS-External LSA %s\n", __func__, lsa->name); + ospf6_flood_area (NULL, lsa, oa); + } + } +} + void ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, u_int nexthop_num, struct in6_addr *nexthop) @@ -483,9 +498,11 @@ ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, } info->type = type; - match->nexthop[0].ifindex = ifindex; + if (nexthop_num && nexthop) - memcpy (&match->nexthop[0].address, nexthop, sizeof (struct in6_addr)); + ospf6_route_add_nexthop (match, ifindex, nexthop); + else + ospf6_route_add_nexthop (match, ifindex, NULL); /* create/update binding in external_id_table */ prefix_id.family = AF_INET; @@ -528,9 +545,10 @@ ospf6_asbr_redistribute_add (int type, ifindex_t ifindex, struct prefix *prefix, } info->type = type; - route->nexthop[0].ifindex = ifindex; if (nexthop_num && nexthop) - memcpy (&route->nexthop[0].address, nexthop, sizeof (struct in6_addr)); + ospf6_route_add_nexthop (route, ifindex, nexthop); + else + ospf6_route_add_nexthop (route, ifindex, NULL); /* create/update binding in external_id_table */ prefix_id.family = AF_INET; @@ -680,6 +698,15 @@ DEFUN (no_ospf6_redistribute, return CMD_SUCCESS; } +ALIAS (no_ospf6_redistribute, + no_ospf6_redistribute_route_map_cmd, + "no redistribute " QUAGGA_REDIST_STR_OSPF6D " route-map WORD", + NO_STR + "Redistribute\n" + QUAGGA_REDIST_HELP_STR_OSPF6D + "Route map reference\n" + "Route map name\n") + int ospf6_redistribute_config_write (struct vty *vty) { @@ -968,13 +995,13 @@ route_map_command_status (struct vty *vty, int ret) switch (ret) { case RMAP_RULE_MISSING: - vty_out (vty, "Can't find rule.%s", VNL); + vty_out (vty, "OSPF6 Can't find rule.%s", VNL); break; case RMAP_COMPILE_ERROR: - vty_out (vty, "Argument is malformed.%s", VNL); + vty_out (vty, "OSPF6 Argument is malformed.%s", VNL); break; default: - vty_out (vty, "route-map add set failed.%s", VNL); + vty_out (vty, "OSPF6 route-map add set failed.%s", VNL); break; } return CMD_WARNING; @@ -1089,17 +1116,30 @@ DEFUN (set_metric, /* delete "set metric" */ DEFUN (no_set_metric, no_set_metric_cmd, - "no set metric <0-4294967295>", + "no set metric", NO_STR - "Set value\n" - "Metric\n" - "METRIC value\n") + SET_STR + "Metric value for destination routing protocol\n") { - int ret = route_map_delete_set ((struct route_map_index *) vty->index, - "metric", argv[0]); + int ret = 0; + + if (argc == 0) + ret = route_map_delete_set ((struct route_map_index *) vty->index, + "metric", NULL); + else + ret = route_map_delete_set ((struct route_map_index *) vty->index, + "metric", argv[0]); return route_map_command_status (vty, ret); } +ALIAS (no_set_metric, + no_set_metric_val_cmd, + "no set metric <0-4294967295>", + NO_STR + SET_STR + "Metric value for destination routing protocol\n" + "Metric value\n") + /* add "set forwarding-address" */ DEFUN (ospf6_routemap_set_forwarding, ospf6_routemap_set_forwarding_cmd, @@ -1158,6 +1198,7 @@ ospf6_routemap_init (void) /* ASE Metric */ install_element (RMAP_NODE, &set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); + install_element (RMAP_NODE, &no_set_metric_val_cmd); /* ASE Metric */ install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd); @@ -1256,13 +1297,13 @@ ospf6_asbr_external_route_show (struct vty *vty, struct ospf6_route *route) inet_ntop (AF_INET6, &info->forwarding, forwarding, sizeof (forwarding)); else snprintf (forwarding, sizeof (forwarding), ":: (ifindex %d)", - route->nexthop[0].ifindex); + ospf6_route_get_first_nh_index (route)); vty_out (vty, "%c %-32s %-15s type-%d %5lu %s%s", zebra_route_char(info->type), prefix, id, route->path.metric_type, (u_long) (route->path.metric_type == 2 ? - route->path.cost_e2 : route->path.cost), + route->path.u.cost_e2 : route->path.cost), forwarding, VNL); } @@ -1277,6 +1318,8 @@ DEFUN (show_ipv6_ospf6_redistribute, { struct ospf6_route *route; + OSPF6_CMD_CHECK_RUNNING (); + ospf6_redistribute_show_config (vty); for (route = ospf6_route_head (ospf6->external_table); route; @@ -1308,6 +1351,7 @@ ospf6_asbr_init (void) install_element (OSPF6_NODE, &ospf6_redistribute_cmd); install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd); install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd); + install_element (OSPF6_NODE, &no_ospf6_redistribute_route_map_cmd); } void diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index f3df90b1..645e8fd9 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -91,6 +91,7 @@ extern int ospf6_redistribute_config_write (struct vty *vty); extern void ospf6_asbr_init (void); extern void ospf6_asbr_redistribute_reset (void); extern void ospf6_asbr_terminate (void); +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); diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 815db7b7..82cf6a6c 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -422,7 +422,7 @@ ospf6_flood_interface (struct ospf6_neighbor *from, } } -static void +void ospf6_flood_area (struct ospf6_neighbor *from, struct ospf6_lsa *lsa, struct ospf6_area *oa) { @@ -892,6 +892,9 @@ ospf6_receive_lsa (struct ospf6_neighbor *from, table calculation (replacing database copy) */ ospf6_install_lsa (new); + if (OSPF6_LSA_IS_MAXAGE (new)) + ospf6_maxage_remove (from->ospf6_if->area->ospf6); + /* (e) possibly acknowledge */ ospf6_acknowledge_lsa (new, ismore_recent, from); diff --git a/ospf6d/ospf6_flood.h b/ospf6d/ospf6_flood.h index 3a6f300b..ba7fd25f 100644 --- a/ospf6d/ospf6_flood.h +++ b/ospf6d/ospf6_flood.h @@ -52,6 +52,8 @@ extern void ospf6_decrement_retrans_count (struct ospf6_lsa *lsa); /* flooding & clear flooding */ extern void ospf6_flood_clear (struct ospf6_lsa *lsa); extern void ospf6_flood (struct ospf6_neighbor *from, struct ospf6_lsa *lsa); +extern void ospf6_flood_area (struct ospf6_neighbor *from, + struct ospf6_lsa *lsa, struct ospf6_area *oa); /* receive & install */ extern void ospf6_receive_lsa (struct ospf6_neighbor *from, diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 26f68ac5..a52da720 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -392,6 +392,7 @@ ospf6_interface_connected_route_update (struct interface *ifp) struct ospf6_route *route; struct connected *c; struct listnode *node, *nnode; + struct in6_addr nh_addr; oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) @@ -447,8 +448,8 @@ ospf6_interface_connected_route_update (struct interface *ifp) route->path.area_id = oi->area->area_id; route->path.type = OSPF6_PATH_TYPE_INTRA; route->path.cost = oi->cost; - route->nexthop[0].ifindex = oi->interface->ifindex; - inet_pton (AF_INET6, "::1", &route->nexthop[0].address); + inet_pton (AF_INET6, "::1", &nh_addr); + ospf6_route_add_nexthop (route, oi->interface->ifindex, &nh_addr); ospf6_route_add (route, oi->route_connected); } @@ -728,7 +729,18 @@ interface_up (struct thread *thread) } /* Join AllSPFRouters */ - ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP); + if (ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP) < 0) + { + if (oi->sso_try_cnt++ < OSPF6_INTERFACE_SSO_RETRY_MAX) + { + zlog_info("Scheduling %s for sso retry, trial count: %d", + oi->interface->name, oi->sso_try_cnt); + thread_add_timer (master, interface_up, oi, + OSPF6_INTERFACE_SSO_RETRY_INT); + } + return 0; + } + oi->sso_try_cnt = 0; /* Reset on success */ /* Update interface route */ ospf6_interface_connected_route_update (oi->interface); @@ -1915,6 +1927,66 @@ ospf6_interface_init (void) install_element (OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd); } +/* Clear the specified interface structure */ +static void +ospf6_interface_clear (struct vty *vty, struct interface *ifp) +{ + struct ospf6_interface *oi; + + if (!if_is_operative (ifp)) + return; + + if (ifp->info == NULL) + return; + + oi = (struct ospf6_interface *) ifp->info; + + if (IS_OSPF6_DEBUG_INTERFACE) + zlog_debug ("Interface %s: clear by reset", ifp->name); + + /* Reset the interface */ + thread_add_event (master, interface_down, oi, 0); + thread_add_event (master, interface_up, oi, 0); +} + +/* Clear interface */ +DEFUN (clear_ipv6_ospf6_interface, + clear_ipv6_ospf6_interface_cmd, + "clear ipv6 ospf6 interface [IFNAME]", + CLEAR_STR + IP6_STR + OSPF6_STR + INTERFACE_STR + IFNAME_STR + ) +{ + struct interface *ifp; + struct listnode *node; + + if (argc == 0) /* Clear all the ospfv3 interfaces. */ + { + for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + ospf6_interface_clear (vty, ifp); + } + else /* Interface name is specified. */ + { + if ((ifp = if_lookup_by_name (argv[0])) == NULL) + { + vty_out (vty, "No such Interface: %s%s", argv[0], VNL); + return CMD_WARNING; + } + ospf6_interface_clear (vty, ifp); + } + + return CMD_SUCCESS; +} + +void +install_element_ospf6_clear_interface (void) +{ + install_element (ENABLE_NODE, &clear_ipv6_ospf6_interface_cmd); +} + DEFUN (debug_ospf6_interface, debug_ospf6_interface_cmd, "debug ospf6 interface", diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 95a377fb..dde589b8 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -78,6 +78,9 @@ struct ospf6_interface /* Interface State */ u_char state; + /* Interface socket setting trial counter, resets on success */ + u_char sso_try_cnt; + /* OSPF6 Interface flag */ char flag; @@ -140,7 +143,8 @@ extern const char *ospf6_interface_state_str[]; #define OSPF6_INTERFACE_INSTANCE_ID 0 #define OSPF6_INTERFACE_BANDWIDTH 10000 /* Kbps */ #define OSPF6_REFERENCE_BANDWIDTH 100000 /* Kbps */ - +#define OSPF6_INTERFACE_SSO_RETRY_INT 1 +#define OSPF6_INTERFACE_SSO_RETRY_MAX 5 /* Function Prototypes */ @@ -166,6 +170,8 @@ extern int neighbor_change (struct thread *); extern void ospf6_interface_init (void); +extern void install_element_ospf6_clear_interface (void); + extern int config_write_ospf6_debug_interface (struct vty *vty); extern void install_element_ospf6_debug_interface (void); diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 6606c96d..f2cade22 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -140,6 +140,31 @@ ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) return 0; } +static void +ospf6_router_lsa_options_set (struct ospf6_area *oa, + struct ospf6_router_lsa *router_lsa) +{ + OSPF6_OPT_CLEAR_ALL (router_lsa->options); + memcpy (router_lsa->options, oa->options, 3); + + if (ospf6_is_router_abr (ospf6)) + SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B); + else + UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B); + + if (!IS_AREA_STUB (oa) && ospf6_asbr_is_asbr (oa->ospf6)) + { + SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E); + } + else + { + UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E); + } + + UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V); + UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W); +} + int ospf6_router_is_stub_router (struct ospf6_lsa *lsa) { @@ -194,23 +219,7 @@ ospf6_router_lsa_originate (struct thread *thread) router_lsa = (struct ospf6_router_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); - OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6); - OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E); - OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC); - OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N); - OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R); - OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC); - - if (ospf6_is_router_abr (ospf6)) - SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B); - else - UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B); - if (ospf6_asbr_is_asbr (ospf6)) - SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E); - else - UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E); - UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V); - UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W); + ospf6_router_lsa_options_set (oa, router_lsa); /* describe links for each interfaces */ lsdesc = (struct ospf6_router_lsdesc *) @@ -228,7 +237,7 @@ ospf6_router_lsa_originate (struct thread *thread) for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on)) if (on->state == OSPF6_NEIGHBOR_FULL) count++; - + if (count == 0) continue; @@ -246,30 +255,6 @@ ospf6_router_lsa_originate (struct thread *thread) return 0; } - /* Fill LSA Header */ - lsa_header->age = 0; - lsa_header->type = htons (OSPF6_LSTYPE_ROUTER); - lsa_header->id = htonl (link_state_id); - lsa_header->adv_router = oa->ospf6->router_id; - lsa_header->seqnum = - ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, - lsa_header->adv_router, oa->lsdb); - lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); - - /* LSA checksum */ - ospf6_lsa_checksum (lsa_header); - - /* create LSA */ - lsa = ospf6_lsa_create (lsa_header); - - /* Originate */ - ospf6_lsa_originate_area (lsa, oa); - - /* Reset setting for consecutive origination */ - memset ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa), - 0, (caddr_t) lsdesc - (caddr_t) router_lsa); - lsdesc = (struct ospf6_router_lsdesc *) - ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa)); link_state_id ++; } @@ -338,7 +323,7 @@ ospf6_router_lsa_originate (struct thread *thread) lsa_header->adv_router = oa->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, - lsa_header->adv_router, oa->lsdb); + lsa_header->adv_router, oa->lsdb); lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); /* LSA checksum */ @@ -355,14 +340,25 @@ ospf6_router_lsa_originate (struct thread *thread) /* Do premature-aging of rest, undesired Router-LSAs */ type = ntohs (OSPF6_LSTYPE_ROUTER); router = oa->ospf6->router_id; + count = 0; for (lsa = ospf6_lsdb_type_router_head (type, router, oa->lsdb); lsa; lsa = ospf6_lsdb_type_router_next (type, router, lsa)) { if (ntohl (lsa->header->id) < link_state_id) continue; ospf6_lsa_purge (lsa); + count++; } + /* + * Waiting till the LSA is actually removed from the database to trigger + * SPF delays network convergence. Unlike IPv4, for an ABR, when all + * interfaces associated with an area are gone, triggering an SPF right away + * helps convergence with inter-area routes. + */ + if (count && !link_state_id) + ospf6_spf_schedule (oa->ospf6, OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED); + return 0; } @@ -459,7 +455,15 @@ ospf6_network_lsa_originate (struct thread *thread) if (oi->state != OSPF6_INTERFACE_DR) { if (old) - ospf6_lsa_purge (old); + { + ospf6_lsa_purge (old); + /* + * Waiting till the LSA is actually removed from the database to + * trigger SPF delays network convergence. + */ + ospf6_spf_schedule (oi->area->ospf6, + OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED); + } return 0; } @@ -468,11 +472,11 @@ ospf6_network_lsa_originate (struct thread *thread) /* If none of neighbor is adjacent to us */ count = 0; - + for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on)) if (on->state == OSPF6_NEIGHBOR_FULL) count++; - + if (count == 0) { if (IS_OSPF6_DEBUG_ORIGINATE (NETWORK)) @@ -1078,7 +1082,7 @@ ospf6_intra_prefix_lsa_originate_transit (struct thread *thread) for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on)) if (on->state == OSPF6_NEIGHBOR_FULL) full_count++; - + if (full_count == 0) { if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) @@ -1214,7 +1218,7 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa) struct ospf6_intra_prefix_lsa *intra_prefix_lsa; struct prefix ls_prefix; struct ospf6_route *route, *ls_entry; - int i, prefix_num; + int prefix_num; struct ospf6_prefix *op; char *start, *current, *end; char buf[64]; @@ -1275,14 +1279,13 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa) break; /* Appendix A.4.1.1 */ - if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU) || - CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_LA)) + if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU)) { if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) { ospf6_linkstate_prefix2str ((struct prefix *)OSPF6_PREFIX_BODY(op), buf, sizeof (buf)); - zlog_debug ("%s: Skipping Prefix %s has NU/LA option set", + zlog_debug ("%s: Skipping Prefix %s has NU option set", __func__, buf); } continue; @@ -1310,13 +1313,11 @@ ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa) { ifp = if_lookup_prefix(&route->prefix); if (ifp) - route->nexthop[0].ifindex = ifp->ifindex; + ospf6_route_add_nexthop (route, ifp->ifindex, NULL); } else { - for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) - ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]); + ospf6_route_copy_nexthops (route, ls_entry); } if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) @@ -1339,7 +1340,7 @@ ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa) struct ospf6_area *oa; struct ospf6_intra_prefix_lsa *intra_prefix_lsa; struct prefix prefix; - struct ospf6_route *route; + struct ospf6_route *route, *nroute; int prefix_num; struct ospf6_prefix *op; char *start, *current, *end; @@ -1377,8 +1378,9 @@ ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa) for (ospf6_route_lock (route); route && ospf6_route_is_prefix (&prefix, route); - route = ospf6_route_next (route)) + route = nroute) { + nroute = ospf6_route_next (route); if (route->type != OSPF6_DEST_TYPE_NETWORK) continue; if (route->path.area_id != oa->area_id) @@ -1408,7 +1410,7 @@ ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa) void ospf6_intra_route_calculation (struct ospf6_area *oa) { - struct ospf6_route *route; + struct ospf6_route *route, *nroute; u_int16_t type; struct ospf6_lsa *lsa; void (*hook_add) (struct ospf6_route *) = NULL; @@ -1435,8 +1437,9 @@ ospf6_intra_route_calculation (struct ospf6_area *oa) oa->route_table->hook_remove = hook_remove; for (route = ospf6_route_head (oa->route_table); route; - route = ospf6_route_next (route)) + route = nroute) { + nroute = ospf6_route_next (route); if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) && CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD)) { @@ -1452,7 +1455,11 @@ ospf6_intra_route_calculation (struct ospf6_area *oa) if (hook_add) (*hook_add) (route); } - + else + { + /* Redo the summaries as things might have changed */ + ospf6_abr_originate_summary (route); + } route->flag = 0; } @@ -1510,13 +1517,13 @@ ospf6_brouter_debug_print (struct ospf6_route *brouter) id, adv_router); zlog_info (" options: %s router-bits: %s metric-type: %d metric: %d/%d", options, capa, brouter->path.metric_type, - brouter->path.cost, brouter->path.cost_e2); + brouter->path.cost, brouter->path.u.cost_e2); } void ospf6_intra_brouter_calculation (struct ospf6_area *oa) { - struct ospf6_route *brouter, *copy; + struct ospf6_route *brouter, *nbrouter, *copy; void (*hook_add) (struct ospf6_route *) = NULL; void (*hook_remove) (struct ospf6_route *) = NULL; u_int32_t brouter_id; @@ -1538,7 +1545,7 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa) inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name)); if (brouter->path.area_id != oa->area_id) continue; - brouter->flag = OSPF6_ROUTE_REMOVE; + SET_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE); if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) || IS_OSPF6_DEBUG_ROUTE (MEMORY)) @@ -1585,8 +1592,9 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa) oa->ospf6->brouter_table->hook_remove = hook_remove; for (brouter = ospf6_route_head (oa->ospf6->brouter_table); brouter; - brouter = ospf6_route_next (brouter)) + brouter = nbrouter) { + nbrouter = ospf6_route_next (brouter); brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix); inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name)); @@ -1631,9 +1639,11 @@ ospf6_intra_brouter_calculation (struct ospf6_area *oa) IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id)) zlog_info ("brouter %s still exists via area %s", brouter_name, oa->name); + /* But re-originate summaries */ + ospf6_abr_originate_summary (brouter); } - - brouter->flag = 0; + UNSET_FLAG (brouter->flag, OSPF6_ROUTE_ADD); + UNSET_FLAG (brouter->flag, OSPF6_ROUTE_CHANGE); } if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id)) diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index a85ca66d..aa64a772 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -141,6 +141,7 @@ struct ospf6_lsa #define OSPF6_LSA_FLOODBACK 0x02 #define OSPF6_LSA_DUPLICATE 0x04 #define OSPF6_LSA_IMPLIEDACK 0x08 +#define OSPF6_LSA_UNAPPROVED 0x10 #define OSPF6_LSA_SEQWRAPPED 0x20 struct ospf6_lsa_handler diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index b5a4587c..d103d23f 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -31,7 +31,9 @@ #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" +#include "ospf6_route.h" #include "ospf6d.h" +#include "bitfield.h" struct ospf6_lsdb * ospf6_lsdb_create (void *data) @@ -545,21 +547,42 @@ ospf6_lsdb_show (struct vty *vty, enum ospf_lsdb_show_level level, } } -/* Decide new Link State ID to originate. - note return value is network byte order */ +/* Decide new Link State ID to originate for the range. */ +u_int32_t +ospf6_new_range_ls_id (struct ospf6_route_table *range_table) +{ + u_int32_t id; + + bf_assign_index(range_table->idspace, id); + return (id); +} + +/* Release the LS ID back to the ID pool */ +void +ospf6_release_range_ls_id (struct ospf6_route_table *range_table, + u_int32_t id) +{ + bf_release_index(range_table->idspace, id); +} + u_int32_t ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router, struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; - u_int32_t id = 1; + u_int32_t id = 1, tmp_id; + /* This routine is curently invoked only for Inter-Prefix LSAs for + * non-summarized routes (no area/range). + */ for (lsa = ospf6_lsdb_type_router_head (type, adv_router, lsdb); lsa; lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa)) { - if (ntohl (lsa->header->id) < id) - continue; - if (ntohl (lsa->header->id) > id) + tmp_id = ntohl (lsa->header->id); + if (tmp_id < id) + continue; + + if (tmp_id > id) { ospf6_lsdb_lsa_unlock (lsa); break; diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h index 425f6153..a8bfcae8 100644 --- a/ospf6d/ospf6_lsdb.h +++ b/ospf6d/ospf6_lsdb.h @@ -24,6 +24,7 @@ #include "prefix.h" #include "table.h" +#include "ospf6_route.h" struct ospf6_lsdb { @@ -80,6 +81,9 @@ extern void ospf6_lsdb_show (struct vty *vty, extern u_int32_t ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router, struct ospf6_lsdb *lsdb); +extern u_int32_t ospf6_new_range_ls_id (struct ospf6_route_table *range_table); +extern void ospf6_release_range_ls_id (struct ospf6_route_table *range_table, + u_int32_t id); extern u_int32_t ospf6_new_ls_seqnum (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb); diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 1afe84a7..11cd195f 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -21,6 +21,7 @@ #include <zebra.h> #include <lib/version.h> +#include <stdlib.h> #include "getopt.h" #include "thread.h" @@ -238,6 +239,9 @@ main (int argc, char *argv[], char *envp[]) /* Preserve name of myself. */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + /* Seed random number for LSA ID */ + srand (time(NULL)); + /* Command line argument treatment. */ while (1) { diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index d382f038..b0e94288 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -245,6 +245,7 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, char *p; int twoway = 0; int neighborchange = 0; + int neighbor_ifindex_change = 0; int backupseen = 0; hello = (struct ospf6_hello *) @@ -285,10 +286,16 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, on->priority = hello->priority; } - /* always override neighbor's source address and ifindex */ - on->ifindex = ntohl (hello->interface_id); + /* Always override neighbor's source address */ memcpy (&on->linklocal_addr, src, sizeof (struct in6_addr)); + /* Neighbor ifindex check */ + if (on->ifindex != (ifindex_t)ntohl (hello->interface_id)) + { + on->ifindex = ntohl (hello->interface_id); + neighbor_ifindex_change++; + } + /* TwoWay check */ for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello)); p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh); @@ -348,6 +355,9 @@ ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, thread_add_event (master, backup_seen, oi, 0); if (neighborchange) thread_add_event (master, neighbor_change, oi, 0); + + if (neighbor_ifindex_change && on->state == OSPF6_NEIGHBOR_FULL) + OSPF6_ROUTER_LSA_SCHEDULE (oi->area); } static void diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index a7737502..53d6c359 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -112,7 +112,7 @@ ospf6_serv_sock (void) } /* ospf6 set socket option */ -void +int ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option) { struct ipv6_mreq mreq6; @@ -125,8 +125,12 @@ ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option) ret = setsockopt (ospf6_sock, IPPROTO_IPV6, option, &mreq6, sizeof (mreq6)); if (ret < 0) - zlog_err ("Network: setsockopt (%d) on ifindex %d failed: %s", - option, ifindex, safe_strerror (errno)); + { + zlog_err ("Network: setsockopt (%d) on ifindex %d failed: %s", + option, ifindex, safe_strerror (errno)); + } + + return ret; } static int diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index f4b74faa..4fa28395 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -29,7 +29,7 @@ extern struct in6_addr allspfrouters6; extern struct in6_addr alldrouters6; extern int ospf6_serv_sock (void); -extern void ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option); +extern int ospf6_sso (ifindex_t ifindex, struct in6_addr *group, int option); extern int ospf6_sendmsg (struct in6_addr *, struct in6_addr *, ifindex_t *, struct iovec *); diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 50575564..e53ff365 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -37,6 +37,7 @@ #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6d.h" +#include "ospf6_zebra.h" unsigned char conf_debug_ospf6_route = 0; @@ -173,18 +174,232 @@ const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] = { "??", "IA", "IE", "E1", "E2", }; +struct ospf6_nexthop * +ospf6_nexthop_create (void) +{ + struct ospf6_nexthop *nh; + + nh = XCALLOC (MTYPE_OSPF6_NEXTHOP, sizeof (struct ospf6_nexthop)); + return nh; +} + +void +ospf6_nexthop_delete (struct ospf6_nexthop *nh) +{ + if (nh) + XFREE (MTYPE_OSPF6_NEXTHOP, nh); +} + +void +ospf6_free_nexthops (struct list *nh_list) +{ + struct ospf6_nexthop *nh; + struct listnode *node, *nnode; + + if (nh_list) + { + for (ALL_LIST_ELEMENTS (nh_list, node, nnode, nh)) + ospf6_nexthop_delete (nh); + } +} + +void +ospf6_clear_nexthops (struct list *nh_list) +{ + struct listnode *node; + struct ospf6_nexthop *nh; + + if (nh_list) + { + for (ALL_LIST_ELEMENTS_RO (nh_list, node, nh)) + ospf6_nexthop_clear (nh); + } +} + +static struct ospf6_nexthop * +ospf6_route_find_nexthop (struct list *nh_list, struct ospf6_nexthop *nh_match) +{ + struct listnode *node; + struct ospf6_nexthop *nh; + + if (nh_list && nh_match) + { + for (ALL_LIST_ELEMENTS_RO (nh_list, node, nh)) + { + if (ospf6_nexthop_is_same (nh, nh_match)) + return (nh); + } + } + + return (NULL); +} + +void +ospf6_copy_nexthops (struct list *dst, struct list *src) +{ + struct ospf6_nexthop *nh_new, *nh; + struct listnode *node; + + if (dst && src) + { + for (ALL_LIST_ELEMENTS_RO (src, node, nh)) + { + if (ospf6_nexthop_is_set (nh)) + { + nh_new = ospf6_nexthop_create (); + ospf6_nexthop_copy (nh_new, nh); + listnode_add (dst, nh_new); + } + } + } +} + +void +ospf6_merge_nexthops (struct list *dst, struct list *src) +{ + struct listnode *node; + struct ospf6_nexthop *nh, *nh_new; + + if (src && dst) + { + for (ALL_LIST_ELEMENTS_RO (src, node, nh)) + { + if (!ospf6_route_find_nexthop (dst, nh)) + { + nh_new = ospf6_nexthop_create (); + ospf6_nexthop_copy (nh_new, nh); + listnode_add (dst, nh_new); + } + } + } +} + +int +ospf6_route_cmp_nexthops (struct ospf6_route *a, struct ospf6_route *b) +{ + struct listnode *anode, *bnode; + struct ospf6_nexthop *anh, *bnh; + + if (a && b) + { + if (listcount(a->nh_list) == listcount(b->nh_list)) + { + for (ALL_LIST_ELEMENTS_RO (a->nh_list, anode, anh)) + { + for (ALL_LIST_ELEMENTS_RO (b->nh_list, bnode, bnh)) + if (!ospf6_nexthop_is_same (anh, bnh)) + return (1); + } + return (0); + } + else + return (1); + } + /* One of the routes doesn't exist ? */ + return (1); +} + +int +ospf6_num_nexthops (struct list *nh_list) +{ + return (listcount(nh_list)); +} + +void +ospf6_add_nexthop (struct list *nh_list, int ifindex, + struct in6_addr *addr) +{ + struct ospf6_nexthop *nh; + struct ospf6_nexthop nh_match; + + if (nh_list) + { + nh_match.ifindex = ifindex; + if (addr != NULL) + memcpy (&nh_match.address, addr, sizeof (struct in6_addr)); + else + memset (&nh_match.address, 0, sizeof (struct in6_addr)); + + if (!ospf6_route_find_nexthop (nh_list, &nh_match)) + { + nh = ospf6_nexthop_create(); + ospf6_nexthop_copy (nh, &nh_match); + listnode_add (nh_list, nh); + } + } +} + +void +ospf6_route_zebra_copy_nexthops (struct ospf6_route *route, + ifindex_t *ifindexes, + struct in6_addr **nexthop_addr, + int entries) +{ + struct ospf6_nexthop *nh; + struct listnode *node; + char buf[64]; + int i; + + if (route) + { + i = 0; + for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh)) + { + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + { + char ifname[IFNAMSIZ]; + inet_ntop (AF_INET6, &nh->address, buf, sizeof (buf)); + if (!if_indextoname(nh->ifindex, ifname)) + strlcpy(ifname, "unknown", sizeof(ifname)); + zlog_debug (" nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname, + nh->ifindex); + } + if (i < entries) + { + nexthop_addr[i] = &nh->address; + ifindexes[i] = nh->ifindex; + i++; + } + else + { + return; + } + } + } +} + +int +ospf6_route_get_first_nh_index (struct ospf6_route *route) +{ + struct ospf6_nexthop *nh; + + if (route) + { + if ((nh = (struct ospf6_nexthop *)listhead (route->nh_list))) + return (nh->ifindex); + } + + return (-1); +} + struct ospf6_route * ospf6_route_create (void) { struct ospf6_route *route; route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route)); + route->nh_list = list_new(); return route; } void ospf6_route_delete (struct ospf6_route *route) { - XFREE (MTYPE_OSPF6_ROUTE, route); + if (route) + { + ospf6_free_nexthops (route->nh_list); + list_free (route->nh_list); + XFREE (MTYPE_OSPF6_ROUTE, route); + } } struct ospf6_route * @@ -193,7 +408,15 @@ ospf6_route_copy (struct ospf6_route *route) struct ospf6_route *new; new = ospf6_route_create (); - memcpy (new, route, sizeof (struct ospf6_route)); + new->type = route->type; + memcpy (&new->prefix, &route->prefix, sizeof (struct prefix)); + new->installed = route->installed; + new->changed = route->changed; + new->flag = route->flag; + new->route_option = route->route_option; + new->linkstate_id = route->linkstate_id; + new->path = route->path; + ospf6_copy_nexthops (new->nh_list, route->nh_list); new->rnode = NULL; new->prev = NULL; new->next = NULL; @@ -226,7 +449,7 @@ ospf6_route_unlock (struct ospf6_route *route) /* Route compare function. If ra is more preferred, it returns less than 0. If rb is more preferred returns greater than 0. Otherwise (neither one is preferred), returns 0 */ -static int +int ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb) { assert (ospf6_route_is_same (ra, rb)); @@ -246,8 +469,8 @@ ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb) if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2) { - if (ra->path.cost_e2 != rb->path.cost_e2) - return (ra->path.cost_e2 - rb->path.cost_e2); + if (ra->path.u.cost_e2 != rb->path.u.cost_e2) + return (ra->path.u.cost_e2 - rb->path.u.cost_e2); } else { @@ -620,7 +843,7 @@ ospf6_route_remove (struct ospf6_route *route, if (node->info == route) { - if (route->next && ospf6_route_is_same (route->next, route)) + if (route->next && route->next->rnode == node) { node->info = route->next; SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST); @@ -795,6 +1018,8 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route) char duration[16]; const char *ifname; struct timeval now, res; + struct listnode *node; + struct ospf6_nexthop *nh; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &route->changed, &res); @@ -810,27 +1035,26 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route) else prefix2str (&route->prefix, destination, sizeof (destination)); - /* nexthop */ - inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop, - sizeof (nexthop)); - ifname = ifindex2ifname (route->nexthop[0].ifindex); - - vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", - (ospf6_route_is_best (route) ? '*' : ' '), - OSPF6_DEST_TYPE_SUBSTR (route->type), - OSPF6_PATH_TYPE_SUBSTR (route->path.type), - destination, nexthop, IFNAMSIZ, ifname, duration, VNL); - - for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) + i = 0; + for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh)) { /* nexthop */ - inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, + inet_ntop (AF_INET6, &nh->address, nexthop, sizeof (nexthop)); - ifname = ifindex2ifname (route->nexthop[i].ifindex); - - vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", - ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL); + ifname = ifindex2ifname (nh->ifindex); + + if (!i) + { + vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", + (ospf6_route_is_best (route) ? '*' : ' '), + OSPF6_DEST_TYPE_SUBSTR (route->type), + OSPF6_PATH_TYPE_SUBSTR (route->path.type), + destination, nexthop, IFNAMSIZ, ifname, duration, VNL); + i++; + } + else + vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", + ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL); } } @@ -842,7 +1066,8 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) char area_id[16], id[16], adv_router[16], capa[16], options[16]; struct timeval now, res; char duration[16]; - int i; + struct listnode *node; + struct ospf6_nexthop *nh; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); @@ -914,17 +1139,16 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) vty_out (vty, "Metric Type: %d%s", route->path.metric_type, VNL); vty_out (vty, "Metric: %d (%d)%s", - route->path.cost, route->path.cost_e2, VNL); + route->path.cost, route->path.u.cost_e2, VNL); /* Nexthops */ vty_out (vty, "Nexthop:%s", VNL); - for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) + for (ALL_LIST_ELEMENTS_RO (route->nh_list, node, nh)) { /* nexthop */ - inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, + inet_ntop (AF_INET6, &nh->address, nexthop, sizeof (nexthop)); - ifname = ifindex2ifname (route->nexthop[i].ifindex); + ifname = ifindex2ifname (nh->ifindex); vty_out (vty, " %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL); } vty_out (vty, "%s", VNL); @@ -937,7 +1161,7 @@ ospf6_route_show_table_summary (struct vty *vty, struct ospf6_route *route, *prev = NULL; int i, pathtype[OSPF6_PATH_TYPE_MAX]; unsigned int number = 0; - int nhinval = 0, ecmp = 0; + int nh_count =0 , nhinval = 0, ecmp = 0; int alternative = 0, destination = 0; for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++) @@ -950,9 +1174,10 @@ ospf6_route_show_table_summary (struct vty *vty, destination++; else alternative++; - if (! ospf6_nexthop_is_set (&route->nexthop[0])) + nh_count = ospf6_num_nexthops (route->nh_list); + if (!nh_count) nhinval++; - else if (ospf6_nexthop_is_set (&route->nexthop[1])) + else if (nh_count > 1) ecmp++; pathtype[route->path.type]++; number++; diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index 2fb2c1d7..0836031b 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -96,7 +96,10 @@ struct ospf6_path /* Cost */ u_int8_t metric_type; u_int32_t cost; - u_int32_t cost_e2; + union { + u_int32_t cost_e2; + u_int32_t cost_config; + } u; }; #define OSPF6_PATH_TYPE_NONE 0 @@ -107,8 +110,13 @@ struct ospf6_path #define OSPF6_PATH_TYPE_REDISTRIBUTE 5 #define OSPF6_PATH_TYPE_MAX 6 +#define OSPF6_PATH_SUBTYPE_DEFAULT_RT 1 + +#define OSPF6_PATH_COST_IS_CONFIGURED(path) (path.u.cost_config != OSPF_AREA_RANGE_COST_UNSPEC) + #include "prefix.h" #include "table.h" +#include "bitfield.h" struct ospf6_route { @@ -136,17 +144,18 @@ struct ospf6_route /* flag */ u_char flag; - /* path */ - struct ospf6_path path; - - /* nexthop */ - struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT]; - /* route option */ void *route_option; /* link state id for advertising */ u_int32_t linkstate_id; + + /* path */ + struct ospf6_path path; + + /* nexthop */ + struct list *nh_list; + }; #define OSPF6_DEST_TYPE_NONE 0 @@ -164,6 +173,7 @@ struct ospf6_route #define OSPF6_ROUTE_ACTIVE_SUMMARY 0x10 #define OSPF6_ROUTE_DO_NOT_ADVERTISE 0x20 #define OSPF6_ROUTE_WAS_REMOVED 0x40 +#define OSPF6_ROUTE_BLACKHOLE_ADDED 0x80 struct ospf6_route_table { @@ -176,6 +186,8 @@ struct ospf6_route_table u_int32_t count; + bitfield_t idspace; + /* hooks */ void (*hook_add) (struct ospf6_route *); void (*hook_change) (struct ospf6_route *); @@ -235,8 +247,8 @@ extern const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX]; ((ra)->type == (rb)->type && \ memcmp (&(ra)->prefix, &(rb)->prefix, sizeof (struct prefix)) == 0 && \ memcmp (&(ra)->path, &(rb)->path, sizeof (struct ospf6_path)) == 0 && \ - memcmp (&(ra)->nexthop, &(rb)->nexthop, \ - sizeof (struct ospf6_nexthop) * OSPF6_MULTI_PATH_LIMIT) == 0) + ospf6_route_cmp_nexthops (ra, rb) == 0) + #define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST)) #define ospf6_linkstate_prefix_adv_router(x) \ @@ -255,9 +267,35 @@ extern void ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id, extern void ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size); +extern struct ospf6_nexthop *ospf6_nexthop_create (void); +extern void ospf6_nexthop_delete (struct ospf6_nexthop *nh); +extern void ospf6_free_nexthops (struct list *nh_list); +extern void ospf6_clear_nexthops (struct list *nh_list); +extern int ospf6_num_nexthops (struct list *nh_list); +extern void ospf6_copy_nexthops (struct list *dst, struct list *src); +extern void ospf6_merge_nexthops (struct list *dst, struct list *src); +extern void ospf6_add_nexthop (struct list *nh_list, int ifindex, + struct in6_addr *addr); +extern int ospf6_num_nexthops (struct list *nh_list); +extern int ospf6_route_cmp_nexthops (struct ospf6_route *a, + struct ospf6_route *b); +extern void ospf6_route_zebra_copy_nexthops (struct ospf6_route *route, + ifindex_t *ifindices, + struct in6_addr **addr, + int entries); +extern int ospf6_route_get_first_nh_index (struct ospf6_route *route); + +/* Hide abstraction of nexthop implementation in route from outsiders */ +#define ospf6_route_copy_nexthops(dst, src) ospf6_copy_nexthops(dst->nh_list, src->nh_list) +#define ospf6_route_merge_nexthops(dst, src) ospf6_merge_nexthops(dst->nh_list, src->nh_list) +#define ospf6_route_num_nexthops(route) ospf6_num_nexthops(route->nh_list) +#define ospf6_route_add_nexthop(route, ifindex, addr) \ + ospf6_add_nexthop(route->nh_list, ifindex, addr) + extern struct ospf6_route *ospf6_route_create (void); extern void ospf6_route_delete (struct ospf6_route *); extern struct ospf6_route *ospf6_route_copy (struct ospf6_route *route); +extern int ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb); extern void ospf6_route_lock (struct ospf6_route *route); extern void ospf6_route_unlock (struct ospf6_route *route); diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 858398eb..c2cee36d 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -36,6 +36,8 @@ #include "ospf6_lsdb.h" #include "ospf6_route.h" #include "ospf6_area.h" +#include "ospf6_proto.h" +#include "ospf6_abr.h" #include "ospf6_spf.h" #include "ospf6_intra.h" #include "ospf6_interface.h" @@ -44,6 +46,41 @@ unsigned char conf_debug_ospf6_spf = 0; +static void +ospf6_spf_copy_nexthops_to_route (struct ospf6_route *rt, + struct ospf6_vertex *v) +{ + if (rt && v) + ospf6_copy_nexthops (rt->nh_list, v->nh_list); +} + +static void +ospf6_spf_merge_nexthops_to_route (struct ospf6_route *rt, + struct ospf6_vertex *v) +{ + if (rt && v) + ospf6_merge_nexthops (rt->nh_list, v->nh_list); +} + +static unsigned int +ospf6_spf_get_ifindex_from_nh (struct ospf6_vertex *v) +{ + struct ospf6_nexthop *nh; + struct listnode *node; + + if (v) + { + node = listhead(v->nh_list); + if (node) + { + nh = listgetdata (node); + if (nh) + return (nh->ifindex); + } + } + return 0; +} + static int ospf6_vertex_cmp (void *a, void *b) { @@ -77,7 +114,6 @@ static struct ospf6_vertex * ospf6_vertex_create (struct ospf6_lsa *lsa) { struct ospf6_vertex *v; - int i; v = (struct ospf6_vertex *) XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex)); @@ -97,6 +133,10 @@ ospf6_vertex_create (struct ospf6_lsa *lsa) /* name */ ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name)); + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + zlog_debug ("%s: Creating vertex %s of type %s", __func__, v->name, + ((ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER) ? "Router" : "N/W")); + /* Associated LSA */ v->lsa = lsa; @@ -106,8 +146,7 @@ ospf6_vertex_create (struct ospf6_lsa *lsa) v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2); v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3); - for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) - ospf6_nexthop_clear (&v->nexthop[i]); + v->nh_list = list_new(); v->parent = NULL; v->child_list = list_new (); @@ -235,11 +274,14 @@ ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v, char buf[64]; assert (VERTEX_IS_TYPE (ROUTER, w)); - ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex : - /* v is the local router & the interface_id is a local ifindex */ - (ifindex_t) ROUTER_LSDESC_GET_IFID (lsdesc)); - assert (ifindex >= 0); - + ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? ospf6_spf_get_ifindex_from_nh (v) : + ROUTER_LSDESC_GET_IFID (lsdesc)); + if (ifindex == 0) + { + zlog_err ("No nexthop ifindex at vertex %s", v->name); + return; + } + oi = ospf6_interface_lookup_by_ifindex (ifindex); if (oi == NULL) { @@ -268,13 +310,8 @@ ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v, zlog_debug (" nexthop %s from %s", buf, lsa->name); } - if (i < OSPF6_MULTI_PATH_LIMIT) - { - memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr, - sizeof (struct in6_addr)); - w->nexthop[i].ifindex = ifindex; - i++; - } + ospf6_add_nexthop (w->nh_list, ifindex, &link_lsa->linklocal_addr); + i++; } if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS)) @@ -285,8 +322,7 @@ static int ospf6_spf_install (struct ospf6_vertex *v, struct ospf6_route_table *result_table) { - struct ospf6_route *route; - int i, j; + struct ospf6_route *route, *parent_route; struct ospf6_vertex *prev; if (IS_OSPF6_DEBUG_SPF (PROCESS)) @@ -307,23 +343,7 @@ ospf6_spf_install (struct ospf6_vertex *v, if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug (" another path found, merge"); - for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) - { - for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++) - { - if (ospf6_nexthop_is_set (&route->nexthop[j])) - { - if (ospf6_nexthop_is_same (&route->nexthop[j], - &v->nexthop[i])) - break; - else - continue; - } - ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]); - break; - } - } + ospf6_spf_merge_nexthops_to_route (route, v); prev = (struct ospf6_vertex *) route->route_option; assert (prev->hops <= v->hops); @@ -350,15 +370,35 @@ ospf6_spf_install (struct ospf6_vertex *v, route->path.origin.adv_router = v->lsa->header->adv_router; route->path.metric_type = 1; route->path.cost = v->cost; - route->path.cost_e2 = v->hops; + route->path.u.cost_e2 = v->hops; route->path.router_bits = v->capability; route->path.options[0] = v->options[0]; route->path.options[1] = v->options[1]; route->path.options[2] = v->options[2]; - for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) - ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]); + ospf6_spf_copy_nexthops_to_route (route, v); + + /* + * The SPF logic implementation does not transfer the multipathing properties + * of a parent to a child node. Thus if there was a 3-way multipath to a + * node's parent and a single hop from the parent to the child, the logic of + * creating new vertices and computing next hops prevents there from being 3 + * paths to the child node. This is primarily because the resolution of + * multipath is done in this routine, not in the main spf loop. + * + * The following logic addresses that problem by merging the parent's nexthop + * information with the child's, if the parent is not the root of the tree. + * This is based on the assumption that before a node's route is 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); + } + } if (v->parent) listnode_add_sort (v->parent->child_list, v); @@ -371,11 +411,12 @@ ospf6_spf_install (struct ospf6_vertex *v, void ospf6_spf_table_finish (struct ospf6_route_table *result_table) { - struct ospf6_route *route; + struct ospf6_route *route, *nroute; struct ospf6_vertex *v; for (route = ospf6_route_head (result_table); route; - route = ospf6_route_next (route)) + route = nroute) { + nroute = ospf6_route_next (route); v = (struct ospf6_vertex *) route->route_option; ospf6_vertex_delete (v); ospf6_route_remove (route, result_table); @@ -421,19 +462,24 @@ ospf6_spf_calculation (u_int32_t router_id, { struct pqueue *candidate_list; struct ospf6_vertex *root, *v, *w; - int i; int size; caddr_t lsdesc; struct ospf6_lsa *lsa; + struct in6_addr address; ospf6_spf_table_finish (result_table); /* Install the calculating router itself as the root of the SPF tree */ /* construct root vertex */ lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0), - router_id, oa->lsdb); + router_id, oa->lsdb_self); if (lsa == NULL) - return; + { + if (IS_OSPF6_DEBUG_SPF (PROCESS)) + zlog_debug ("%s: No router LSA for area %s\n", + __func__, oa->name); + return; + } /* initialize */ candidate_list = pqueue_create (); @@ -443,8 +489,7 @@ ospf6_spf_calculation (u_int32_t router_id, root->area = oa; root->cost = 0; root->hops = 0; - root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */ - inet_pton (AF_INET6, "::1", &root->nexthop[0].address); + inet_pton (AF_INET6, "::1", &address); /* Actually insert root to the candidate-list as the only candidate */ pqueue_enqueue (root, candidate_list); @@ -475,6 +520,9 @@ ospf6_spf_calculation (u_int32_t router_id, if (lsa == NULL) continue; + if (OSPF6_LSA_IS_MAXAGE (lsa)) + continue; + if (! ospf6_lsdesc_backlink (lsa, lsdesc, v)) continue; @@ -494,14 +542,12 @@ ospf6_spf_calculation (u_int32_t router_id, /* nexthop calculation */ if (w->hops == 0) - w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc); + ospf6_add_nexthop (w->nh_list, ROUTER_LSDESC_GET_IFID (lsdesc), NULL); else if (w->hops == 1 && v->hops == 0) ospf6_nexthop_calc (w, v, lsdesc); else { - for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && - i < OSPF6_MULTI_PATH_LIMIT; i++) - ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]); + ospf6_copy_nexthops (w->nh_list, v->nh_list); } /* add new candidate to the candidate_list */ @@ -549,7 +595,6 @@ ospf6_spf_calculation_thread (struct thread *t) struct ospf6 *ospf6; struct timeval start, end, runtime; struct listnode *node; - struct ospf6_route *route; int areas_processed = 0; char rbuf[32]; @@ -559,6 +604,9 @@ ospf6_spf_calculation_thread (struct thread *t) /* execute SPF calculation */ quagga_gettime (QUAGGA_CLK_MONOTONIC, &start); + if (ospf6_is_router_abr (ospf6)) + ospf6_abr_range_reset_cost (ospf6); + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) { @@ -592,10 +640,8 @@ ospf6_spf_calculation_thread (struct thread *t) areas_processed++; } - /* Redo summaries if required */ - for (route = ospf6_route_head (ospf6->route_table); route; - route = ospf6_route_next (route)) - ospf6_abr_originate_summary(route); + if (ospf6_is_router_abr (ospf6)) + ospf6_abr_defaults_to_stub (ospf6); quagga_gettime (QUAGGA_CLK_MONOTONIC, &end); timersub (&end, &start, &runtime); diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h index b3481dc3..7bf525d6 100644 --- a/ospf6d/ospf6_spf.h +++ b/ospf6d/ospf6_spf.h @@ -60,9 +60,6 @@ struct ospf6_vertex /* Router hops to this node */ u_char hops; - /* nexthops to this node */ - struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT]; - /* capability bits */ u_char capability; @@ -72,6 +69,9 @@ struct ospf6_vertex /* For tree display */ struct ospf6_vertex *parent; struct list *child_list; + + /* nexthops to this node */ + struct list *nh_list; }; #define OSPF6_VERTEX_TYPE_ROUTER 0x01 diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 7fffba83..798a1cda 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -92,6 +92,7 @@ ospf6_top_route_hook_add (struct ospf6_route *route) static void ospf6_top_route_hook_remove (struct ospf6_route *route) { + route->flag |= OSPF6_ROUTE_REMOVE; ospf6_abr_originate_summary (route); ospf6_zebra_route_update_remove (route); } @@ -107,6 +108,7 @@ ospf6_top_brouter_hook_add (struct ospf6_route *route) static void ospf6_top_brouter_hook_remove (struct ospf6_route *route) { + route->flag |= OSPF6_ROUTE_REMOVE; ospf6_abr_examin_brouter (ADV_ROUTER_IN_PREFIX (&route->prefix)); ospf6_asbr_lsentry_remove (route); ospf6_abr_originate_summary (route); @@ -721,6 +723,8 @@ DEFUN (show_ipv6_ospf6_route, ROUTE_STR ) { + OSPF6_CMD_CHECK_RUNNING (); + ospf6_route_table_show (vty, argc, argv, ospf6->route_table); return CMD_SUCCESS; } @@ -752,6 +756,8 @@ DEFUN (show_ipv6_ospf6_route_match, const char *sargv[CMD_ARGC_MAX]; int i, sargc; + OSPF6_CMD_CHECK_RUNNING (); + /* copy argv to sargv and then append "match" */ for (i = 0; i < argc; i++) sargv[i] = argv[i]; @@ -786,6 +792,8 @@ DEFUN (show_ipv6_ospf6_route_match_detail, sargv[sargc++] = "detail"; sargv[sargc] = NULL; + OSPF6_CMD_CHECK_RUNNING (); + ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table); return CMD_SUCCESS; } @@ -850,6 +858,8 @@ DEFUN (show_ipv6_ospf6_route_type_detail, sargv[sargc++] = "detail"; sargv[sargc] = NULL; + OSPF6_CMD_CHECK_RUNNING (); + ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table); return CMD_SUCCESS; } diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index c8f20d86..5f3b66a2 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -371,7 +371,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) int nhcount; struct in6_addr **nexthops; ifindex_t *ifindexes; - int i, ret = 0; + int ret = 0; struct prefix_ipv6 *dest; if (IS_OSPF6_DEBUG_ZEBRA (SEND)) @@ -417,11 +417,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) return; } - nhcount = 0; - for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) - if (ospf6_nexthop_is_set (&request->nexthop[i])) - nhcount++; - + nhcount = ospf6_route_num_nexthops (request); if (nhcount == 0) { if (IS_OSPF6_DEBUG_ZEBRA (SEND)) @@ -448,20 +444,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) return; } - for (i = 0; i < nhcount; i++) - { - if (IS_OSPF6_DEBUG_ZEBRA (SEND)) - { - const char *ifname; - inet_ntop (AF_INET6, &request->nexthop[i].address, - buf, sizeof (buf)); - ifname = ifindex2ifname (request->nexthop[i].ifindex); - zlog_debug (" nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname, - request->nexthop[i].ifindex); - } - nexthops[i] = &request->nexthop[i].address; - ifindexes[i] = request->nexthop[i].ifindex; - } + ospf6_route_zebra_copy_nexthops (request, ifindexes, nexthops, nhcount); api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_OSPF6; @@ -476,7 +459,7 @@ ospf6_zebra_route_update (int type, struct ospf6_route *request) api.ifindex = ifindexes; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = (request->path.metric_type == 2 ? - request->path.cost_e2 : request->path.cost); + request->path.u.cost_e2 : request->path.cost); dest = (struct prefix_ipv6 *) &request->prefix; if (type == REM) @@ -518,6 +501,90 @@ ospf6_zebra_route_update_remove (struct ospf6_route *request) ospf6_zebra_route_update (REM, request); } +void +ospf6_zebra_add_discard (struct ospf6_route *request) +{ + struct zapi_ipv6 api; + char buf[INET6_ADDRSTRLEN]; + struct prefix_ipv6 *dest; + + if (zclient->redist[ZEBRA_ROUTE_OSPF6]) + { + if (!CHECK_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) + { + api.type = ZEBRA_ROUTE_OSPF6; + api.flags = ZEBRA_FLAG_BLACKHOLE; + api.message = 0; + api.safi = SAFI_UNICAST; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 0; + api.ifindex_num = 0; + + dest = (struct prefix_ipv6 *) &request->prefix; + + zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, dest, &api); + + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + zlog_debug ("Zebra: Route add discard %s/%d", + inet_ntop (AF_INET6, &dest->prefix, + buf, INET6_ADDRSTRLEN), + dest->prefixlen); + SET_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED); + } + else + { + dest = (struct prefix_ipv6 *) &request->prefix; + + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + zlog_debug ("Zebra: Blackhole route present already %s/%d", + inet_ntop (AF_INET6, &dest->prefix, + buf, INET6_ADDRSTRLEN), + dest->prefixlen); + } + } +} + +void +ospf6_zebra_delete_discard (struct ospf6_route *request) +{ + struct zapi_ipv6 api; + char buf[INET6_ADDRSTRLEN]; + struct prefix_ipv6 *dest; + + if (zclient->redist[ZEBRA_ROUTE_OSPF6]) + { + if (CHECK_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) + { + + api.type = ZEBRA_ROUTE_OSPF6; + api.flags = ZEBRA_FLAG_BLACKHOLE; + api.message = 0; + api.safi = SAFI_UNICAST; + SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 0; + api.ifindex_num = 0; + + dest = (struct prefix_ipv6 *) &request->prefix; + + zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, dest, &api); + + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + zlog_debug ("Zebra: Route delete discard %s/%d", + inet_ntop (AF_INET6, &dest->prefix, buf, + INET6_ADDRSTRLEN), dest->prefixlen); + UNSET_FLAG (request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED); + } + else + { + dest = (struct prefix_ipv6 *) &request->prefix; + if (IS_OSPF6_DEBUG_ZEBRA (SEND)) + zlog_debug ("Zebra: Blackhole route already deleted %s/%d", + inet_ntop (AF_INET6, &dest->prefix, buf, + INET6_ADDRSTRLEN), dest->prefixlen); + } + } +} + DEFUN (redistribute_ospf6, redistribute_ospf6_cmd, "redistribute ospf6", diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h index 05694d39..4d028182 100644 --- a/ospf6d/ospf6_zebra.h +++ b/ospf6d/ospf6_zebra.h @@ -45,6 +45,8 @@ extern void ospf6_zebra_no_redistribute (int); #define ospf6_zebra_is_redistribute(type) \ vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT) extern void ospf6_zebra_init(struct thread_master *); +extern void ospf6_zebra_add_discard (struct ospf6_route *request); +extern void ospf6_zebra_delete_discard (struct ospf6_route *request); extern int config_write_ospf6_debug_zebra (struct vty *vty); extern void install_element_ospf6_debug_zebra (void); diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index c2baa314..c929dfff 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -1690,6 +1690,8 @@ DEFUN (show_ipv6_ospf6_linkstate, struct listnode *node; struct ospf6_area *oa; + OSPF6_CMD_CHECK_RUNNING (); + for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { vty_out (vty, "%s SPF Result in Area %s%s%s", @@ -1738,6 +1740,8 @@ DEFUN (show_ipv6_ospf6_linkstate_detail, struct listnode *node; struct ospf6_area *oa; + OSPF6_CMD_CHECK_RUNNING (); + /* copy argv to sargv and then append "detail" */ for (i = 0; i < argc; i++) sargv[i] = argv[i]; @@ -1790,6 +1794,8 @@ ospf6_init (void) install_element_ospf6_debug_abr (); install_element_ospf6_debug_flood (); + install_element_ospf6_clear_interface (); + install_element (VIEW_NODE, &show_version_ospf6_cmd); install_element (ENABLE_NODE, &show_version_ospf6_cmd); @@ -1892,6 +1898,8 @@ ospf6_init (void) void ospf6_clean (void) { + if (!ospf6) + return; if (ospf6->route_table) ospf6_route_remove_all (ospf6->route_table); if (ospf6->brouter_table) |