From 4dc43886914a1304b8331e0836a00f0eb605c7c9 Mon Sep 17 00:00:00 2001 From: Mobashshera Rasool Date: Fri, 28 May 2021 02:33:03 -0700 Subject: [PATCH] ospf6d: ASBR Summarisation feature implementation Feature Implementation. ======================== This feature will help in advertising the External LSAs with aggregation. The commands allow us to tune the advertisement with different parameters as mentioned in the CLI List below. It can also help in case we do not want to advertise any prefix with the no-advertise option. New CLIs added: =============== summary-address X:X::X:X/M$prefix [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)}] no summary-address X:X::X:X/M$prefix [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)}] summary-address X:X::X:X/M$prefix no-advertise no summary-address X:X::X:X/M$prefix no-advertise aggregation timer (5-1800) no aggregation timer (5-1800) show ipv6 ospf6 summary-address [detail$detail] [json] debug ospf6 lsa aggregation CAT RUN: ======== QE to add test scripts Signed-Off-by: Mobashshera Rasool --- ospf6d/ospf6_asbr.c | 1139 ++++++++++++++++++++++++++++++++++++++++-- ospf6d/ospf6_asbr.h | 68 ++- ospf6d/ospf6_flood.c | 27 +- ospf6d/ospf6_flood.h | 3 + ospf6d/ospf6_lsa.c | 35 ++ ospf6d/ospf6_lsa.h | 4 + ospf6d/ospf6_lsdb.c | 23 + ospf6d/ospf6_route.h | 6 + ospf6d/ospf6_top.c | 454 ++++++++++++++++- ospf6d/ospf6_top.h | 13 + ospf6d/ospf6d.h | 4 + ospf6d/subdir.am | 1 + 12 files changed, 1725 insertions(+), 52 deletions(-) diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 3e911a743a..8cb3a4e0b3 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -57,6 +57,7 @@ DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DIST_ARGS, "OSPF6 Distribute arguments"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments"); +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_RT_AGGR, "OSPF6 ASBR Summarisation"); static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type); static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6, @@ -71,8 +72,8 @@ unsigned char conf_debug_ospf6_asbr = 0; #define ZROUTE_NAME(x) zebra_route_string(x) /* AS External LSA origination */ -void ospf6_as_external_lsa_originate(struct ospf6_route *route, - struct ospf6 *ospf6) +struct ospf6_lsa *ospf6_as_external_lsa_originate(struct ospf6_route *route, + struct ospf6 *ospf6) { char buffer[OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; @@ -164,6 +165,8 @@ void ospf6_as_external_lsa_originate(struct ospf6_route *route, /* Originate */ ospf6_lsa_originate_process(lsa, ospf6); + + return lsa; } int ospf6_orig_as_external_lsa(struct thread *thread) @@ -1301,6 +1304,29 @@ void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa) } } +static struct ospf6_external_aggr_rt * +ospf6_external_aggr_match(struct ospf6 *ospf6, struct prefix *p) +{ + struct route_node *node; + + node = route_node_match(ospf6->rt_aggr_tbl, (struct prefix *)p); + if (node) { + + if (IS_OSPF6_DEBUG_AGGR) { + if (node->info) { + struct ospf6_external_aggr_rt *ag = node->info; + zlog_debug("%s: Matching aggregator found.prefix: %pFX Aggregator %pFX", + __func__, + p, + &ag->p); + } + } + route_unlock_node(node); + return node->info; + } + return NULL; +} + void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, struct prefix *prefix, unsigned int nexthop_num, @@ -1378,6 +1404,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, match->path.cost = troute.path.cost; else match->path.cost = metric_value(ospf6, type, 0); + if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding)) memcpy(&info->forwarding, &tinfo.forwarding, sizeof(struct in6_addr)); @@ -1414,7 +1441,8 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, } match->path.origin.id = htonl(info->id); - ospf6_as_external_lsa_originate(match, ospf6); + ospf6_handle_external_lsa_origination(ospf6, match, prefix); + ospf6_asbr_status_update(ospf6, ospf6->redistribute); for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) { if (IS_AREA_NSSA(oa)) @@ -1432,7 +1460,6 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, info = (struct ospf6_external_info *)XCALLOC( MTYPE_OSPF6_EXTERNAL_INFO, sizeof(struct ospf6_external_info)); route->route_option = info; - info->id = ospf6->external_id++; /* copy result of route-map */ if (ROUTEMAP(red)) { @@ -1463,30 +1490,70 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, else ospf6_route_add_nexthop(route, ifindex, NULL); - /* create/update binding in external_id_table */ - prefix_id.family = AF_INET; - prefix_id.prefixlen = IPV4_MAX_BITLEN; - prefix_id.u.prefix4.s_addr = htonl(info->id); - node = route_node_get(ospf6->external_id_table, &prefix_id); - node->info = route; - route = ospf6_route_add(route, ospf6->external_table); - route->route_option = info; + ospf6_handle_external_lsa_origination(ospf6, route, prefix); - if (IS_OSPF6_DEBUG_ASBR) { - inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf)); - zlog_debug( - "Advertise as AS-External Id:%s prefix %pFX metric %u", - ibuf, prefix, route->path.metric_type); - } - - route->path.origin.id = htonl(info->id); - ospf6_as_external_lsa_originate(route, ospf6); ospf6_asbr_status_update(ospf6, ospf6->redistribute); for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) { if (IS_AREA_NSSA(oa)) ospf6_nssa_lsa_originate(route, oa); } + + return; +} + +static void ospf6_asbr_external_lsa_remove_by_id(struct ospf6 *ospf6, + uint32_t id) +{ + struct ospf6_lsa *lsa; + + lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), + htonl(id), ospf6->router_id, ospf6->lsdb); + if (!lsa) + return; + + ospf6_external_lsa_purge(ospf6, lsa); + + return; +} + +static void +ospf6_link_route_to_aggr(struct ospf6_external_aggr_rt *aggr, + struct ospf6_route *rt) +{ + hash_get(aggr->match_extnl_hash, rt, hash_alloc_intern); + rt->aggr_route = aggr; +} + +static void +ospf6_unlink_route_from_aggr(struct ospf6 *ospf6, struct ospf6_external_aggr_rt *aggr, + struct ospf6_route *rt) +{ + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Unlinking external route(%pFX) from aggregator(%pFX), external route count:%ld", + __func__, + &rt->prefix, + &aggr->p, + OSPF6_EXTERNAL_RT_COUNT(aggr)); + + hash_release(aggr->match_extnl_hash, rt); + rt->aggr_route = NULL; + + /* Flush the aggregate route if matching + * external route count becomes zero. + */ + if (!OSPF6_EXTERNAL_RT_COUNT(aggr) && CHECK_FLAG(aggr->aggrflags, + OSPF6_EXTERNAL_AGGRT_ORIGINATED)) { + /* Flush the aggregate LSA */ + ospf6_asbr_external_lsa_remove_by_id(ospf6, aggr->id); + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Flushing the aggregate route)", + __func__);; + aggr->id = 0; + /* Unset the Origination flag */ + UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED); + } } void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex, @@ -1495,11 +1562,8 @@ void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex, struct ospf6_area *oa; struct ospf6_route *match; struct ospf6_external_info *info = NULL; - struct listnode *lnode; - struct route_node *node; struct ospf6_lsa *lsa; - struct prefix prefix_id; - char ibuf[16]; + struct listnode *lnode; match = ospf6_route_lookup(prefix, ospf6->external_table); if (match == NULL) { @@ -1517,21 +1581,6 @@ void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex, return; } - if (IS_OSPF6_DEBUG_ASBR) { - inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf)); - zlog_debug("Withdraw %pFX (AS-External Id:%s)", prefix, ibuf); - } - - lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), - htonl(info->id), ospf6->router_id, ospf6->lsdb); - if (lsa) { - if (IS_OSPF6_DEBUG_ASBR) { - zlog_debug("withdraw type 5 LSA for route %pFX", - prefix); - } - ospf6_lsa_purge(lsa); - } - /* Delete the NSSA LSA */ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) { lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7), @@ -1546,15 +1595,13 @@ void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex, } } - /* remove binding in external_id_table */ - prefix_id.family = AF_INET; - prefix_id.prefixlen = IPV4_MAX_BITLEN; - prefix_id.u.prefix4.s_addr = htonl(info->id); - node = route_node_lookup(ospf6->external_id_table, &prefix_id); - assert(node); - node->info = NULL; - route_unlock_node(node); /* to free the lookup lock */ - route_unlock_node(node); /* to free the original lock */ + /* This means aggregation on this route was not done, hence remove LSA + * if any originated for this prefix + */ + if (!match->aggr_route) + ospf6_asbr_external_lsa_remove_by_id(ospf6, info->id); + else + ospf6_unlink_route_from_aggr(ospf6, match->aggr_route, match); ospf6_route_remove(match, ospf6->external_table); XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info); @@ -2613,3 +2660,997 @@ void install_element_ospf6_debug_asbr(void) install_element(CONFIG_NODE, &debug_ospf6_asbr_cmd); install_element(CONFIG_NODE, &no_debug_ospf6_asbr_cmd); } + +/* ASBR Summarisation */ +static void ospf6_originate_new_aggr_lsa(struct ospf6 *ospf6, + struct ospf6_external_aggr_rt *aggr, + struct ospf6_route *rt_aggr) +{ + + struct prefix prefix_id; + struct route_node *node; + struct ospf6_lsa *lsa = NULL; + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Originate new aggregate route(%pFX)", __func__, + &aggr->p); + + aggr->id = ospf6->external_id++; + /* create/update binding in external_id_table */ + prefix_id.family = AF_INET; + prefix_id.prefixlen = 32; + prefix_id.u.prefix4.s_addr = htonl(aggr->id); + node = route_node_get(ospf6->external_id_table, &prefix_id); + node->info = aggr; + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug( + "Advertise AS-External Id:%pI4 prefix %pFX metric %u", + &prefix_id.u.prefix4, &aggr->p, rt_aggr->path.cost); + + rt_aggr->path.origin.id = htonl(aggr->id); + + /* Originate summary LSA */ + lsa = ospf6_as_external_lsa_originate(rt_aggr, ospf6); + if (lsa) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Set the origination bit for aggregator", + __func__); + SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED); + } + + return; +} + +static void ospf6_fill_aggr_route_details(struct ospf6 *ospf6, + struct ospf6_external_info *ei_aggr, + struct ospf6_route *rt_aggr, + struct ospf6_external_aggr_rt *aggr) +{ + /* Prepare the external_info for aggregator */ + memset(ei_aggr, 0, sizeof(struct ospf6_external_info)); + memset(rt_aggr, 0, + sizeof(struct ospf6_route)); + + rt_aggr->prefix = aggr->p; + rt_aggr->route_option = ei_aggr; + ei_aggr->tag = aggr->tag; + ei_aggr->type = 0; + + /* When metric is not configured, apply the default metric */ + rt_aggr->path.cost = ((aggr->metric == -1) ? + DEFAULT_DEFAULT_METRIC : (unsigned)(aggr->metric)); + rt_aggr->path.metric_type = aggr->mtype; + + rt_aggr->path.origin.id = htonl(aggr->id); +} + +static void +ospf6_aggr_handle_advertise_change(struct ospf6 *ospf6, + struct ospf6_external_aggr_rt *aggr) +{ + struct ospf6_external_info ei_aggr; + struct ospf6_route rt_aggr; + + /* Check if advertise option modified. */ + if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.", + __func__); + + if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: No-advertise,So Flush the Aggregate route(%pFX)", + __func__, + &aggr->p); + + ospf6_asbr_external_lsa_remove_by_id(ospf6, aggr->id); + /* Setting it here as 0, so that it is considered as + * invalid */ + aggr->id = 0; + UNSET_FLAG(aggr->aggrflags, + OSPF6_EXTERNAL_AGGRT_ORIGINATED); + } + return; + } + + /* There are no routes present under this aggregation config, hence + * nothing to originate here */ + if (OSPF6_EXTERNAL_RT_COUNT(aggr) == 0) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: No routes present under this aggregation", + __func__); + return; + } + + if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Now it is advertisable", + __func__); + + /* Prepare the external_info for aggregator */ + /* Fill all the details which will get advertised */ + ospf6_fill_aggr_route_details(ospf6, &ei_aggr, &rt_aggr, aggr); + + ospf6_originate_new_aggr_lsa(ospf6, aggr, &rt_aggr); + + return; + } +} + +static void +ospf6_originate_summary_lsa(struct ospf6 *ospf6, + struct ospf6_external_aggr_rt *aggr, + struct ospf6_route *rt) +{ + struct ospf6_lsa *lsa = NULL, *aggr_lsa = NULL; + struct ospf6_route rt_aggr; + struct ospf6_external_info ei_aggr, *info = NULL; + struct ospf6_external_aggr_rt *old_aggr; + struct ospf6_as_external_lsa *external; + route_tag_t tag = 0; + unsigned int metric = 0; + int mtype; + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Prepare to originate Summary route(%pFX)", + __func__, &aggr->p); + + /* This case to handle when the overlapping aggregator address + * is available. Best match will be considered.So need to delink + * from old aggregator and link to the new aggr. + */ + if (rt->aggr_route) { + if (rt->aggr_route != aggr) { + old_aggr = rt->aggr_route; + ospf6_unlink_route_from_aggr(ospf6, old_aggr, rt); + } + } + + /* Add the external route to hash table */ + ospf6_link_route_to_aggr(aggr, rt); + + /* The key for ID field is a running number and not prefix */ + info = rt->route_option; + assert(info); + if (info->id) { + lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), + htonl(info->id), ospf6->router_id, ospf6->lsdb); + assert(lsa); + } + + aggr_lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), + htonl(aggr->id), ospf6->router_id, ospf6->lsdb); + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Aggr LSA ID: %d flags %x.", + __func__, aggr->id, aggr->aggrflags); + /* Dont originate external LSA, + * If it is configured not to advertise. + */ + if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) { + /* If it is already originated as external LSA, + * But, it is configured not to advertise then + * flush the originated external lsa. + */ + if (lsa) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Purge the external LSA %s.", + __func__, lsa->name); + ospf6_external_lsa_purge(ospf6, lsa); + info->id = 0; + rt->path.origin.id = 0; + } + + if (aggr_lsa) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Purge the aggr external LSA %s.", + __func__, lsa->name); + ospf6_external_lsa_purge(ospf6, aggr_lsa); + aggr->id = 0; + } + + UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED); + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Don't originate the summary address,It is configured to not-advertise.", + __func__); + return; + } + + /* Prepare the external_info for aggregator */ + ospf6_fill_aggr_route_details(ospf6, &ei_aggr, &rt_aggr, aggr); + + /* Summary route already originated, + * So, Do nothing. + */ + if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) { + if (!aggr_lsa) { + zlog_warn( + "%s: Could not refresh/originate %pFX", + __func__, + &aggr->p); + /* Remove the assert later */ + assert(aggr_lsa); + return; + } + + external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( + aggr_lsa->header); + metric = (unsigned long)OSPF6_ASBR_METRIC(external); + tag = ospf6_as_external_lsa_get_tag(aggr_lsa); + mtype = CHECK_FLAG(external->bits_metric,\ + OSPF6_ASBR_BIT_E)? 2 : 1; + + /* If tag/metric/metric-type modified , then re-originate the + * route with modified tag/metric/metric-type details. + */ + if ((tag != ei_aggr.tag) + || (metric != (unsigned int)rt_aggr.path.cost) + || (mtype != aggr->mtype)) { + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug( + "%s: Routetag(old:%d new:%d)/Metric(o:%u,n:%u)/mtype(o:%d n:%d) modified,So refresh the summary route.(%pFX)", + __func__, tag, ei_aggr.tag, + metric, + aggr->metric, + mtype, aggr->mtype, + &aggr->p); + + aggr_lsa = ospf6_as_external_lsa_originate(&rt_aggr, ospf6); + if (aggr_lsa) + SET_FLAG(aggr->aggrflags, + OSPF6_EXTERNAL_AGGRT_ORIGINATED); + } + + return; + } + + /* If the external route prefix same as aggregate route + * and if external route is already originated as TYPE-5 + * then it need to be refreshed and originate bit should + * be set. + */ + if (lsa && prefix_same((struct prefix *)&rt_aggr.prefix, + (struct prefix *)&rt->prefix)) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: External route prefix is same as aggr so refreshing LSA(%pFX)", + __PRETTY_FUNCTION__, + &aggr->p); + + THREAD_OFF(lsa->refresh); + thread_add_event(master, ospf6_lsa_refresh, lsa, 0, + &lsa->refresh); + aggr->id = info->id; + SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED); + return; + } + + ospf6_originate_new_aggr_lsa(ospf6, aggr, &rt_aggr); + return; +} + +static void ospf6_aggr_handle_external_info(void *data) +{ + struct ospf6_route *rt = (struct ospf6_route *)data; + struct ospf6_external_aggr_rt *aggr = NULL; + struct ospf6_lsa *lsa = NULL; + struct ospf6_external_info *info; + struct ospf6 *ospf6 = NULL; + struct prefix prefix_id; + struct route_node *node; + + rt->aggr_route = NULL; + + rt->to_be_processed = true; + + if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL)) + zlog_debug("%s: Handle external route for origination/refresh (%pFX)", + __func__, + &rt->prefix); + + ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); + assert(ospf6); + + aggr = ospf6_external_aggr_match(ospf6, + &rt->prefix); + if (aggr) { + ospf6_originate_summary_lsa(ospf6, aggr, rt); + return; + } + + info = rt->route_option; + if (info->id) { + lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), + htonl(info->id), ospf6->router_id, ospf6->lsdb); + if (lsa) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: LSA found, refresh it", __func__); + THREAD_OFF(lsa->refresh); + thread_add_event(master, ospf6_lsa_refresh, lsa, 0, + &lsa->refresh); + return; + } + } + + info->id = ospf6->external_id++; + rt->path.origin.id = htonl(info->id); + + /* create/update binding in external_id_table */ + prefix_id.family = AF_INET; + prefix_id.prefixlen = 32; + prefix_id.u.prefix4.s_addr = htonl(info->id); + node = route_node_get(ospf6->external_id_table, &prefix_id); + node->info = rt; + + lsa = ospf6_as_external_lsa_originate(rt, ospf6); + + return; +} + +static void +ospf6_asbr_summary_config_delete(struct ospf6 *ospf6, struct route_node *rn) +{ + struct ospf6_external_aggr_rt *aggr = rn->info; + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Deleting Aggregate route (%pFX)", + __func__, + &aggr->p); + + /*Sent a Max age LSA if it is already originated.*/ + if (CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Flushing Aggregate route (%pFX)", + __func__, + &aggr->p); + + ospf6_asbr_external_lsa_remove_by_id(ospf6, aggr->id); + } + + rn->info = NULL; + route_unlock_node(rn); +} + +static void ospf6_handle_external_aggr_update(struct ospf6 *ospf6) +{ + struct route_node *rn = NULL; + unsigned int metric = 0; + int mtype; + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Process modified aggregators.", __func__); + + for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) { + struct ospf6_external_aggr_rt *aggr; + struct ospf6_lsa *lsa = NULL; + struct ospf6_as_external_lsa *asel = NULL; + struct ospf6_route rt_aggr; + struct ospf6_external_info ei_aggr; + route_tag_t tag = 0; + + if (!rn->info) + continue; + + aggr = rn->info; + + if (aggr->action == OSPF6_ROUTE_AGGR_DEL) { + aggr->action = OSPF6_ROUTE_AGGR_NONE; + ospf6_asbr_summary_config_delete(ospf6, rn); + + if (OSPF6_EXTERNAL_RT_COUNT(aggr)) + hash_clean(aggr->match_extnl_hash, + (void *)ospf6_aggr_handle_external_info); + + hash_free(aggr->match_extnl_hash); + XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR, aggr); + + } else if (aggr->action == OSPF6_ROUTE_AGGR_MODIFY) { + + aggr->action = OSPF6_ROUTE_AGGR_NONE; + + /* Check if tag/metric/metric-type modified */ + if (CHECK_FLAG(aggr->aggrflags, + OSPF6_EXTERNAL_AGGRT_ORIGINATED) + && !CHECK_FLAG(aggr->aggrflags, + OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) { + + lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), + htonl(aggr->id), ospf6->router_id, ospf6->lsdb); + if (!lsa) { + zlog_warn( + "%s: Could not refresh/originate %pFX", + __func__, + &aggr->p); + + continue; + } + + asel = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( + lsa->header); + metric = (unsigned long)OSPF6_ASBR_METRIC(asel); + tag = ospf6_as_external_lsa_get_tag(lsa); + mtype = CHECK_FLAG(asel->bits_metric,\ + OSPF6_ASBR_BIT_E)? 2 : 1; + + /* Fill all the details which will get advertised */ + ospf6_fill_aggr_route_details(ospf6, &ei_aggr, + &rt_aggr, aggr); + + /* If tag/metric/metric-type modified , then + * re-originate the route with modified + * tag/metric/metric-type details. + */ + if ((tag != ei_aggr.tag) + || (metric + != (unsigned int)rt_aggr.path.cost) + || (mtype + != aggr->mtype)) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug( + "%s: Changed tag(old:%d new:%d)/metric(o:%u n:%d)/mtype(o:%d n:%d),So refresh the summary route.(%pFX)", + __func__, tag, + ei_aggr.tag, + metric, + (unsigned int)rt_aggr.path.cost, + mtype, aggr->mtype, + &aggr->p); + + lsa = ospf6_as_external_lsa_originate(&rt_aggr, ospf6); + if (lsa) + SET_FLAG(aggr->aggrflags, + OSPF6_EXTERNAL_AGGRT_ORIGINATED); + + } + } + + /* Advertise option modified ? + * If so, handled it here. + */ + ospf6_aggr_handle_advertise_change(ospf6, aggr); + } + } +} + +static void ospf6_aggr_unlink_external_info(void *data) +{ + struct ospf6_route *rt = (struct ospf6_route *)data; + + rt->aggr_route = NULL; + + rt->to_be_processed = true; +} + +void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr) +{ + if (OSPF6_EXTERNAL_RT_COUNT(aggr)) + hash_clean(aggr->match_extnl_hash, + (void *)ospf6_aggr_unlink_external_info); + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Release the aggregator Address(%pFX)", + __func__, + &aggr->p); + + hash_free(aggr->match_extnl_hash); + aggr->match_extnl_hash = NULL; + + XFREE(MTYPE_OSPF6_EXTERNAL_RT_AGGR, aggr); +} + +static void +ospf6_delete_all_marked_aggregators(struct ospf6 *ospf6) +{ + struct route_node *rn = NULL; + struct ospf6_external_aggr_rt *aggr; + + /* Loop through all the aggregators, Delete all aggregators + * which are marked as DELETE. Set action to NONE for remaining + * aggregators + */ + for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) + if (rn->info) { + aggr = rn->info; + + if (aggr->action != OSPF6_ROUTE_AGGR_DEL) { + aggr->action = OSPF6_ROUTE_AGGR_NONE; + continue; + } + ospf6_asbr_summary_config_delete(ospf6, rn); + ospf6_external_aggregator_free(aggr); + } +} + +static void ospf6_handle_exnl_rt_after_aggr_del(struct ospf6 *ospf6, + struct ospf6_route *rt) +{ + struct ospf6_lsa *lsa; + + /* Process only marked external routes. + * These routes were part of a deleted + * aggregator.So, originate now. + */ + if (!rt->to_be_processed) + return; + + rt->to_be_processed = false; + + lsa = ospf6_find_external_lsa(ospf6, &rt->prefix); + + if (lsa) { + THREAD_OFF(lsa->refresh); + thread_add_event(master, ospf6_lsa_refresh, lsa, 0, + &lsa->refresh); + } + else { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Originate external route(%pFX)", + __func__, + &rt->prefix); + + lsa = ospf6_as_external_lsa_originate(rt, ospf6); + } +} + +static void ospf6_handle_aggregated_exnl_rt(struct ospf6 *ospf6, + struct ospf6_external_aggr_rt *aggr, + struct ospf6_route *rt) +{ + struct ospf6_lsa *lsa; + struct ospf6_as_external_lsa *ext_lsa; + struct ospf6_external_info *info; + + /* Handling the case where the external route prefix + * and aggegate prefix is same + * If same dont flush the originated external LSA. + */ + if (prefix_same((struct prefix *)&aggr->p, + (struct prefix *)&rt->prefix)) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: External Route prefix same as Aggregator(%pFX), so dont flush.", + __func__, + &rt->prefix); + + return; + } + + info = rt->route_option; + assert(info); + + lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), + htonl(info->id), ospf6->router_id, ospf6->lsdb); + if (lsa) { + ext_lsa = (struct ospf6_as_external_lsa + *)((char *)(lsa->header) + + sizeof(struct ospf6_lsa_header)); + + if (rt->prefix.prefixlen != ext_lsa->prefix.prefix_length) + return; + + ospf6_external_lsa_purge(ospf6, lsa); + + /* Resetting the ID of route */ + rt->path.origin.id = 0; + info->id = 0; + } +} + +static void +ospf6_handle_external_aggr_add(struct ospf6 *ospf6) +{ + struct ospf6_route *rt = NULL; + struct ospf6_external_info *ei = NULL; + struct ospf6_external_aggr_rt *aggr; + + /* Delete all the aggregators which are marked as + * OSPF6_ROUTE_AGGR_DEL. + */ + ospf6_delete_all_marked_aggregators(ospf6); + + for (rt = ospf6_route_head(ospf6->external_table); rt; rt = ospf6_route_next(rt)) { + ei = rt->route_option; + if (ei != NULL) { + if (is_default_prefix(&rt->prefix)) + continue; + + aggr = ospf6_external_aggr_match(ospf6, + &rt->prefix); + + /* If matching aggregator found, Add + * the external route refrenace to the + * aggregator and originate the aggr + * route if it is advertisable. + * flush the external LSA if it is + * already originated for this external + * prefix. + */ + if (aggr) { + ospf6_originate_summary_lsa(ospf6, aggr, rt); + + /* All aggregated external rts + * are handled here. + */ + ospf6_handle_aggregated_exnl_rt( + ospf6, aggr, rt); + continue; + } + + /* External routes which are only out + * of aggregation will be handled here. + */ + ospf6_handle_exnl_rt_after_aggr_del( + ospf6, rt); + } + } +} + +static int ospf6_asbr_summary_process(struct thread *thread) +{ + struct ospf6 *ospf6 = THREAD_ARG(thread); + int operation = 0; + + ospf6->t_external_aggr = NULL; + operation = ospf6->aggr_action; + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: operation:%d", + __func__, + operation); + + switch (operation) { + case OSPF6_ROUTE_AGGR_ADD: + ospf6_handle_external_aggr_add(ospf6); + break; + case OSPF6_ROUTE_AGGR_DEL: + case OSPF6_ROUTE_AGGR_MODIFY: + ospf6_handle_external_aggr_update(ospf6); + break; + default: + break; + } + + return OSPF6_SUCCESS; +} + +static void +ospf6_start_asbr_summary_delay_timer(struct ospf6 *ospf6, + struct ospf6_external_aggr_rt *aggr, + ospf6_aggr_action_t operation) +{ + aggr->action = operation; + + if (ospf6->t_external_aggr) { + if (ospf6->aggr_action == OSPF6_ROUTE_AGGR_ADD) { + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Not required to restart timer,set is already added.", + __func__); + return; + } + + if (operation == OSPF6_ROUTE_AGGR_ADD) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s, Restarting Aggregator delay timer.", + __func__); + THREAD_OFF(ospf6->t_external_aggr); + } + } + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Start Aggregator delay timer %d(in seconds).", + __func__, ospf6->aggr_delay_interval); + + ospf6->aggr_action = operation; + thread_add_timer(master, + ospf6_asbr_summary_process, + ospf6, ospf6->aggr_delay_interval, + &ospf6->t_external_aggr); +} + +int ospf6_asbr_external_rt_advertise(struct ospf6 *ospf6, + struct prefix *p) +{ + struct route_node *rn; + struct ospf6_external_aggr_rt *aggr; + + rn = route_node_lookup(ospf6->rt_aggr_tbl, (struct prefix *)p); + if (!rn) + return OSPF6_INVALID; + + aggr = rn->info; + + route_unlock_node(rn); + + if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) + return OSPF6_INVALID; + + UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE); + + if (!OSPF6_EXTERNAL_RT_COUNT(aggr)) + return OSPF6_SUCCESS; + + ospf6_start_asbr_summary_delay_timer(ospf6, aggr, OSPF6_ROUTE_AGGR_MODIFY); + + return OSPF6_SUCCESS; +} + +int ospf6_external_aggr_delay_timer_set(struct ospf6 *ospf6, + unsigned int interval) +{ + ospf6->aggr_delay_interval = interval; + + return OSPF6_SUCCESS; +} + +static unsigned int ospf6_external_rt_hash_key(const void *data) +{ + const struct ospf6_route *rt = data; + unsigned int key = 0; + + key = prefix_hash_key(&rt->prefix); + return key; +} + +static bool ospf6_external_rt_hash_cmp(const void *d1, const void *d2) +{ + const struct ospf6_route *rt1 = d1; + const struct ospf6_route *rt2 = d2; + + return prefix_same((struct prefix *)&rt1->prefix, + (struct prefix *)&rt2->prefix); +} + +static struct ospf6_external_aggr_rt * +ospf6_external_aggr_new(struct prefix *p) +{ + struct ospf6_external_aggr_rt *aggr; + + aggr = (struct ospf6_external_aggr_rt *)XCALLOC( + MTYPE_OSPF6_EXTERNAL_RT_AGGR, + sizeof(struct ospf6_external_aggr_rt)); + + if (!aggr) + return NULL; + + aggr->p.family = p->family; + prefix_copy(&aggr->p, p); + aggr->p.prefixlen = p->prefixlen; + aggr->metric = -1; + aggr->mtype = DEFAULT_METRIC_TYPE; + aggr->match_extnl_hash = hash_create(ospf6_external_rt_hash_key, + ospf6_external_rt_hash_cmp, + "Ospf6 external route hash"); + return aggr; +} + +static void ospf6_external_aggr_add(struct ospf6 *ospf6, + struct ospf6_external_aggr_rt *aggr) +{ + struct route_node *rn; + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Adding Aggregate route to Aggr table (%pFX)", + __func__, + &aggr->p); + + rn = route_node_get(ospf6->rt_aggr_tbl, (struct prefix *)&aggr->p); + if (rn->info) + route_unlock_node(rn); + else + rn->info = aggr; +} + +int ospf6_asbr_external_rt_no_advertise(struct ospf6 *ospf6, + struct prefix *p) +{ + struct ospf6_external_aggr_rt *aggr; + route_tag_t tag = 0; + + aggr = ospf6_external_aggr_config_lookup(ospf6, p); + if (aggr) { + if (CHECK_FLAG(aggr->aggrflags, + OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) + return OSPF6_SUCCESS; + + SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE); + + aggr->tag = tag; + aggr->metric = -1; + + if (!OSPF6_EXTERNAL_RT_COUNT(aggr)) + return OSPF6_SUCCESS; + + ospf6_start_asbr_summary_delay_timer(ospf6, aggr, + OSPF6_ROUTE_AGGR_MODIFY); + } else { + aggr = ospf6_external_aggr_new(p); + + if (!aggr) + return OSPF6_FAILURE; + + SET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE); + ospf6_external_aggr_add(ospf6, aggr); + ospf6_start_asbr_summary_delay_timer(ospf6, aggr, + OSPF6_ROUTE_AGGR_ADD); + } + + return OSPF6_SUCCESS; +} + +struct ospf6_external_aggr_rt * +ospf6_external_aggr_config_lookup(struct ospf6 *ospf6, struct prefix *p) +{ + struct route_node *rn; + + rn = route_node_lookup(ospf6->rt_aggr_tbl, (struct prefix *)p); + if (rn) { + route_unlock_node(rn); + return rn->info; + } + + return NULL; +} + + +int ospf6_external_aggr_config_set(struct ospf6 *ospf6, struct prefix *p, + route_tag_t tag, int metric, int mtype) +{ + struct ospf6_external_aggr_rt *aggregator; + + aggregator = ospf6_external_aggr_config_lookup(ospf6, p); + + if (aggregator) { + if (CHECK_FLAG(aggregator->aggrflags, + OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) + UNSET_FLAG(aggregator->aggrflags, + OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE); + else if ((aggregator->tag == tag) + && (aggregator->metric == metric) + && (aggregator->mtype == mtype)) + return OSPF6_SUCCESS; + + aggregator->tag = tag; + aggregator->metric = metric; + aggregator->mtype = mtype; + + ospf6_start_asbr_summary_delay_timer(ospf6, aggregator, + OSPF6_ROUTE_AGGR_MODIFY); + } else { + aggregator = ospf6_external_aggr_new(p); + if (!aggregator) + return OSPF6_FAILURE; + + aggregator->tag = tag; + aggregator->metric = metric; + aggregator->mtype = mtype; + + ospf6_external_aggr_add(ospf6, aggregator); + ospf6_start_asbr_summary_delay_timer(ospf6, aggregator, + OSPF6_ROUTE_AGGR_ADD); + } + + return OSPF6_SUCCESS; +} + +int ospf6_external_aggr_config_unset(struct ospf6 *ospf6, + struct prefix *p) +{ + struct route_node *rn; + struct ospf6_external_aggr_rt *aggr; + + rn = route_node_lookup(ospf6->rt_aggr_tbl, (struct prefix *)p); + if (!rn) + return OSPF6_INVALID; + + aggr = rn->info; + + route_unlock_node(rn); + + if (!OSPF6_EXTERNAL_RT_COUNT(aggr)) { + ospf6_asbr_summary_config_delete(ospf6, rn); + ospf6_external_aggregator_free(aggr); + return OSPF6_SUCCESS; + } + + ospf6_start_asbr_summary_delay_timer(ospf6, aggr, + OSPF6_ROUTE_AGGR_DEL); + + return OSPF6_SUCCESS; +} + +void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6, + struct ospf6_route *rt, + struct prefix *p) +{ + + struct ospf6_external_aggr_rt *aggr; + struct ospf6_external_info *info; + struct prefix prefix_id; + struct route_node *node; + char pbuf[PREFIX2STR_BUFFER], ibuf[16]; + + if (!is_default_prefix(p)) { + aggr = ospf6_external_aggr_match(ospf6, + p); + + if (aggr) { + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("%s: Send Aggregate LSA (%pFX)", + __func__, + &aggr->p); + + ospf6_originate_summary_lsa( + ospf6, aggr, rt); + + /* Handling the case where the + * external route prefix + * and aggegate prefix is same + * If same dont flush the + * originated + * external LSA. + */ + ospf6_handle_aggregated_exnl_rt( + ospf6, aggr, rt); + return; + } + } + + info = rt->route_option; + + /* When the info->id = 0, it means it is being originated for the + * first time. + */ + if (!info->id) { + info->id = ospf6->external_id++; + + /* create/update binding in external_id_table */ + prefix_id.family = AF_INET; + prefix_id.prefixlen = 32; + prefix_id.u.prefix4.s_addr = htonl(info->id); + node = route_node_get(ospf6->external_id_table, &prefix_id); + node->info = rt; + + } + else { + prefix_id.family = AF_INET; + prefix_id.prefixlen = 32; + prefix_id.u.prefix4.s_addr = htonl(info->id); + } + + rt->path.origin.id = htonl(info->id); + + if (IS_OSPF6_DEBUG_ASBR) { + inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf)); + prefix2str(p, pbuf, sizeof(pbuf)); + zlog_debug("Advertise new AS-External Id:%s prefix %s metric %u", + ibuf, pbuf, rt->path.metric_type); + } + + ospf6_as_external_lsa_originate(rt, ospf6); + + return; +} + +void ospf6_unset_all_aggr_flag(struct ospf6 *ospf6) +{ + struct route_node *rn = NULL; + struct ospf6_external_aggr_rt *aggr; + + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug("Unset the origination bit for all aggregator"); + + /* Resetting the running external ID counter so that the origination + * of external LSAs starts from the beginning 0.0.0.1 */ + ospf6->external_id = OSPF6_EXT_INIT_LS_ID; + + for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) { + if (!rn->info) + continue; + + aggr = rn->info; + + UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED); + } +} diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index 7ccd1c992b..a4a6f5f3c9 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -46,6 +46,52 @@ struct ospf6_external_info { route_tag_t tag; ifindex_t ifindex; + +}; + +/* OSPF6 ASBR Summarisation */ +typedef enum { + OSPF6_ROUTE_AGGR_NONE = 0, + OSPF6_ROUTE_AGGR_ADD, + OSPF6_ROUTE_AGGR_DEL, + OSPF6_ROUTE_AGGR_MODIFY +}ospf6_aggr_action_t; + +#define OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE 0x1 +#define OSPF6_EXTERNAL_AGGRT_ORIGINATED 0x2 + +#define OSPF6_EXTERNAL_RT_COUNT(aggr) \ + (((struct ospf6_external_aggr_rt *)aggr)->match_extnl_hash->count) + +struct ospf6_external_aggr_rt { + /* range address and masklen */ + struct prefix p; + + /* use bits for OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE and + * OSPF6_EXTERNAL_AGGRT_ORIGINATED + */ + uint16_t aggrflags; + + /* To store external metric-type */ + uint8_t mtype; + + /* Route tag for summary address */ + route_tag_t tag; + + /* To store aggregated metric config */ + int metric; + + /* To Store the LS ID when LSA is originated */ + uint32_t id; + + /* How many prefixes are using this range */ + uint32_t refcount; + + /* Action to be done after delay timer expiry */ + int action; + + /* Hash table of matching external routes */ + struct hash *match_extnl_hash; }; /* AS-External-LSA */ @@ -110,8 +156,28 @@ extern void ospf6_asbr_distribute_list_update(struct ospf6 *ospf6, struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type, unsigned short instance); extern void ospf6_asbr_routemap_update(const char *mapname); -extern void ospf6_as_external_lsa_originate(struct ospf6_route *route, +extern struct ospf6_lsa *ospf6_as_external_lsa_originate(struct ospf6_route *route, struct ospf6 *ospf6); extern void ospf6_asbr_status_update(struct ospf6 *ospf6, int status); +int ospf6_asbr_external_rt_advertise(struct ospf6 *ospf6, + struct prefix *p); +int ospf6_external_aggr_delay_timer_set(struct ospf6 *ospf6, + unsigned int interval); +int ospf6_asbr_external_rt_no_advertise(struct ospf6 *ospf6, + struct prefix *p); + +struct ospf6_external_aggr_rt * +ospf6_external_aggr_config_lookup(struct ospf6 *ospf6, struct prefix *p); + +int ospf6_external_aggr_config_set(struct ospf6 *ospf6, struct prefix *p, + route_tag_t tag, int metric, int mtype); + +int ospf6_external_aggr_config_unset(struct ospf6 *ospf6, + struct prefix *p); +void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6, + struct ospf6_route *rt, + struct prefix *p); +void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr); +void ospf6_unset_all_aggr_flag(struct ospf6 *ospf6); #endif /* OSPF6_ASBR_H */ diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 738c2218fa..ca834b963b 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -106,7 +106,7 @@ void ospf6_lsa_originate(struct ospf6_lsa *lsa) lsdb_self = ospf6_get_scoped_lsdb_self(lsa); ospf6_lsdb_add(ospf6_lsa_copy(lsa), lsdb_self); - lsa->refresh = NULL; + THREAD_OFF(lsa->refresh); thread_add_timer(master, ospf6_lsa_refresh, lsa, OSPF_LS_REFRESH_TIME, &lsa->refresh); @@ -139,6 +139,31 @@ void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa, ospf6_lsa_originate(lsa); } +void ospf6_remove_id_from_external_id_table(struct ospf6 *ospf6, + uint32_t id) +{ + struct prefix prefix_id; + struct route_node *node; + + /* remove binding in external_id_table */ + prefix_id.family = AF_INET; + prefix_id.prefixlen = 32; + prefix_id.u.prefix4.s_addr = id; + node = route_node_lookup(ospf6->external_id_table, &prefix_id); + assert(node); + node->info = NULL; + route_unlock_node(node); /* to free the lookup lock */ + route_unlock_node(node); /* to free the original lock */ + +} + +void ospf6_external_lsa_purge(struct ospf6 *ospf6, struct ospf6_lsa *lsa) +{ + ospf6_lsa_purge(lsa); + + ospf6_remove_id_from_external_id_table(ospf6, lsa->header->id); +} + void ospf6_lsa_purge(struct ospf6_lsa *lsa) { struct ospf6_lsa *self; diff --git a/ospf6d/ospf6_flood.h b/ospf6d/ospf6_flood.h index 5515a1c3fe..4e4fc55ed4 100644 --- a/ospf6d/ospf6_flood.h +++ b/ospf6d/ospf6_flood.h @@ -39,6 +39,9 @@ extern void ospf6_lsa_originate_area(struct ospf6_lsa *lsa, struct ospf6_area *oa); extern void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa, struct ospf6_interface *oi); +void ospf6_remove_id_from_external_id_table(struct ospf6 *ospf6, + uint32_t id); +void ospf6_external_lsa_purge(struct ospf6 *ospf6, struct ospf6_lsa *lsa); extern void ospf6_lsa_purge(struct ospf6_lsa *lsa); extern void ospf6_lsa_purge_multi_ls_id(struct ospf6_area *oa, diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index bab5fdaae8..9c03ce21ed 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -45,6 +45,10 @@ #include "ospf6_flood.h" #include "ospf6d.h" +#ifndef VTYSH_EXTRACT_PL +#include "ospf6d/ospf6_lsa_clippy.c" +#endif + DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary"); @@ -822,6 +826,8 @@ int ospf6_lsa_expire(struct thread *thread) if (CHECK_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY)) return 0; /* dbexchange will do something ... */ ospf6 = ospf6_get_by_lsdb(lsa); + assert(ospf6); + /* reinstall lsa */ ospf6_install_lsa(lsa); @@ -994,6 +1000,30 @@ static char *ospf6_lsa_handler_name(const struct ospf6_lsa_handler *h) return buf; } +DEFPY (debug_ospf6_lsa_aggregation, + debug_ospf6_lsa_aggregation_cmd, + "[no] debug ospf6 lsa aggregation", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug Link State Advertisements (LSAs)\n" + "External LSA Aggregation\n") +{ + + struct ospf6_lsa_handler *handler; + + handler = ospf6_get_lsa_handler(OSPF6_LSTYPE_AS_EXTERNAL); + if (handler == NULL) + return CMD_WARNING_CONFIG_FAILED; + + if (no) + UNSET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_AGGR); + else + SET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_AGGR); + + return CMD_SUCCESS; +} + DEFUN (debug_ospf6_lsa_type, debug_ospf6_lsa_hex_cmd, "debug ospf6 lsa []", @@ -1105,6 +1135,9 @@ void install_element_ospf6_debug_lsa(void) install_element(ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd); install_element(CONFIG_NODE, &debug_ospf6_lsa_hex_cmd); install_element(CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd); + + install_element(ENABLE_NODE, &debug_ospf6_lsa_aggregation_cmd); + install_element(CONFIG_NODE, &debug_ospf6_lsa_aggregation_cmd); } int config_write_ospf6_debug_lsa(struct vty *vty) @@ -1128,6 +1161,8 @@ int config_write_ospf6_debug_lsa(struct vty *vty) if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_FLOOD)) vty_out(vty, "debug ospf6 lsa %s flooding\n", ospf6_lsa_handler_name(handler)); + if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_AGGR)) + vty_out(vty, "debug ospf6 lsa aggregation\n"); } return 0; diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 15b0d4ebbc..7b4fce6ff3 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -28,6 +28,7 @@ #define OSPF6_LSA_DEBUG_ORIGINATE 0x02 #define OSPF6_LSA_DEBUG_EXAMIN 0x04 #define OSPF6_LSA_DEBUG_FLOOD 0x08 +#define OSPF6_LSA_DEBUG_AGGR 0x10 /* OSPF LSA Default metric values */ #define DEFAULT_DEFAULT_METRIC 20 @@ -51,6 +52,8 @@ (ospf6_lstype_debug(type) & OSPF6_LSA_DEBUG_EXAMIN) #define IS_OSPF6_DEBUG_FLOOD_TYPE(type) \ (ospf6_lstype_debug(type) & OSPF6_LSA_DEBUG_FLOOD) +#define IS_OSPF6_DEBUG_AGGR \ + (ospf6_lstype_debug(OSPF6_LSTYPE_AS_EXTERNAL) & OSPF6_LSA_DEBUG_AGGR) \ /* LSA definition */ @@ -263,4 +266,5 @@ extern void install_element_ospf6_debug_lsa(void); extern void ospf6_lsa_age_set(struct ospf6_lsa *lsa); extern void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6); extern struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa); +struct ospf6_lsa *ospf6_find_external_lsa(struct ospf6 *ospf6, struct prefix *p); #endif /* OSPF6_LSA_H */ diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 304f03fde8..cbf517d045 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -30,6 +30,7 @@ #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" +#include "ospf6_asbr.h" #include "ospf6_route.h" #include "ospf6d.h" #include "bitfield.h" @@ -194,6 +195,28 @@ struct ospf6_lsa *ospf6_lsdb_lookup(uint16_t type, uint32_t id, return (struct ospf6_lsa *)node->info; } +struct ospf6_lsa *ospf6_find_external_lsa(struct ospf6 *ospf6, struct prefix *p) +{ + struct ospf6_route *match; + struct ospf6_lsa *lsa; + struct ospf6_external_info *info; + + match = ospf6_route_lookup(p, ospf6->external_table); + if (match == NULL) { + if (IS_OSPF6_DEBUG_ASBR) + zlog_debug("No such route %pFX to withdraw", p); + + return NULL; + } + + info = (struct ospf6_external_info *)(match->route_option); + assert(info); + + lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), + htonl(info->id), ospf6->router_id, ospf6->lsdb); + return lsa; +} + struct ospf6_lsa *ospf6_lsdb_lookup_next(uint16_t type, uint32_t id, uint32_t adv_router, struct ospf6_lsdb *lsdb) diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index a791a82cd4..01b735b1e8 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -161,6 +161,12 @@ struct ospf6_route { /* nexthop */ struct list *nh_list; + + /* points to the summarised route */ + struct ospf6_external_aggr_rt *aggr_route; + + /* For Aggr routes */ + bool to_be_processed; }; #define OSPF6_DEST_TYPE_NONE 0 diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 6f40989efd..513dfb14bc 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -409,13 +409,31 @@ static struct ospf6 *ospf6_create(const char *name) o->external_table = OSPF6_ROUTE_TABLE_CREATE(GLOBAL, EXTERNAL_ROUTES); o->external_table->scope = o; - + /* Setting this to 1, so that the LS ID 0 can be considered as invalid + * for self originated external LSAs. This helps in differentiating if + * an LSA is originated for any route or not in the route data. + * rt->route_option->id is by default 0 + * Consider a route having id as 0 and prefix as 1::1, an external LSA + * is originated with ID 0.0.0.0. Now consider another route 2::2 + * and for this LSA was not originated because of some configuration + * but the ID field rt->route_option->id is still 0.Consider now this + * 2::2 is being deleted, it will search LSA with LS ID as 0 and it + * will find the LSA and hence delete it but the LSA belonged to prefix + * 1::1, this happened because of LS ID 0. + */ + o->external_id = OSPF6_EXT_INIT_LS_ID; o->external_id_table = route_table_init(); o->write_oi_count = OSPF6_WRITE_INTERFACE_COUNT_DEFAULT; o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; o->distance_table = route_table_init(); + + o->rt_aggr_tbl = route_table_init(); + o->aggr_delay_interval = OSPF6_EXTL_AGGR_DEFAULT_DELAY; + o->t_external_aggr = NULL; + o->aggr_action = OSPF6_ROUTE_AGGR_NONE; + o->fd = -1; o->max_multipath = MULTIPATH_NUM; @@ -461,6 +479,7 @@ struct ospf6 *ospf6_instance_create(const char *name) void ospf6_delete(struct ospf6 *o) { struct listnode *node, *nnode; + struct route_node *rn = NULL; struct ospf6_area *oa; struct vrf *vrf; @@ -499,6 +518,11 @@ void ospf6_delete(struct ospf6 *o) ospf6_vrf_unlink(o, vrf); } + for (rn = route_top(o->rt_aggr_tbl); rn; rn = route_next(rn)) + if (rn->info) + ospf6_external_aggregator_free(rn->info); + route_table_finish(o->rt_aggr_tbl); + XFREE(MTYPE_OSPF6_TOP, o->name); XFREE(MTYPE_OSPF6_TOP, o); } @@ -527,6 +551,7 @@ static void ospf6_disable(struct ospf6 *o) THREAD_OFF(o->t_ase_calc); THREAD_OFF(o->t_distribute_update); THREAD_OFF(o->t_ospf6_receive); + THREAD_OFF(o->t_external_aggr); } } @@ -1672,6 +1697,386 @@ DEFUN(show_ipv6_ospf6_route_type_detail, show_ipv6_ospf6_route_type_detail_cmd, return CMD_SUCCESS; } +bool ospf6_is_valid_summary_addr(struct vty *vty, struct prefix *p) +{ + struct in6_addr addr_zero; + + memset(&addr_zero, 0, sizeof(struct in6_addr)); + + /* Default prefix validation*/ + if ((is_default_prefix((struct prefix *)p)) + || (!memcmp(&p->u.prefix6, &addr_zero, sizeof(struct in6_addr)))) { + vty_out(vty, "Default address should not be configured as summary address.\n"); + return false; + } + + /* Host route should not be configured as summary address */ + if (p->prefixlen == IPV6_MAX_PREFIXLEN) { + vty_out(vty, "Host route should not be configured as summary address.\n"); + return false; + } + + return true; +} + +/* External Route Aggregation */ +DEFPY (ospf6_external_route_aggregation, + ospf6_external_route_aggregation_cmd, + "summary-address X:X::X:X/M$prefix [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)$mtype}]", + "External summary address\n" + "Specify IPv6 prefix\n" + "Router tag \n" + "Router tag value\n" + "Metric \n" + "Advertised metric for this route\n" + "OSPFv3 exterior metric type for summarised routes\n" + "Set OSPFv3 External Type 1/2 metrics\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + struct prefix p; + int ret = CMD_SUCCESS; + p.family = AF_INET6; + ret = str2prefix(prefix_str, &p); + if (ret == 0) { + vty_out(vty, "Malformed prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Apply mask for given prefix. */ + apply_mask((struct prefix *)&p); + + if (!ospf6_is_valid_summary_addr(vty, &p)) + return CMD_WARNING_CONFIG_FAILED; + + if (!tag_str) + tag = 0; + + if (!metric_str) + metric = -1; + + if (!mtype_str) + mtype = DEFAULT_METRIC_TYPE; + + ret = ospf6_external_aggr_config_set(ospf6, &p, tag, metric, mtype); + if (ret == OSPF6_FAILURE) { + vty_out(vty, "Invalid configuration!!\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + return CMD_SUCCESS; +} + +DEFPY(no_ospf6_external_route_aggregation, + no_ospf6_external_route_aggregation_cmd, + "no summary-address X:X::X:X/M$prefix [tag (1-4294967295)] [{metric (0-16777215) | metric-type (1-2)}]", + NO_STR + "External summary address\n" + "Specify IPv6 prefix\n" + "Router tag\n" + "Router tag value\n" + "Metric \n" + "Advertised metric for this route\n" + "OSPFv3 exterior metric type for summarised routes\n" + "Set OSPFv3 External Type 1/2 metrics\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + struct prefix p; + int ret = CMD_SUCCESS; + + ret = str2prefix(prefix_str, &p); + if (ret == 0) { + vty_out(vty, "Malformed prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Apply mask for given prefix. */ + apply_mask((struct prefix *)&p); + + if (!ospf6_is_valid_summary_addr(vty, &p)) + return CMD_WARNING_CONFIG_FAILED; + + ret = ospf6_external_aggr_config_unset(ospf6, &p); + if (ret == OSPF6_INVALID) + vty_out(vty, "Invalid configuration!!\n"); + + return CMD_SUCCESS; +} + +DEFPY (ospf6_external_route_aggregation_no_advertise, + ospf6_external_route_aggregation_no_advertise_cmd, + "summary-address X:X::X:X/M$prefix no-advertise", + "External summary address\n" + "Specify IPv6 prefix\n" + "Don't advertise summary route \n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + struct prefix p; + int ret = CMD_SUCCESS; + + ret = str2prefix(prefix_str, &p); + if (ret == 0) { + vty_out(vty, "Malformed prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Apply mask for given prefix. */ + apply_mask((struct prefix *)&p); + + if (!ospf6_is_valid_summary_addr(vty, &p)) + return CMD_WARNING_CONFIG_FAILED; + + ret = ospf6_asbr_external_rt_no_advertise(ospf6, &p); + if (ret == OSPF6_INVALID) + vty_out(vty, "!!Invalid configuration\n"); + + return CMD_SUCCESS; +} + +DEFPY (no_ospf6_external_route_aggregation_no_advertise, + no_ospf6_external_route_aggregation_no_advertise_cmd, + "no summary-address X:X::X:X/M$prefix no-advertise", + NO_STR + "External summary address\n" + "Specify IPv6 prefix\n" + "Adverise summary route to the AS \n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + struct prefix p; + int ret = CMD_SUCCESS; + + ret = str2prefix(prefix_str, &p); + if (ret == 0) { + vty_out(vty, "Malformed prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Apply mask for given prefix. */ + apply_mask((struct prefix *)&p); + + if (!ospf6_is_valid_summary_addr(vty, &p)) + return CMD_WARNING_CONFIG_FAILED; + + ret = ospf6_asbr_external_rt_advertise(ospf6, &p); + if (ret == OSPF6_INVALID) + vty_out(vty, "!!Invalid configuration\n"); + + return CMD_SUCCESS; +} + +DEFPY (ospf6_route_aggregation_timer, + ospf6_route_aggregation_timer_cmd, + "aggregation timer (5-1800)", + "External route aggregation\n" + "Delay timer (in seconds)\n" + "Timer interval(in seconds)\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + ospf6_external_aggr_delay_timer_set(ospf6, timer); + + return CMD_SUCCESS; +} + +DEFPY (no_ospf6_route_aggregation_timer, + no_ospf6_route_aggregation_timer_cmd, + "no aggregation timer [5-1800]", + NO_STR + "External route aggregation\n" + "Delay timer\n" + "Timer interval(in seconds)\n") +{ + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + ospf6_external_aggr_delay_timer_set(ospf6, + OSPF6_EXTL_AGGR_DEFAULT_DELAY); + return CMD_SUCCESS; +} + +static int +ospf6_print_vty_external_routes_walkcb(struct hash_bucket *bucket, void *arg) +{ + struct ospf6_route *rt = bucket->data; + struct vty *vty = (struct vty *)arg; + static unsigned int count; + + vty_out(vty, "%pFX ", &rt->prefix); + + count++; + + if (count%5 == 0) + vty_out(vty, "\n"); + + if (OSPF6_EXTERNAL_RT_COUNT(rt->aggr_route) == count) + count = 0; + + return HASHWALK_CONTINUE; +} + +static int +ospf6_print_json_external_routes_walkcb(struct hash_bucket *bucket, void *arg) +{ + struct ospf6_route *rt = bucket->data; + struct json_object *json = (struct json_object *)arg; + char buf[PREFIX2STR_BUFFER]; + char exnalbuf[20]; + static unsigned int count; + + prefix2str(&rt->prefix, buf, sizeof(buf)); + + snprintf(exnalbuf, 20, "Exnl Addr-%d", count); + + json_object_string_add(json, exnalbuf, buf); + + count++; + + if (OSPF6_EXTERNAL_RT_COUNT(rt->aggr_route) == count) + count = 0; + + return HASHWALK_CONTINUE; +} + +static int +ospf6_show_summary_address(struct vty *vty, struct ospf6 *ospf6, + json_object *json, + bool uj, const char *detail) +{ + struct route_node *rn; + static char header[] = "Summary-address Metric-type Metric Tag External_Rt_count\n"; + + if (!uj) { + vty_out(vty, "aggregation delay interval :%d(in seconds)\n\n", + ospf6->aggr_delay_interval); + vty_out(vty, "%s\n", header); + } + else + json_object_int_add(json, "aggregation delay interval", + ospf6->aggr_delay_interval); + + for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) + if (rn->info) { + struct ospf6_external_aggr_rt *aggr = rn->info; + json_object *json_aggr = NULL; + char buf[PREFIX2STR_BUFFER]; + + prefix2str(&aggr->p, buf, sizeof(buf)); + + if (uj) { + + json_aggr = json_object_new_object(); + + json_object_object_add(json, + buf, + json_aggr); + + json_object_string_add(json_aggr, + "Summary address", + buf); + + json_object_string_add( + json_aggr, "Metric-type", + (aggr->mtype == DEFAULT_METRIC_TYPE) + ? "E2" + : "E1"); + + json_object_int_add(json_aggr, "Metric", + (aggr->metric != -1) + ? aggr->metric + : DEFAULT_DEFAULT_METRIC); + + json_object_int_add(json_aggr, "Tag", + aggr->tag); + + json_object_int_add(json_aggr, + "External route count", + OSPF6_EXTERNAL_RT_COUNT(aggr)); + + if (OSPF6_EXTERNAL_RT_COUNT(aggr) && detail) { + json_object_int_add(json_aggr, "ID", + aggr->id); + json_object_int_add(json_aggr, "Flags", + aggr->aggrflags); + hash_walk(aggr->match_extnl_hash, + ospf6_print_json_external_routes_walkcb, + json_aggr); + } + + } else { + vty_out(vty, "%-22s", buf); + + (aggr->mtype == DEFAULT_METRIC_TYPE) + ? vty_out(vty, "%-16s", "E2") + : vty_out(vty, "%-16s", "E1"); + vty_out(vty, "%-11d", (aggr->metric != -1) + ? aggr->metric + : DEFAULT_DEFAULT_METRIC); + + vty_out(vty, "%-12u", aggr->tag); + + vty_out(vty, "%-5ld\n", + OSPF6_EXTERNAL_RT_COUNT(aggr)); + + if (OSPF6_EXTERNAL_RT_COUNT(aggr) && detail) { + vty_out(vty, + "Matched External routes:\n"); + hash_walk(aggr->match_extnl_hash, + ospf6_print_vty_external_routes_walkcb, + vty); + vty_out(vty, "\n"); + } + + vty_out(vty, "\n"); + } + } + + return CMD_SUCCESS; +} + +DEFPY (show_ipv6_ospf6_external_aggregator, + show_ipv6_ospf6_external_aggregator_cmd, + "show ipv6 ospf6 summary-address [detail$detail] [json]", + SHOW_STR + IP6_STR + OSPF6_STR + "Show external summary addresses\n" + "detailed informtion\n" + JSON_STR) +{ + bool uj = use_json(argc, argv); + struct ospf6 *ospf6 = NULL; + json_object *json = NULL; + + if (uj) + json = json_object_new_object(); + + /* Default Vrf */ + ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME); + if (ospf6 == NULL) { + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else + vty_out(vty, "OSPFv3 is not running\n"); + + return CMD_SUCCESS; + } + + ospf6_show_summary_address(vty, ospf6, json, uj, detail); + + if (uj) { + vty_out(vty, "%s\n",json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + static void ospf6_stub_router_config_write(struct vty *vty, struct ospf6 *ospf6) { if (CHECK_FLAG(ospf6->flag, OSPF6_STUB_ROUTER)) { @@ -1711,6 +2116,41 @@ static int ospf6_distance_config_write(struct vty *vty, struct ospf6 *ospf6) return 0; } +static int ospf6_asbr_summary_config_write(struct vty *vty, struct ospf6 *ospf6) +{ + struct route_node *rn; + struct ospf6_external_aggr_rt *aggr; + char buf[PREFIX2STR_BUFFER]; + + if (ospf6->aggr_delay_interval != OSPF6_EXTL_AGGR_DEFAULT_DELAY) + vty_out(vty, " aggregation timer %u\n", + ospf6->aggr_delay_interval); + + /* print 'summary-address A:B::C:D/M' */ + for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) + if (rn->info) { + aggr = rn->info; + prefix2str(&aggr->p, buf, sizeof(buf)); + vty_out(vty, " summary-address %s ", buf); + if (aggr->tag) + vty_out(vty, " tag %u ", aggr->tag); + + if (aggr->metric != -1) + vty_out(vty, " metric %d ", aggr->metric); + + if (aggr->mtype != DEFAULT_METRIC_TYPE) + vty_out(vty, " metric-type %d ", aggr->mtype); + + if (CHECK_FLAG(aggr->aggrflags, + OSPF6_EXTERNAL_AGGRT_NO_ADVERTISE)) + vty_out(vty, " no-advertise"); + + vty_out(vty, "\n"); + } + + return 0; +} + /* OSPF configuration write function. */ static int config_write_ospf6(struct vty *vty) { @@ -1768,6 +2208,7 @@ static int config_write_ospf6(struct vty *vty) ospf6_spf_config_write(vty, ospf6); ospf6_distance_config_write(vty, ospf6); ospf6_distribute_config_write(vty, ospf6); + ospf6_asbr_summary_config_write(vty, ospf6); vty_out(vty, "!\n"); } @@ -1826,6 +2267,17 @@ void ospf6_top_init(void) install_element(OSPF6_NODE, &ospf6_max_multipath_cmd); install_element(OSPF6_NODE, &no_ospf6_max_multipath_cmd); + /* ASBR Summarisation */ + install_element(OSPF6_NODE, &ospf6_external_route_aggregation_cmd); + install_element(OSPF6_NODE, &no_ospf6_external_route_aggregation_cmd); + install_element(OSPF6_NODE, + &ospf6_external_route_aggregation_no_advertise_cmd); + install_element(OSPF6_NODE, + &no_ospf6_external_route_aggregation_no_advertise_cmd); + install_element(OSPF6_NODE, &ospf6_route_aggregation_timer_cmd); + install_element(OSPF6_NODE, &no_ospf6_route_aggregation_timer_cmd); + install_element(VIEW_NODE, &show_ipv6_ospf6_external_aggregator_cmd); + install_element(OSPF6_NODE, &ospf6_distance_cmd); install_element(OSPF6_NODE, &no_ospf6_distance_cmd); install_element(OSPF6_NODE, &ospf6_distance_ospf6_cmd); diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 3eb423f681..39165c9007 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -91,6 +91,7 @@ struct ospf6 { struct ospf6_route_table *external_table; struct route_table *external_id_table; +#define OSPF6_EXT_INIT_LS_ID 1 uint32_t external_id; /* OSPF6 redistribute configuration */ @@ -130,6 +131,7 @@ struct ospf6 { struct thread *maxage_remover; struct thread *t_distribute_update; /* Distirbute update timer. */ struct thread *t_ospf6_receive; /* OSPF6 receive timer */ + struct thread *t_external_aggr; /* OSPF6 aggregation timer */ #define OSPF6_WRITE_INTERFACE_COUNT_DEFAULT 20 struct thread *t_write; @@ -158,6 +160,16 @@ struct ospf6 { struct list *oi_write_q; uint32_t redist_count; + + /* Action for aggregation of external LSAs */ + int aggr_action; + +#define OSPF6_EXTL_AGGR_DEFAULT_DELAY 5 + /* For ASBR summary delay timer */ + int aggr_delay_interval; + /* Table of configured Aggregate addresses */ + struct route_table *rt_aggr_tbl; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(ospf6); @@ -188,4 +200,5 @@ struct ospf6 *ospf6_lookup_by_vrf_id(vrf_id_t vrf_id); struct ospf6 *ospf6_lookup_by_vrf_name(const char *name); const char *ospf6_vrf_id_to_name(vrf_id_t vrf_id); void ospf6_vrf_init(void); +bool ospf6_is_valid_summary_addr(struct vty *vty, struct prefix *p); #endif /* OSPF6_TOP_H */ diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h index e054803df3..5afece9b0a 100644 --- a/ospf6d/ospf6d.h +++ b/ospf6d/ospf6d.h @@ -49,6 +49,10 @@ extern struct thread_master *master; #define MSG_OK 0 #define MSG_NG 1 +#define OSPF6_SUCCESS 1 +#define OSPF6_FAILURE 0 +#define OSPF6_INVALID -1 + /* cast macro: XXX - these *must* die, ick ick. */ #define OSPF6_PROCESS(x) ((struct ospf6 *) (x)) #define OSPF6_AREA(x) ((struct ospf6_area *) (x)) diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index 2b7bce5392..e64b4cf0a5 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -90,6 +90,7 @@ ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la clippy_scan += \ ospf6d/ospf6_top.c \ ospf6d/ospf6_asbr.c \ + ospf6d/ospf6_lsa.c \ # end nodist_ospf6d_ospf6d_SOURCES = \