diff options
Diffstat (limited to 'ospf6d')
| -rw-r--r-- | ospf6d/ospf6_abr.c | 14 | ||||
| -rw-r--r-- | ospf6d/ospf6_area.c | 2 | ||||
| -rw-r--r-- | ospf6d/ospf6_asbr.c | 1219 | ||||
| -rw-r--r-- | ospf6d/ospf6_asbr.h | 73 | ||||
| -rw-r--r-- | ospf6d/ospf6_flood.c | 37 | ||||
| -rw-r--r-- | ospf6d/ospf6_flood.h | 3 | ||||
| -rw-r--r-- | ospf6d/ospf6_interface.c | 49 | ||||
| -rw-r--r-- | ospf6d/ospf6_interface.h | 1 | ||||
| -rw-r--r-- | ospf6d/ospf6_intra.c | 46 | ||||
| -rw-r--r-- | ospf6d/ospf6_lsa.c | 35 | ||||
| -rw-r--r-- | ospf6d/ospf6_lsa.h | 5 | ||||
| -rw-r--r-- | ospf6d/ospf6_lsdb.c | 23 | ||||
| -rw-r--r-- | ospf6d/ospf6_nssa.c | 57 | ||||
| -rw-r--r-- | ospf6d/ospf6_route.c | 94 | ||||
| -rw-r--r-- | ospf6d/ospf6_route.h | 86 | ||||
| -rw-r--r-- | ospf6d/ospf6_spf.c | 2 | ||||
| -rw-r--r-- | ospf6d/ospf6_top.c | 514 | ||||
| -rw-r--r-- | ospf6d/ospf6_top.h | 17 | ||||
| -rw-r--r-- | ospf6d/ospf6_zebra.c | 21 | ||||
| -rw-r--r-- | ospf6d/ospf6d.h | 4 | ||||
| -rw-r--r-- | ospf6d/subdir.am | 1 |
21 files changed, 2043 insertions, 260 deletions
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index cc99d7c387..69be807c13 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -477,11 +477,11 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, monotime(&summary->changed); } + summary->prefix_options = route->prefix_options; summary->path.router_bits = route->path.router_bits; summary->path.options[0] = route->path.options[0]; summary->path.options[1] = route->path.options[1]; summary->path.options[2] = route->path.options[2]; - summary->path.prefix_options = route->path.prefix_options; summary->path.area_id = area->area_id; summary->path.type = OSPF6_PATH_TYPE_INTER; summary->path.subtype = route->path.subtype; @@ -514,7 +514,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, /* Fill Inter-Area-Prefix-LSA */ OSPF6_ABR_SUMMARY_METRIC_SET(prefix_lsa, route->path.cost); prefix_lsa->prefix.prefix_length = route->prefix.prefixlen; - prefix_lsa->prefix.prefix_options = route->path.prefix_options; + prefix_lsa->prefix.prefix_options = route->prefix_options; /* set Prefix */ memcpy(p, &route->prefix.u.prefix6, @@ -715,7 +715,7 @@ void ospf6_abr_defaults_to_stub(struct ospf6 *o) if (!o->backbone) return; - def = ospf6_route_create(); + def = ospf6_route_create(o); def->type = OSPF6_DEST_TYPE_NETWORK; def->prefix.family = AF_INET6; def->prefix.prefixlen = 0; @@ -1150,10 +1150,11 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) /* (5),(6): the path preference is handled by the sorting in the routing table. Always install the path by substituting old route (if any). */ - route = ospf6_route_create(); + route = ospf6_route_create(oa->ospf6); route->type = type; route->prefix = prefix; + route->prefix_options = prefix_options; route->path.origin.type = lsa->header->type; route->path.origin.id = lsa->header->id; route->path.origin.adv_router = lsa->header->adv_router; @@ -1161,7 +1162,6 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) route->path.options[0] = options[0]; route->path.options[1] = options[1]; route->path.options[2] = options[2]; - route->path.prefix_options = prefix_options; route->path.area_id = oa->area_id; route->path.type = OSPF6_PATH_TYPE_INTER; route->path.cost = abr_entry->path.cost + cost; @@ -1237,7 +1237,9 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) listcount(old_route->nh_list)); } } else { - struct ospf6_route *tmp_route = ospf6_route_create(); + struct ospf6_route *tmp_route; + + tmp_route = ospf6_route_create(oa->ospf6); ospf6_copy_nexthops(tmp_route->nh_list, o_path->nh_list); diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 355b8441bd..f4d9964a57 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -519,7 +519,7 @@ DEFUN (area_range, range = ospf6_route_lookup(&prefix, oa->range_table); if (range == NULL) { - range = ospf6_route_create(); + range = ospf6_route_create(ospf6); range->type = OSPF6_DEST_TYPE_RANGE; range->prefix = prefix; range->path.area_id = oa->area_id; diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 3e911a743a..165e409eed 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, @@ -70,9 +71,28 @@ unsigned char conf_debug_ospf6_asbr = 0; #define ZROUTE_NAME(x) zebra_route_string(x) +/* Originate Type-5 and Type-7 LSA */ +static struct ospf6_lsa *ospf6_originate_type5_type7_lsas( + struct ospf6_route *route, + struct ospf6 *ospf6) +{ + struct ospf6_lsa *lsa; + struct listnode *lnode; + struct ospf6_area *oa = NULL; + + lsa = ospf6_as_external_lsa_originate(route, ospf6); + + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) { + if (IS_AREA_NSSA(oa)) + ospf6_nssa_lsa_originate(route, oa); + } + + return lsa; +} + /* 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; @@ -121,7 +141,7 @@ void ospf6_as_external_lsa_originate(struct ospf6_route *route, as_external_lsa->prefix.prefix_length = route->prefix.prefixlen; /* PrefixOptions */ - as_external_lsa->prefix.prefix_options = route->path.prefix_options; + as_external_lsa->prefix.prefix_options = route->prefix_options; /* don't use refer LS-type */ as_external_lsa->prefix.prefix_refer_lstype = htons(0); @@ -164,6 +184,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) @@ -583,18 +605,18 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa) } } - route = ospf6_route_create(); + route = ospf6_route_create(ospf6); route->type = OSPF6_DEST_TYPE_NETWORK; route->prefix.family = AF_INET6; route->prefix.prefixlen = external->prefix.prefix_length; ospf6_prefix_in6_addr(&route->prefix.u.prefix6, external, &external->prefix); + route->prefix_options = external->prefix.prefix_options; route->path.area_id = asbr_entry->path.area_id; route->path.origin.type = lsa->header->type; route->path.origin.id = lsa->header->id; route->path.origin.adv_router = lsa->header->adv_router; - route->path.prefix_options = external->prefix.prefix_options; memcpy(&route->path.ls_prefix, &asbr_id, sizeof(struct prefix)); if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) { @@ -705,7 +727,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa, return; } - route_to_del = ospf6_route_create(); + route_to_del = ospf6_route_create(ospf6); route_to_del->type = OSPF6_DEST_TYPE_NETWORK; route_to_del->prefix.family = AF_INET6; route_to_del->prefix.prefixlen = external->prefix.prefix_length; @@ -1301,6 +1323,28 @@ 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, p); + if (node == NULL) + return NULL; + + if (IS_OSPF6_DEBUG_AGGR) { + 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; +} + void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, struct prefix *prefix, unsigned int nexthop_num, @@ -1308,8 +1352,6 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, struct ospf6 *ospf6) { route_map_result_t ret; - struct listnode *lnode; - struct ospf6_area *oa; struct ospf6_route troute; struct ospf6_external_info tinfo; struct ospf6_route *route, *match; @@ -1378,6 +1420,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,25 +1457,22 @@ 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)) - ospf6_nssa_lsa_originate(match, oa); - } return; } /* create new entry */ - route = ospf6_route_create(); + route = ospf6_route_create(ospf6); route->type = OSPF6_DEST_TYPE_NETWORK; prefix_copy(&route->prefix, prefix); + route->ospf6 = ospf6; 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,43 +1503,109 @@ 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; - - 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); - } + ospf6_handle_external_lsa_origination(ospf6, route, prefix); - route->path.origin.id = htonl(info->id); - ospf6_as_external_lsa_originate(route, ospf6); ospf6_asbr_status_update(ospf6, ospf6->redistribute); + +} + +static void ospf6_asbr_external_lsa_remove_by_id(struct ospf6 *ospf6, + uint32_t id) +{ + struct ospf6_lsa *lsa; + struct ospf6_area *oa; + struct listnode *lnode; + + 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); + + /* Delete the NSSA LSA */ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) { - if (IS_AREA_NSSA(oa)) - ospf6_nssa_lsa_originate(route, oa); + lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7), + htonl(id), ospf6->router_id, + oa->lsdb); + if (lsa) { + if (IS_OSPF6_DEBUG_ASBR) + zlog_debug("withdraw type 7 lsa, LS ID: %u", + htonl(id)); + + ospf6_lsa_purge(lsa); + } + } + +} + +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_asbr_summary_remove_lsa_and_route(struct ospf6 *ospf6, + struct ospf6_external_aggr_rt *aggr) +{ + + /* Send a Max age LSA if it is already originated.*/ + if (!CHECK_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED)) + return; + + 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); + + if (aggr->route) { + if (IS_OSPF6_DEBUG_AGGR) + zlog_debug( + "%s: Remove the blackhole route", + __func__); + ospf6_zebra_route_update_remove(aggr->route, ospf6); + ospf6_route_delete(aggr->route); + aggr->route = NULL; } + + aggr->id = 0; + /* Unset the Origination flag */ + UNSET_FLAG(aggr->aggrflags, OSPF6_EXTERNAL_AGGRT_ORIGINATED); +} + +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)) + ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr); } void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex, struct prefix *prefix, struct ospf6 *ospf6) { - 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]; match = ospf6_route_lookup(prefix, ospf6->external_table); if (match == NULL) { @@ -1517,44 +1623,17 @@ 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), - htonl(info->id), ospf6->router_id, - oa->lsdb); - if (lsa) { - if (IS_OSPF6_DEBUG_ASBR) { - zlog_debug("withdraw type 7 LSA for route %pFX", - prefix); - } - ospf6_lsa_purge(lsa); - } - } + /* 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); - /* 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 */ + if (IS_OSPF6_DEBUG_ASBR) + zlog_debug("Removing route from external table %pFX", + prefix); ospf6_route_remove(match, ospf6->external_table); XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info); @@ -1574,6 +1653,7 @@ DEFUN (ospf6_redistribute, VTY_DECLVAR_CONTEXT(ospf6, ospf6); char *proto = argv[argc - 1]->text; + type = proto_redistnum(AFI_IP6, proto); if (type < 0) return CMD_WARNING_CONFIG_FAILED; @@ -2613,3 +2693,988 @@ 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 */ +void ospf6_fill_aggr_route_details(struct ospf6 *ospf6, + struct ospf6_external_aggr_rt *aggr) +{ + struct ospf6_route *rt_aggr = aggr->route; + struct ospf6_external_info *ei_aggr = rt_aggr->route_option; + + rt_aggr->prefix = aggr->p; + ei_aggr->tag = aggr->tag; + ei_aggr->type = 0; + ei_aggr->id = aggr->id; + + /* When metric is not configured, apply the default metric */ + rt_aggr->path.cost = ((aggr->metric == -1) ? + DEFAULT_DEFAULT_METRIC + : (unsigned int)(aggr->metric)); + rt_aggr->path.metric_type = aggr->mtype; + + rt_aggr->path.origin.id = htonl(aggr->id); +} + +static void ospf6_originate_new_aggr_lsa(struct ospf6 *ospf6, + struct ospf6_external_aggr_rt *aggr) +{ + + struct prefix prefix_id; + struct route_node *node; + struct ospf6_lsa *lsa = NULL; + struct ospf6_route *rt_aggr; + struct ospf6_external_info *info; + + 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, aggr->metric); + + /* Create summary route and save it. */ + rt_aggr = ospf6_route_create(ospf6); + rt_aggr->type = OSPF6_DEST_TYPE_NETWORK; + /* Needed to install route while calling zebra api */ + SET_FLAG(rt_aggr->flag, OSPF6_ROUTE_BEST); + + info = XCALLOC(MTYPE_OSPF6_EXTERNAL_INFO, sizeof(*info)); + rt_aggr->route_option = info; + aggr->route = rt_aggr; + + /* Prepare the external_info for aggregator + * Fill all the details which will get advertised + */ + ospf6_fill_aggr_route_details(ospf6, aggr); + + /* Add next-hop to Null interface. */ + ospf6_add_route_nexthop_blackhole(rt_aggr); + + ospf6_zebra_route_update_add(rt_aggr, ospf6); + + /* Originate summary LSA */ + lsa = ospf6_originate_type5_type7_lsas(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); + } +} + +static void +ospf6_aggr_handle_advertise_change(struct ospf6 *ospf6, + struct ospf6_external_aggr_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__); + ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr); + + 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__); + + ospf6_originate_new_aggr_lsa(ospf6, 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_external_info *info = NULL; + struct ospf6_external_aggr_rt *old_aggr; + struct ospf6_as_external_lsa *external; + struct ospf6_route *rt_aggr = NULL; + 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_asbr_summary_remove_lsa_and_route(ospf6, aggr); + } + + 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; + } + + /* 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; + + /* Prepare the external_info for aggregator */ + ospf6_fill_aggr_route_details(ospf6, aggr); + rt_aggr = aggr->route; + /* If tag/metric/metric-type modified , then re-originate the + * route with modified tag/metric/metric-type details. + */ + if ((tag != 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, aggr->tag, + metric, + aggr->metric, + mtype, aggr->mtype, + &aggr->p); + + aggr_lsa = ospf6_originate_type5_type7_lsas(aggr->route, + 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(&aggr->p, &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); +} + +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 = rt->ospf6; + 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; + + (void)ospf6_originate_type5_type7_lsas(rt, ospf6); +} + +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); + + ospf6_asbr_summary_remove_lsa_and_route(ospf6, aggr); + + rn->info = NULL; + route_unlock_node(rn); +} + +static int +ospf6_handle_external_aggr_modify(struct ospf6 *ospf6, + struct ospf6_external_aggr_rt *aggr) +{ + struct ospf6_lsa *lsa = NULL; + struct ospf6_as_external_lsa *asel = NULL; + struct ospf6_route *rt_aggr; + unsigned int metric = 0; + route_tag_t tag = 0; + int mtype; + + 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); + + return OSPF6_FAILURE; + } + + 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 for advertisement */ + ospf6_fill_aggr_route_details(ospf6, aggr); + rt_aggr = aggr->route; + /* If tag/metric/metric-type modified , then + * re-originate the route with modified + * tag/metric/metric-type details. + */ + if ((tag != 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, + aggr->tag, + metric, + (unsigned int)rt_aggr->path.cost, + mtype, aggr->mtype, + &aggr->p); + + (void)ospf6_originate_type5_type7_lsas( + aggr->route, + ospf6); + } + + return OSPF6_SUCCESS; +} + +static void ospf6_handle_external_aggr_update(struct ospf6 *ospf6) +{ + struct route_node *rn = NULL; + int ret; + + 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; + + 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, + 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)) { + + ret = ospf6_handle_external_aggr_modify(ospf6, + aggr); + if (ret == OSPF6_FAILURE) + continue; + } + + /* 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, + 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) + continue; + + 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); + + (void)ospf6_originate_type5_type7_lsas(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(&aggr->p, &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) + continue; + + 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, 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(&rt1->prefix, &rt2->prefix); +} + +static struct ospf6_external_aggr_rt * +ospf6_external_aggr_new(struct prefix *p) +{ + struct ospf6_external_aggr_rt *aggr; + + aggr = XCALLOC(MTYPE_OSPF6_EXTERNAL_RT_AGGR, + sizeof(struct ospf6_external_aggr_rt)); + + prefix_copy(&aggr->p, p); + 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, &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, 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, 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; + + 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) { + zlog_debug("Advertise new AS-External Id:%pI4 prefix %pFX metric %u", + &prefix_id.u.prefix4, p, rt->path.metric_type); + } + + ospf6_originate_type5_type7_lsas(rt, ospf6); + +} + +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..0aa1374a46 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; + + /* Action to be done after delay timer expiry */ + int action; + + /* OSPFv3 route generated by summary address. */ + struct ospf6_route *route; + + /* Hash table of matching external routes */ + struct hash *match_extnl_hash; }; /* AS-External-LSA */ @@ -110,8 +156,31 @@ 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, - struct ospf6 *ospf6); +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); +void ospf6_fill_aggr_route_details(struct ospf6 *ospf6, + struct ospf6_external_aggr_rt *aggr); #endif /* OSPF6_ASBR_H */ diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 738c2218fa..3d52597161 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -89,6 +89,16 @@ void ospf6_lsa_originate(struct ospf6_lsa *lsa) struct ospf6_lsa *old; struct ospf6_lsdb *lsdb_self; + if (lsa->header->adv_router == INADDR_ANY) { + if (IS_OSPF6_DEBUG_ORIGINATE_TYPE(lsa->header->type)) + zlog_debug( + "Refusing to originate LSA (zero router ID): %s", + lsa->name); + + ospf6_lsa_delete(lsa); + return; + } + /* find previous LSA */ old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id, lsa->header->adv_router, lsa->lsdb); @@ -106,7 +116,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 +149,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_interface.c b/ospf6d/ospf6_interface.c index b52d6af90e..a169b9c60e 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -385,7 +385,6 @@ void ospf6_interface_connected_route_update(struct interface *ifp) struct connected *c; struct listnode *node, *nnode; struct in6_addr nh_addr; - int count = 0, max_addr_count; oi = (struct ospf6_interface *)ifp->info; if (oi == NULL) @@ -404,22 +403,10 @@ void ospf6_interface_connected_route_update(struct interface *ifp) /* update "route to advertise" interface route table */ ospf6_route_remove_all(oi->route_connected); - if (oi->ifmtu >= OSPF6_JUMBO_MTU) - max_addr_count = OSPF6_MAX_IF_ADDRS_JUMBO; - else - max_addr_count = OSPF6_MAX_IF_ADDRS; - for (ALL_LIST_ELEMENTS(oi->interface->connected, node, nnode, c)) { if (c->address->family != AF_INET6) continue; - /* number of interface addresses supported is based on MTU - * size of OSPFv3 packet - */ - count++; - if (count >= max_addr_count) - break; - CONTINUE_IF_ADDRESS_LINKLOCAL(IS_OSPF6_DEBUG_INTERFACE, c->address); CONTINUE_IF_ADDRESS_UNSPECIFIED(IS_OSPF6_DEBUG_INTERFACE, @@ -448,7 +435,7 @@ void ospf6_interface_connected_route_update(struct interface *ifp) } } - route = ospf6_route_create(); + route = ospf6_route_create(oi->area->ospf6); memcpy(&route->prefix, c->address, sizeof(struct prefix)); apply_mask(&route->prefix); route->type = OSPF6_DEST_TYPE_NETWORK; @@ -821,7 +808,9 @@ int interface_up(struct thread *thread) } /* decide next interface state */ - if (oi->type == OSPF_IFTYPE_POINTOPOINT) { + if (oi->type == OSPF_IFTYPE_LOOPBACK) { + ospf6_interface_state_change(OSPF6_INTERFACE_LOOPBACK, oi); + } else if (oi->type == OSPF_IFTYPE_POINTOPOINT) { ospf6_interface_state_change(OSPF6_INTERFACE_POINTTOPOINT, oi); } else if (oi->priority == 0) ospf6_interface_state_change(OSPF6_INTERFACE_DROTHER, oi); @@ -1728,7 +1717,6 @@ DEFUN (ipv6_ospf6_area, int idx_ipv4 = 3; uint32_t area_id; int format; - int ipv6_count = 0; assert(ifp); @@ -1743,23 +1731,6 @@ DEFUN (ipv6_ospf6_area, return CMD_SUCCESS; } - /* if more than OSPF6_MAX_IF_ADDRS are configured on this interface - * then don't allow ospfv3 to be configured - */ - ipv6_count = connected_count_by_family(ifp, AF_INET6); - if (oi->ifmtu == OSPF6_DEFAULT_MTU && ipv6_count > OSPF6_MAX_IF_ADDRS) { - vty_out(vty, - "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n", - ifp->name, OSPF6_MAX_IF_ADDRS, ipv6_count); - return CMD_WARNING_CONFIG_FAILED; - } else if (oi->ifmtu >= OSPF6_JUMBO_MTU - && ipv6_count > OSPF6_MAX_IF_ADDRS_JUMBO) { - vty_out(vty, - "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n", - ifp->name, OSPF6_MAX_IF_ADDRS_JUMBO, ipv6_count); - return CMD_WARNING_CONFIG_FAILED; - } - if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) { vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg); return CMD_WARNING_CONFIG_FAILED; @@ -2613,15 +2584,6 @@ static int config_write_interface(struct vty *vty) return write; } -static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf); -static struct cmd_node interface_node = { - .name = "interface", - .node = INTERFACE_NODE, - .parent_node = CONFIG_NODE, - .prompt = "%s(config-if)# ", - .config_write = config_write_interface, -}; - static int ospf6_ifp_create(struct interface *ifp) { if (IS_OSPF6_DEBUG_ZEBRA(RECV)) @@ -2679,8 +2641,7 @@ static int ospf6_ifp_destroy(struct interface *ifp) void ospf6_interface_init(void) { /* Install interface node. */ - install_node(&interface_node); - if_cmd_init(); + if_cmd_init(config_write_interface); if_zapi_callbacks(ospf6_ifp_create, ospf6_ifp_up, ospf6_ifp_down, ospf6_ifp_destroy); diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index c9cd74b691..b5efca743e 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -201,7 +201,6 @@ extern void ospf6_interface_disable(struct ospf6_interface *); extern void ospf6_interface_state_update(struct interface *); extern void ospf6_interface_connected_route_update(struct interface *); -extern void ospf6_interface_connected_route_add(struct connected *); extern struct in6_addr * ospf6_interface_get_global_address(struct interface *ifp); diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index c971c6180e..e4db8f3a02 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -767,7 +767,6 @@ int ospf6_link_lsa_originate(struct thread *thread) struct ospf6_link_lsa *link_lsa; struct ospf6_route *route; struct ospf6_prefix *op; - int count, max_addr_count; oi = (struct ospf6_interface *)THREAD_ARG(thread); oi->thread_link_lsa = NULL; @@ -811,30 +810,22 @@ int ospf6_link_lsa_originate(struct thread *thread) memcpy(link_lsa->options, oi->area->options, 3); memcpy(&link_lsa->linklocal_addr, oi->linklocal_addr, sizeof(struct in6_addr)); + link_lsa->prefix_num = htonl(oi->route_connected->count); op = (struct ospf6_prefix *)((caddr_t)link_lsa + sizeof(struct ospf6_link_lsa)); - /* connected prefix to advertise, number of interface addresses - * supported is based on MTU size of OSPFv3 packets - */ - if (oi->ifmtu >= OSPF6_JUMBO_MTU) - max_addr_count = OSPF6_MAX_IF_ADDRS_JUMBO; - else - max_addr_count = OSPF6_MAX_IF_ADDRS; - for (route = ospf6_route_head(oi->route_connected), count = 0; - route && count < max_addr_count; - route = ospf6_route_next(route), count++) { + /* connected prefix to advertise */ + for (route = ospf6_route_head(oi->route_connected); route; + route = ospf6_route_next(route)) { op->prefix_length = route->prefix.prefixlen; - op->prefix_options = route->path.prefix_options; + op->prefix_options = route->prefix_options; op->prefix_metric = htons(0); memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6, OSPF6_PREFIX_SPACE(op->prefix_length)); op = OSPF6_PREFIX_NEXT(op); } - link_lsa->prefix_num = htonl(count); - /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = htons(OSPF6_LSTYPE_LINK); @@ -1014,7 +1005,6 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread) unsigned short prefix_num = 0; struct ospf6_route_table *route_advertise; int ls_id = 0; - int count, max_addr_count; oa = (struct ospf6_area *)THREAD_ARG(thread); oa->thread_intra_prefix_lsa = NULL; @@ -1060,8 +1050,6 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread) intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id; route_advertise = ospf6_route_table_create(0, 0); - route_advertise->hook_add = NULL; - route_advertise->hook_remove = NULL; for (ALL_LIST_ELEMENTS_RO(oa->if_list, i, oi)) { if (oi->state == OSPF6_INTERFACE_DOWN) { @@ -1090,14 +1078,8 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread) zlog_debug(" Interface %s:", oi->interface->name); /* connected prefix to advertise */ - if (oi->ifmtu >= OSPF6_JUMBO_MTU) - max_addr_count = OSPF6_MAX_IF_ADDRS_JUMBO; - else - max_addr_count = OSPF6_MAX_IF_ADDRS; - - for (route = ospf6_route_head(oi->route_connected), count = 0; - route && count < max_addr_count; - route = ospf6_route_best_next(route), count++) { + for (route = ospf6_route_head(oi->route_connected); route; + route = ospf6_route_best_next(route)) { if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX)) zlog_debug(" include %pFX", &route->prefix); ospf6_route_add(ospf6_route_copy(route), @@ -1193,7 +1175,7 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread) } op->prefix_length = route->prefix.prefixlen; - op->prefix_options = route->path.prefix_options; + op->prefix_options = route->prefix_options; op->prefix_metric = htons(route->path.cost); memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6, OSPF6_PREFIX_SPACE(op->prefix_length)); @@ -1312,8 +1294,6 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) /* connected prefix to advertise */ route_advertise = ospf6_route_table_create(0, 0); - route_advertise->hook_add = NULL; - route_advertise->hook_remove = NULL; type = ntohs(OSPF6_LSTYPE_LINK); for (ALL_LSDB_TYPED(oi->lsdb, type, lsa)) { @@ -1347,7 +1327,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) || current + OSPF6_PREFIX_SIZE(op) > end) break; - route = ospf6_route_create(); + route = ospf6_route_create(oi->area->ospf6); route->type = OSPF6_DEST_TYPE_NETWORK; route->prefix.family = AF_INET6; @@ -1356,6 +1336,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) sizeof(struct in6_addr)); memcpy(&route->prefix.u.prefix6, OSPF6_PREFIX_BODY(op), OSPF6_PREFIX_SPACE(op->prefix_length)); + route->prefix_options = op->prefix_options; route->path.origin.type = lsa->header->type; route->path.origin.id = lsa->header->id; @@ -1363,7 +1344,6 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) route->path.options[0] = link_lsa->options[0]; route->path.options[1] = link_lsa->options[1]; route->path.options[2] = link_lsa->options[2]; - route->path.prefix_options = op->prefix_options; route->path.area_id = oi->area->area_id; route->path.type = OSPF6_PATH_TYPE_INTRA; @@ -1384,7 +1364,7 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) for (route = ospf6_route_head(route_advertise); route; route = ospf6_route_best_next(route)) { op->prefix_length = route->prefix.prefixlen; - op->prefix_options = route->path.prefix_options; + op->prefix_options = route->prefix_options; op->prefix_metric = htons(0); memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6, OSPF6_PREFIX_SPACE(op->prefix_length)); @@ -1810,19 +1790,19 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa) continue; } - route = ospf6_route_create(); + route = ospf6_route_create(oa->ospf6); memset(&route->prefix, 0, sizeof(struct prefix)); route->prefix.family = AF_INET6; route->prefix.prefixlen = op->prefix_length; ospf6_prefix_in6_addr(&route->prefix.u.prefix6, intra_prefix_lsa, op); + route->prefix_options = op->prefix_options; route->type = OSPF6_DEST_TYPE_NETWORK; route->path.origin.type = lsa->header->type; route->path.origin.id = lsa->header->id; route->path.origin.adv_router = lsa->header->adv_router; - route->path.prefix_options = op->prefix_options; route->path.area_id = oa->area_id; route->path.type = OSPF6_PATH_TYPE_INTRA; route->path.metric_type = 1; 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 <router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown> [<originate|examine|flooding>]", @@ -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..4c95ee69bd 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,6 @@ 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..039c65d739 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 = 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_nssa.c b/ospf6d/ospf6_nssa.c index 9f8cdf8fb7..470a5b1338 100644 --- a/ospf6d/ospf6_nssa.c +++ b/ospf6d/ospf6_nssa.c @@ -1159,10 +1159,49 @@ static void ospf6_nssa_flush_area(struct ospf6_area *area) } } -static void ospf6_area_nssa_update(struct ospf6_area *area) +static void ospf6_check_and_originate_type7_lsa(struct ospf6_area *area) { struct ospf6_route *route; + struct route_node *rn = NULL; + struct ospf6_external_aggr_rt *aggr; + + /* Loop through the external_table to find the LSAs originated + * without aggregation and originate type-7 LSAs for them. + */ + for (route = ospf6_route_head( + area->ospf6->external_table); + route; route = ospf6_route_next(route)) { + /* This means the Type-5 LSA was originated for this route */ + if (route->path.origin.id != 0) + ospf6_nssa_lsa_originate(route, area); + + } + + /* Loop through the aggregation table to originate type-7 LSAs + * for the aggregated type-5 LSAs + */ + for (rn = route_top(area->ospf6->rt_aggr_tbl); rn; + rn = route_next(rn)) { + if (!rn->info) + continue; + + aggr = rn->info; + + if (CHECK_FLAG(aggr->aggrflags, + OSPF6_EXTERNAL_AGGRT_ORIGINATED)) { + if (IS_OSPF6_DEBUG_NSSA) + zlog_debug( + "Originating Type-7 LSAs for area %s", + area->name); + + ospf6_nssa_lsa_originate(aggr->route, area); + } + } +} + +static void ospf6_area_nssa_update(struct ospf6_area *area) +{ if (IS_AREA_NSSA(area)) { if (!ospf6_check_and_set_router_abr(area->ospf6)) OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E); @@ -1194,10 +1233,7 @@ static void ospf6_area_nssa_update(struct ospf6_area *area) zlog_debug("NSSA area %s", area->name); /* Originate NSSA LSA */ - for (route = ospf6_route_head( - area->ospf6->external_table); - route; route = ospf6_route_next(route)) - ospf6_nssa_lsa_originate(route, area); + ospf6_check_and_originate_type7_lsa(area); } } else { /* Disable NSSA */ @@ -1259,13 +1295,10 @@ void ospf6_nssa_lsa_originate(struct ospf6_route *route, struct in6_addr *fwd_addr; struct ospf6_as_external_lsa *as_external_lsa; - char buf[PREFIX2STR_BUFFER]; caddr_t p; - if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL)) { - prefix2str(&route->prefix, buf, sizeof(buf)); - zlog_debug("Originate AS-External-LSA for %s", buf); - } + if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL)) + zlog_debug("Originate NSSA-LSA for %pFX", &route->prefix); /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); @@ -1296,7 +1329,7 @@ void ospf6_nssa_lsa_originate(struct ospf6_route *route, as_external_lsa->prefix.prefix_length = route->prefix.prefixlen; /* PrefixOptions */ - as_external_lsa->prefix.prefix_options = route->path.prefix_options; + as_external_lsa->prefix.prefix_options = route->prefix_options; /* Set the P bit */ as_external_lsa->prefix.prefix_options |= OSPF6_PREFIX_OPTION_P; @@ -1334,7 +1367,7 @@ void ospf6_nssa_lsa_originate(struct ospf6_route *route, lsa_header->adv_router = area->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id, - lsa_header->adv_router, area->ospf6->lsdb); + lsa_header->adv_router, area->lsdb); lsa_header->length = htons((caddr_t)p - (caddr_t)lsa_header); /* LSA checksum */ diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 0a026785f4..cd3139d28a 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -284,12 +284,21 @@ void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr) struct ospf6_nexthop nh_match; if (nh_list) { - nh_match.ifindex = ifindex; - if (addr != NULL) + if (addr) { + if (ifindex) + nh_match.type = NEXTHOP_TYPE_IPV6_IFINDEX; + else + nh_match.type = NEXTHOP_TYPE_IPV6; + memcpy(&nh_match.address, addr, sizeof(struct in6_addr)); - else + } else { + nh_match.type = NEXTHOP_TYPE_IFINDEX; + memset(&nh_match.address, 0, sizeof(struct in6_addr)); + } + + nh_match.ifindex = ifindex; if (!ospf6_route_find_nexthop(nh_list, &nh_match)) { nh = ospf6_nexthop_create(); @@ -299,36 +308,76 @@ void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr) } } +void ospf6_add_route_nexthop_blackhole(struct ospf6_route *route) +{ + struct ospf6_nexthop *nh; + struct ospf6_nexthop nh_match = {}; + + /* List not allocated. */ + if (route->nh_list == NULL) + return; + + /* Entry already exists. */ + nh_match.type = NEXTHOP_TYPE_BLACKHOLE; + if (ospf6_route_find_nexthop(route->nh_list, &nh_match)) + return; + + nh = ospf6_nexthop_create(); + ospf6_nexthop_copy(nh, &nh_match); + listnode_add(route->nh_list, nh); +} + void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route, struct zapi_nexthop nexthops[], int entries, vrf_id_t vrf_id) { struct ospf6_nexthop *nh; struct listnode *node; - char buf[64]; int i; if (route) { i = 0; for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) { if (IS_OSPF6_DEBUG_ZEBRA(SEND)) { - const char *ifname; - inet_ntop(AF_INET6, &nh->address, buf, - sizeof(buf)); - ifname = ifindex2ifname(nh->ifindex, vrf_id); - zlog_debug(" nexthop: %s%%%.*s(%d)", buf, - IFNAMSIZ, ifname, nh->ifindex); + zlog_debug(" nexthop: %s %pI6%%%.*s(%d)", + nexthop_type_to_str(nh->type), + &nh->address, IFNAMSIZ, + ifindex2ifname(nh->ifindex, vrf_id), + nh->ifindex); } + if (i >= entries) return; nexthops[i].vrf_id = vrf_id; - nexthops[i].ifindex = nh->ifindex; - if (!IN6_IS_ADDR_UNSPECIFIED(&nh->address)) { + nexthops[i].type = nh->type; + + switch (nh->type) { + case NEXTHOP_TYPE_BLACKHOLE: + /* NOTHING */ + break; + + case NEXTHOP_TYPE_IFINDEX: + nexthops[i].ifindex = nh->ifindex; + break; + + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4: + /* + * OSPFv3 with IPv4 routes is not supported + * yet. Skip this next hop. + */ + if (IS_OSPF6_DEBUG_ZEBRA(SEND)) + zlog_debug(" Skipping IPv4 next hop"); + continue; + + case NEXTHOP_TYPE_IPV6_IFINDEX: + nexthops[i].ifindex = nh->ifindex; + /* FALLTHROUGH */ + case NEXTHOP_TYPE_IPV6: nexthops[i].gate.ipv6 = nh->address; - nexthops[i].type = NEXTHOP_TYPE_IPV6_IFINDEX; - } else - nexthops[i].type = NEXTHOP_TYPE_IFINDEX; + break; + } i++; } } @@ -404,7 +453,7 @@ void ospf6_copy_paths(struct list *dst, struct list *src) } } -struct ospf6_route *ospf6_route_create(void) +struct ospf6_route *ospf6_route_create(struct ospf6 *ospf6) { struct ospf6_route *route; @@ -415,6 +464,8 @@ struct ospf6_route *ospf6_route_create(void) route->paths = list_new(); route->paths->cmp = (int (*)(void *, void *))ospf6_path_cmp; route->paths->del = (void (*)(void *))ospf6_path_free; + route->ospf6 = ospf6; + return route; } @@ -433,9 +484,10 @@ struct ospf6_route *ospf6_route_copy(struct ospf6_route *route) { struct ospf6_route *new; - new = ospf6_route_create(); + new = ospf6_route_create(route->ospf6); new->type = route->type; memcpy(&new->prefix, &route->prefix, sizeof(struct prefix)); + new->prefix_options = route->prefix_options; new->installed = route->installed; new->changed = route->changed; new->flag = route->flag; @@ -1137,6 +1189,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route, { char destination[PREFIX2STR_BUFFER], nexthop[64]; char area_id[16], id[16], adv_router[16], capa[16], options[16]; + char pfx_options[16]; struct timeval now, res; char duration[64]; struct listnode *node; @@ -1264,10 +1317,13 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route, vty_out(vty, "Router Bits: %s\n", capa); /* Prefix Options */ + ospf6_prefix_options_printbuf(route->prefix_options, pfx_options, + sizeof(pfx_options)); if (use_json) - json_object_string_add(json_route, "prefixOptions", "xxx"); + json_object_string_add(json_route, "prefixOptions", + pfx_options); else - vty_out(vty, "Prefix Options: xxx\n"); + vty_out(vty, "Prefix Options: %s\n", pfx_options); /* Metrics */ if (use_json) { diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index a791a82cd4..991720ec2e 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -24,6 +24,7 @@ #include "command.h" #include "zclient.h" #include "lib/json.h" +#include "lib/nexthop.h" #define OSPF6_MULTI_PATH_LIMIT 4 @@ -44,23 +45,60 @@ struct ospf6_nexthop { /* IP address, if any */ struct in6_addr address; + + /** Next-hop type information. */ + enum nexthop_types_t type; }; -#define ospf6_nexthop_is_set(x) \ - ((x)->ifindex || !IN6_IS_ADDR_UNSPECIFIED(&(x)->address)) -#define ospf6_nexthop_is_same(a, b) \ - ((a)->ifindex == (b)->ifindex \ - && IN6_ARE_ADDR_EQUAL(&(a)->address, &(b)->address)) -#define ospf6_nexthop_clear(x) \ - do { \ - (x)->ifindex = 0; \ - memset(&(x)->address, 0, sizeof(struct in6_addr)); \ - } while (0) -#define ospf6_nexthop_copy(a, b) \ - do { \ - (a)->ifindex = (b)->ifindex; \ - memcpy(&(a)->address, &(b)->address, sizeof(struct in6_addr)); \ - } while (0) +static inline bool ospf6_nexthop_is_set(const struct ospf6_nexthop *nh) +{ + return nh->type != 0; +} + +static inline bool ospf6_nexthop_is_same(const struct ospf6_nexthop *nha, + const struct ospf6_nexthop *nhb) +{ + if (nha->type != nhb->type) + return false; + + switch (nha->type) { + case NEXTHOP_TYPE_BLACKHOLE: + /* NOTHING */ + break; + + case NEXTHOP_TYPE_IFINDEX: + if (nha->ifindex != nhb->ifindex) + return false; + break; + + case NEXTHOP_TYPE_IPV4_IFINDEX: + case NEXTHOP_TYPE_IPV4: + /* OSPFv3 does not support IPv4 next hops. */ + return false; + + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (nha->ifindex != nhb->ifindex) + return false; + /* FALLTHROUGH */ + case NEXTHOP_TYPE_IPV6: + if (!IN6_ARE_ADDR_EQUAL(&nha->address, &nhb->address)) + return false; + break; + } + + return true; +} + +static inline void ospf6_nexthop_clear(struct ospf6_nexthop *nh) +{ + memset(nh, 0, sizeof(*nh)); +} + +static inline void ospf6_nexthop_copy(struct ospf6_nexthop *nha, + const struct ospf6_nexthop *nhb) +{ + memcpy(nha, nhb, sizeof(*nha)); +} /* Path */ struct ospf6_ls_origin { @@ -79,9 +117,6 @@ struct ospf6_path { /* Optional Capabilities */ uint8_t options[3]; - /* Prefix Options */ - uint8_t prefix_options; - /* Associated Area */ in_addr_t area_id; @@ -127,6 +162,9 @@ struct ospf6_route { struct ospf6_route *prev; struct ospf6_route *next; + /* Back pointer to ospf6 */ + struct ospf6 *ospf6; + unsigned int lock; /* Destination Type */ @@ -147,6 +185,9 @@ struct ospf6_route { /* flag */ uint8_t flag; + /* Prefix Options */ + uint8_t prefix_options; + /* route option */ void *route_option; @@ -161,6 +202,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 @@ -279,6 +326,7 @@ extern void ospf6_copy_nexthops(struct list *dst, struct list *src); extern void ospf6_merge_nexthops(struct list *dst, struct list *src); extern void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr); +extern void ospf6_add_route_nexthop_blackhole(struct ospf6_route *route); extern int ospf6_num_nexthops(struct list *nh_list); extern int ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b); @@ -294,7 +342,7 @@ extern int ospf6_route_get_first_nh_index(struct ospf6_route *route); #define ospf6_route_add_nexthop(route, ifindex, addr) \ ospf6_add_nexthop(route->nh_list, ifindex, addr) -extern struct ospf6_route *ospf6_route_create(void); +extern struct ospf6_route *ospf6_route_create(struct ospf6 *ospf6); extern void ospf6_route_delete(struct ospf6_route *); extern struct ospf6_route *ospf6_route_copy(struct ospf6_route *route); extern int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb); diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 051b3a63ef..4e7a7146eb 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -374,7 +374,7 @@ static int ospf6_spf_install(struct ospf6_vertex *v, up to here. */ assert(route == NULL); - route = ospf6_route_create(); + route = ospf6_route_create(v->area->ospf6); memcpy(&route->prefix, &v->vertex_id, sizeof(struct prefix)); route->type = OSPF6_DEST_TYPE_LINKSTATE; route->path.type = OSPF6_PATH_TYPE_INTRA; diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 6f40989efd..6105e2c24b 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); } } @@ -690,6 +715,7 @@ static void ospf6_process_reset(struct ospf6 *ospf6) struct interface *ifp; struct vrf *vrf = vrf_lookup_by_id(ospf6->vrf_id); + ospf6_unset_all_aggr_flag(ospf6); ospf6_flush_self_originated_lsas_now(ospf6); ospf6->inst_shutdown = 0; ospf6_db_clear(ospf6); @@ -989,7 +1015,6 @@ DEFUN_HIDDEN (ospf6_interface_area, struct ospf6_interface *oi; struct interface *ifp; vrf_id_t vrf_id = VRF_DEFAULT; - int ipv6_count = 0; uint32_t area_id; int format; @@ -1012,23 +1037,6 @@ DEFUN_HIDDEN (ospf6_interface_area, return CMD_SUCCESS; } - /* if more than OSPF6_MAX_IF_ADDRS are configured on this interface - * then don't allow ospfv3 to be configured - */ - ipv6_count = connected_count_by_family(ifp, AF_INET6); - if (oi->ifmtu == OSPF6_DEFAULT_MTU && ipv6_count > OSPF6_MAX_IF_ADDRS) { - vty_out(vty, - "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n", - ifp->name, OSPF6_MAX_IF_ADDRS, ipv6_count); - return CMD_WARNING_CONFIG_FAILED; - } else if (oi->ifmtu >= OSPF6_JUMBO_MTU - && ipv6_count > OSPF6_MAX_IF_ADDRS_JUMBO) { - vty_out(vty, - "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n", - ifp->name, OSPF6_MAX_IF_ADDRS_JUMBO, ipv6_count); - return CMD_WARNING_CONFIG_FAILED; - } - if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) { vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg); return CMD_WARNING_CONFIG_FAILED; @@ -1672,6 +1680,424 @@ 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_BITLEN) { + 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, sizeof(exnalbuf), "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 void +ospf6_show_vrf_name(struct vty *vty, struct ospf6 *ospf6, + json_object *json) +{ + if (json) { + if (ospf6->vrf_id == VRF_DEFAULT) + json_object_string_add(json, "vrfName", + "default"); + else + json_object_string_add(json, "vrfName", + ospf6->name); + json_object_int_add(json, "vrfId", ospf6->vrf_id); + } else { + if (ospf6->vrf_id == VRF_DEFAULT) + vty_out(vty, "VRF Name: %s\n", "default"); + else if (ospf6->name) + vty_out(vty, "VRF Name: %s\n", ospf6->name); + } +} + +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 const char header[] = "Summary-address Metric-type Metric Tag External_Rt_count\n"; + json_object *json_vrf = NULL; + + if (!uj) { + ospf6_show_vrf_name(vty, ospf6, json_vrf); + vty_out(vty, "aggregation delay interval :%d(in seconds)\n\n", + ospf6->aggr_delay_interval); + vty_out(vty, "%s\n", header); + } else { + json_vrf = json_object_new_object(); + + ospf6_show_vrf_name(vty, ospf6, json_vrf); + + json_object_int_add(json_vrf, "aggregation delay interval", + ospf6->aggr_delay_interval); + } + + + for (rn = route_top(ospf6->rt_aggr_tbl); rn; rn = route_next(rn)) { + if (!rn->info) + continue; + + 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_vrf, + 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"); + } + } + + if (uj) + json_object_object_add(json, ospf6->name, + json_vrf); + + return CMD_SUCCESS; +} + +DEFPY (show_ipv6_ospf6_external_aggregator, + show_ipv6_ospf6_external_aggregator_cmd, + "show ipv6 ospf6 [vrf <NAME|all>] summary-address [detail$detail] [json]", + SHOW_STR + IP6_STR + OSPF6_STR + VRF_CMD_HELP_STR + "All VRFs\n" + "Show external summary addresses\n" + "detailed informtion\n" + JSON_STR) +{ + bool uj = use_json(argc, argv); + struct ospf6 *ospf6 = NULL; + json_object *json = NULL; + const char *vrf_name = NULL; + struct listnode *node; + bool all_vrf = false; + int idx_vrf = 0; + + if (uj) + json = json_object_new_object(); + + OSPF6_CMD_CHECK_RUNNING(); + OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + + for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { + if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) { + + ospf6_show_summary_address(vty, ospf6, json, uj, + detail); + + if (!all_vrf) + break; + } + } + + 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 +2137,44 @@ 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) + continue; + + 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 +2232,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 +2291,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..fe02cd3f84 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,16 +160,22 @@ 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); #define OSPF6_DISABLED 0x01 #define OSPF6_STUB_ROUTER 0x02 -#define OSPF6_MAX_IF_ADDRS 100 -#define OSPF6_MAX_IF_ADDRS_JUMBO 200 -#define OSPF6_DEFAULT_MTU 1500 -#define OSPF6_JUMBO_MTU 9000 /* global pointer for OSPF top data structure */ extern struct ospf6 *ospf6; @@ -188,4 +196,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/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 72bc3a2f3a..5403e643dc 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -131,38 +131,17 @@ void ospf6_zebra_no_redistribute(int type, vrf_id_t vrf_id) static int ospf6_zebra_if_address_update_add(ZAPI_CALLBACK_ARGS) { struct connected *c; - struct ospf6_interface *oi; - int ipv6_count = 0; c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf, vrf_id); if (c == NULL) return 0; - oi = (struct ospf6_interface *)c->ifp->info; - if (oi == NULL) - oi = ospf6_interface_create(c->ifp); - assert(oi); - if (IS_OSPF6_DEBUG_ZEBRA(RECV)) zlog_debug("Zebra Interface address add: %s %5s %pFX", c->ifp->name, prefix_family_str(c->address), c->address); - ipv6_count = connected_count_by_family(c->ifp, AF_INET6); - if (oi->ifmtu == OSPF6_DEFAULT_MTU && ipv6_count > OSPF6_MAX_IF_ADDRS) { - zlog_warn( - "Zebra Interface : %s has too many interface addresses %d only support %d, increase MTU", - c->ifp->name, ipv6_count, OSPF6_MAX_IF_ADDRS); - return 0; - } else if (oi->ifmtu >= OSPF6_JUMBO_MTU - && ipv6_count > OSPF6_MAX_IF_ADDRS_JUMBO) { - zlog_warn( - "Zebra Interface : %s has too many interface addresses %d only support %d", - c->ifp->name, ipv6_count, OSPF6_MAX_IF_ADDRS_JUMBO); - return 0; - } - if (c->address->family == AF_INET6) { ospf6_interface_state_update(c->ifp); ospf6_interface_connected_route_update(c->ifp); 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 3f9ff76f3b..78fb26b00e 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 = \ |
