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 = \