forked from Mirror/frr
ospfd: add support for NSSA Type-7 address ranges
Implement NSSA address ranges as specified by RFC 3101: NSSA border routers may be configured with Type-7 address ranges. Each Type-7 address range is defined as an [address,mask] pair. Many separate Type-7 networks may fall into a single Type-7 address range, just as a subnetted network is composed of many separate subnets. NSSA border routers may aggregate Type-7 routes by advertising a single Type-5 LSA for each Type-7 address range. The Type-5 LSA resulting from a Type-7 address range match will be distributed to all Type-5 capable areas. Syntax: area A.B.C.D nssa range A.B.C.D/M [<not-advertise|cost (0-16777215)>] Example: router ospf router-id 1.1.1.1 area 1 nssa area 1 nssa range 172.16.0.0/16 area 1 nssa range 10.1.0.0/16 ! Since regular area ranges and NSSA ranges have a lot in common, this commit reuses the existing infrastructure for area ranges as much as possible to avoid code duplication. Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
parent
271588ace0
commit
f07ff222f8
|
@ -325,7 +325,6 @@ Areas
|
|||
announced to other areas. This command can be used only in ABR and ONLY
|
||||
router-LSAs (Type-1) and network-LSAs (Type-2) (i.e. LSAs with scope area) can
|
||||
be summarized. Type-5 AS-external-LSAs can't be summarized - their scope is AS.
|
||||
Summarizing Type-7 AS-external-LSAs isn't supported yet by FRR.
|
||||
|
||||
.. code-block:: frr
|
||||
|
||||
|
@ -441,6 +440,21 @@ Areas
|
|||
existence of a default route in the RIB that wasn't learned via the OSPF
|
||||
protocol.
|
||||
|
||||
.. clicmd:: area A.B.C.D nssa range A.B.C.D/M [<not-advertise|cost (0-16777215)>]
|
||||
|
||||
.. clicmd:: area (0-4294967295) nssa range A.B.C.D/M [<not-advertise|cost (0-16777215)>]
|
||||
|
||||
Summarize a group of external subnets into a single Type-7 LSA, which is
|
||||
then translated to a Type-5 LSA and avertised to the backbone.
|
||||
This command can only be used at the area boundary (NSSA ABR router).
|
||||
|
||||
By default, the metric of the summary route is calculated as the highest
|
||||
metric among the summarized routes. The `cost` option, however, can be used
|
||||
to set an explicit metric.
|
||||
|
||||
The `not-advertise` option, when present, prevents the summary route from
|
||||
being advertised, effectively filtering the summarized routes.
|
||||
|
||||
.. clicmd:: area A.B.C.D default-cost (0-16777215)
|
||||
|
||||
|
||||
|
|
172
ospfd/ospf_abr.c
172
ospfd/ospf_abr.c
|
@ -54,6 +54,7 @@ static void ospf_area_range_free(struct ospf_area_range *range)
|
|||
}
|
||||
|
||||
static void ospf_area_range_add(struct ospf_area *area,
|
||||
struct route_table *ranges,
|
||||
struct ospf_area_range *range)
|
||||
{
|
||||
struct route_node *rn;
|
||||
|
@ -64,7 +65,7 @@ static void ospf_area_range_add(struct ospf_area *area,
|
|||
p.prefix = range->addr;
|
||||
apply_mask_ipv4(&p);
|
||||
|
||||
rn = route_node_get(area->ranges, (struct prefix *)&p);
|
||||
rn = route_node_get(ranges, (struct prefix *)&p);
|
||||
if (rn->info)
|
||||
route_unlock_node(rn);
|
||||
else
|
||||
|
@ -75,11 +76,12 @@ static void ospf_area_range_delete(struct ospf_area *area,
|
|||
struct route_node *rn)
|
||||
{
|
||||
struct ospf_area_range *range = rn->info;
|
||||
bool nssa = CHECK_FLAG(range->flags, OSPF_AREA_RANGE_NSSA);
|
||||
|
||||
if (ospf_area_range_active(range) &&
|
||||
CHECK_FLAG(range->flags, OSPF_AREA_RANGE_ADVERTISE))
|
||||
ospf_delete_discard_route(area->ospf, area->ospf->new_table,
|
||||
(struct prefix_ipv4 *)&rn->p);
|
||||
(struct prefix_ipv4 *)&rn->p, nssa);
|
||||
|
||||
ospf_area_range_free(range);
|
||||
rn->info = NULL;
|
||||
|
@ -88,11 +90,12 @@ static void ospf_area_range_delete(struct ospf_area *area,
|
|||
}
|
||||
|
||||
struct ospf_area_range *ospf_area_range_lookup(struct ospf_area *area,
|
||||
struct route_table *ranges,
|
||||
struct prefix_ipv4 *p)
|
||||
{
|
||||
struct route_node *rn;
|
||||
|
||||
rn = route_node_lookup(area->ranges, (struct prefix *)p);
|
||||
rn = route_node_lookup(ranges, (struct prefix *)p);
|
||||
if (rn) {
|
||||
route_unlock_node(rn);
|
||||
return rn->info;
|
||||
|
@ -134,11 +137,12 @@ struct ospf_area_range *ospf_area_range_lookup_next(struct ospf_area *area,
|
|||
}
|
||||
|
||||
static struct ospf_area_range *ospf_area_range_match(struct ospf_area *area,
|
||||
struct route_table *ranges,
|
||||
struct prefix_ipv4 *p)
|
||||
{
|
||||
struct route_node *node;
|
||||
|
||||
node = route_node_match(area->ranges, (struct prefix *)p);
|
||||
node = route_node_match(ranges, (struct prefix *)p);
|
||||
if (node) {
|
||||
route_unlock_node(node);
|
||||
return node->info;
|
||||
|
@ -154,7 +158,7 @@ struct ospf_area_range *ospf_area_range_match_any(struct ospf *ospf,
|
|||
struct listnode *node;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area))
|
||||
if ((range = ospf_area_range_match(area, p)))
|
||||
if ((range = ospf_area_range_match(area, area->ranges, p)))
|
||||
return range;
|
||||
|
||||
return NULL;
|
||||
|
@ -171,11 +175,12 @@ static int ospf_area_actively_attached(struct ospf_area *area)
|
|||
}
|
||||
|
||||
int ospf_area_range_set(struct ospf *ospf, struct ospf_area *area,
|
||||
struct prefix_ipv4 *p, int advertise)
|
||||
struct route_table *ranges, struct prefix_ipv4 *p,
|
||||
int advertise, bool nssa)
|
||||
{
|
||||
struct ospf_area_range *range;
|
||||
|
||||
range = ospf_area_range_lookup(area, p);
|
||||
range = ospf_area_range_lookup(area, ranges, p);
|
||||
if (range != NULL) {
|
||||
if (!CHECK_FLAG(advertise, OSPF_AREA_RANGE_ADVERTISE))
|
||||
range->cost_config = OSPF_AREA_RANGE_COST_UNSPEC;
|
||||
|
@ -186,7 +191,7 @@ int ospf_area_range_set(struct ospf *ospf, struct ospf_area *area,
|
|||
ospf_schedule_abr_task(ospf);
|
||||
} else {
|
||||
range = ospf_area_range_new(p);
|
||||
ospf_area_range_add(area, range);
|
||||
ospf_area_range_add(area, ranges, range);
|
||||
ospf_schedule_abr_task(ospf);
|
||||
}
|
||||
|
||||
|
@ -197,15 +202,19 @@ int ospf_area_range_set(struct ospf *ospf, struct ospf_area *area,
|
|||
range->cost_config = OSPF_AREA_RANGE_COST_UNSPEC;
|
||||
}
|
||||
|
||||
if (nssa)
|
||||
SET_FLAG(range->flags, OSPF_AREA_RANGE_NSSA);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ospf_area_range_cost_set(struct ospf *ospf, struct ospf_area *area,
|
||||
struct prefix_ipv4 *p, uint32_t cost)
|
||||
struct route_table *ranges, struct prefix_ipv4 *p,
|
||||
uint32_t cost)
|
||||
{
|
||||
struct ospf_area_range *range;
|
||||
|
||||
range = ospf_area_range_lookup(area, p);
|
||||
range = ospf_area_range_lookup(area, ranges, p);
|
||||
if (range == NULL)
|
||||
return 0;
|
||||
|
||||
|
@ -219,11 +228,11 @@ int ospf_area_range_cost_set(struct ospf *ospf, struct ospf_area *area,
|
|||
}
|
||||
|
||||
int ospf_area_range_unset(struct ospf *ospf, struct ospf_area *area,
|
||||
struct prefix_ipv4 *p)
|
||||
struct route_table *ranges, struct prefix_ipv4 *p)
|
||||
{
|
||||
struct route_node *rn;
|
||||
|
||||
rn = route_node_lookup(area->ranges, (struct prefix *)p);
|
||||
rn = route_node_lookup(ranges, (struct prefix *)p);
|
||||
if (rn == NULL)
|
||||
return 0;
|
||||
|
||||
|
@ -240,7 +249,7 @@ int ospf_area_range_substitute_set(struct ospf *ospf, struct ospf_area *area,
|
|||
{
|
||||
struct ospf_area_range *range;
|
||||
|
||||
range = ospf_area_range_lookup(area, p);
|
||||
range = ospf_area_range_lookup(area, area->ranges, p);
|
||||
|
||||
if (range != NULL) {
|
||||
if (!CHECK_FLAG(range->flags, OSPF_AREA_RANGE_ADVERTISE)
|
||||
|
@ -248,7 +257,7 @@ int ospf_area_range_substitute_set(struct ospf *ospf, struct ospf_area *area,
|
|||
ospf_schedule_abr_task(ospf);
|
||||
} else {
|
||||
range = ospf_area_range_new(p);
|
||||
ospf_area_range_add(area, range);
|
||||
ospf_area_range_add(area, area->ranges, range);
|
||||
ospf_schedule_abr_task(ospf);
|
||||
}
|
||||
|
||||
|
@ -265,7 +274,7 @@ int ospf_area_range_substitute_unset(struct ospf *ospf, struct ospf_area *area,
|
|||
{
|
||||
struct ospf_area_range *range;
|
||||
|
||||
range = ospf_area_range_lookup(area, p);
|
||||
range = ospf_area_range_lookup(area, area->ranges, p);
|
||||
if (range == NULL)
|
||||
return 0;
|
||||
|
||||
|
@ -517,8 +526,7 @@ void ospf_check_abr_status(struct ospf *ospf)
|
|||
}
|
||||
|
||||
static void ospf_abr_update_aggregate(struct ospf_area_range *range,
|
||||
struct ospf_route * or,
|
||||
struct ospf_area *area)
|
||||
uint32_t cost, struct ospf_area *area)
|
||||
{
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s: Start", __func__);
|
||||
|
@ -538,18 +546,16 @@ static void ospf_abr_update_aggregate(struct ospf_area_range *range,
|
|||
} else {
|
||||
if (!ospf_area_range_active(range)) {
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s: use or->cost %d", __func__,
|
||||
or->cost);
|
||||
zlog_debug("%s: use cost %d", __func__, cost);
|
||||
|
||||
range->cost = or->cost; /* 1st time get 1st cost */
|
||||
range->cost = cost; /* 1st time get 1st cost */
|
||||
}
|
||||
|
||||
if (or->cost > range->cost) {
|
||||
if (cost > range->cost) {
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s: update to %d", __func__,
|
||||
or->cost);
|
||||
zlog_debug("%s: update to %d", __func__, cost);
|
||||
|
||||
range->cost = or->cost;
|
||||
range->cost = cost;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -584,6 +590,7 @@ static int ospf_abr_translate_nssa(struct ospf_area *area, struct ospf_lsa *lsa)
|
|||
struct ospf_lsa *old = NULL, *new = NULL;
|
||||
struct as_external_lsa *ext7;
|
||||
struct prefix_ipv4 p;
|
||||
struct ospf_area_range *range;
|
||||
|
||||
if (!CHECK_FLAG(lsa->data->options, OSPF_OPTION_NP)) {
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
|
@ -625,6 +632,18 @@ static int ospf_abr_translate_nssa(struct ospf_area *area, struct ospf_lsa *lsa)
|
|||
return 1;
|
||||
}
|
||||
|
||||
range = ospf_area_range_match(area, area->nssa_ranges, &p);
|
||||
if (range) {
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
zlog_debug("Suppressed by range %pI4/%u of area %pI4",
|
||||
&range->addr, range->masklen,
|
||||
&area->area_id);
|
||||
|
||||
ospf_abr_update_aggregate(range, GET_METRIC(ext7->e[0].metric),
|
||||
area);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (old && CHECK_FLAG(old->flags, OSPF_LSA_APPROVED)) {
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
zlog_debug(
|
||||
|
@ -654,17 +673,27 @@ static int ospf_abr_translate_nssa(struct ospf_area *area, struct ospf_lsa *lsa)
|
|||
}
|
||||
}
|
||||
|
||||
/* Area where Aggregate testing will be inserted, just like summary
|
||||
advertisements */
|
||||
/* ospf_abr_check_nssa_range (p_arg, lsa-> cost, lsa -> area); */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ospf_abr_translate_nssa_range(struct prefix_ipv4 *p, uint32_t cost)
|
||||
static void ospf_abr_translate_nssa_range(struct ospf *ospf,
|
||||
struct prefix_ipv4 *p, uint32_t cost)
|
||||
{
|
||||
/* The Type-7 is created from the aggregated prefix and forwarded
|
||||
for lsa installation and flooding... to be added... */
|
||||
struct external_info ei = {};
|
||||
struct ospf_lsa *lsa;
|
||||
|
||||
prefix_copy(&ei.p, p);
|
||||
ei.type = ZEBRA_ROUTE_OSPF;
|
||||
ei.route_map_set.metric = cost;
|
||||
ei.route_map_set.metric_type = -1;
|
||||
|
||||
lsa = ospf_external_info_find_lsa(ospf, p);
|
||||
if (lsa)
|
||||
lsa = ospf_external_lsa_refresh(ospf, lsa, &ei,
|
||||
LSA_REFRESH_FORCE, true);
|
||||
else
|
||||
lsa = ospf_external_lsa_originate(ospf, &ei);
|
||||
SET_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT);
|
||||
}
|
||||
|
||||
void ospf_abr_announce_network_to_area(struct prefix_ipv4 *p, uint32_t cost,
|
||||
|
@ -871,9 +900,11 @@ static void ospf_abr_announce_network(struct ospf *ospf, struct prefix_ipv4 *p,
|
|||
zlog_debug(
|
||||
"%s: this is intra-area route to %pFX",
|
||||
__func__, p);
|
||||
if ((range = ospf_area_range_match(or_area, p))
|
||||
&& !ospf_area_is_transit(area))
|
||||
ospf_abr_update_aggregate(range, or, area);
|
||||
if ((range = ospf_area_range_match(
|
||||
or_area, or_area->ranges, p)) &&
|
||||
!ospf_area_is_transit(area))
|
||||
ospf_abr_update_aggregate(range, or->cost,
|
||||
area);
|
||||
else
|
||||
ospf_abr_announce_network_to_area(p, or->cost,
|
||||
area);
|
||||
|
@ -1324,7 +1355,7 @@ static void ospf_abr_unapprove_summaries(struct ospf *ospf)
|
|||
zlog_debug("%s: Stop", __func__);
|
||||
}
|
||||
|
||||
static void ospf_abr_prepare_aggregates(struct ospf *ospf)
|
||||
static void ospf_abr_prepare_aggregates(struct ospf *ospf, bool nssa)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct route_node *rn;
|
||||
|
@ -1335,7 +1366,14 @@ static void ospf_abr_prepare_aggregates(struct ospf *ospf)
|
|||
zlog_debug("%s: Start", __func__);
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
|
||||
for (rn = route_top(area->ranges); rn; rn = route_next(rn))
|
||||
struct route_table *ranges;
|
||||
|
||||
if (nssa)
|
||||
ranges = area->nssa_ranges;
|
||||
else
|
||||
ranges = area->ranges;
|
||||
|
||||
for (rn = route_top(ranges); rn; rn = route_next(rn))
|
||||
if ((range = rn->info) != NULL) {
|
||||
range->cost = 0;
|
||||
range->specifics = 0;
|
||||
|
@ -1431,13 +1469,11 @@ static void ospf_abr_announce_aggregates(struct ospf *ospf)
|
|||
zlog_debug("%s: Stop", __func__);
|
||||
}
|
||||
|
||||
static void
|
||||
ospf_abr_send_nssa_aggregates(struct ospf *ospf) /* temporarily turned off */
|
||||
static void ospf_abr_send_nssa_aggregates(struct ospf *ospf)
|
||||
{
|
||||
struct listnode *node; /*, n; */
|
||||
struct ospf_area *area; /*, *ar; */
|
||||
struct listnode *node;
|
||||
struct ospf_area *area;
|
||||
struct route_node *rn;
|
||||
struct ospf_area_range *range;
|
||||
struct prefix_ipv4 p;
|
||||
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
|
@ -1451,20 +1487,13 @@ ospf_abr_send_nssa_aggregates(struct ospf *ospf) /* temporarily turned off */
|
|||
zlog_debug("%s: looking at area %pI4", __func__,
|
||||
&area->area_id);
|
||||
|
||||
for (rn = route_top(area->ranges); rn; rn = route_next(rn)) {
|
||||
if (rn->info == NULL)
|
||||
continue;
|
||||
for (rn = route_top(area->nssa_ranges); rn;
|
||||
rn = route_next(rn)) {
|
||||
struct ospf_area_range *range;
|
||||
|
||||
range = rn->info;
|
||||
|
||||
if (!CHECK_FLAG(range->flags,
|
||||
OSPF_AREA_RANGE_ADVERTISE)) {
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
zlog_debug(
|
||||
"%s: discarding suppress-ranges",
|
||||
__func__);
|
||||
if (!range)
|
||||
continue;
|
||||
}
|
||||
|
||||
p.family = AF_INET;
|
||||
p.prefix = range->addr;
|
||||
|
@ -1474,14 +1503,9 @@ ospf_abr_send_nssa_aggregates(struct ospf *ospf) /* temporarily turned off */
|
|||
zlog_debug("%s: this is range: %pFX", __func__,
|
||||
&p);
|
||||
|
||||
if (CHECK_FLAG(range->flags,
|
||||
OSPF_AREA_RANGE_SUBSTITUTE)) {
|
||||
p.family = AF_INET;
|
||||
p.prefix = range->subst_addr;
|
||||
p.prefixlen = range->subst_masklen;
|
||||
}
|
||||
|
||||
if (ospf_area_range_active(range)) {
|
||||
if (ospf_area_range_active(range)
|
||||
&& CHECK_FLAG(range->flags,
|
||||
OSPF_AREA_RANGE_ADVERTISE)) {
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
zlog_debug("%s: active range",
|
||||
__func__);
|
||||
|
@ -1491,7 +1515,8 @@ ospf_abr_send_nssa_aggregates(struct ospf *ospf) /* temporarily turned off */
|
|||
* translate, Install (as Type-5), Approve, and
|
||||
* Flood
|
||||
*/
|
||||
ospf_abr_translate_nssa_range(&p, range->cost);
|
||||
ospf_abr_translate_nssa_range(ospf, &p,
|
||||
range->cost);
|
||||
}
|
||||
} /* all area ranges*/
|
||||
} /* all areas */
|
||||
|
@ -1929,14 +1954,21 @@ static void ospf_abr_remove_unapproved_summaries(struct ospf *ospf)
|
|||
zlog_debug("%s: Stop", __func__);
|
||||
}
|
||||
|
||||
static void ospf_abr_manage_discard_routes(struct ospf *ospf)
|
||||
static void ospf_abr_manage_discard_routes(struct ospf *ospf, bool nssa)
|
||||
{
|
||||
struct listnode *node, *nnode;
|
||||
struct route_node *rn;
|
||||
struct ospf_area *area;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
|
||||
for (rn = route_top(area->ranges); rn; rn = route_next(rn)) {
|
||||
struct route_table *ranges;
|
||||
|
||||
if (nssa)
|
||||
ranges = area->nssa_ranges;
|
||||
else
|
||||
ranges = area->ranges;
|
||||
|
||||
for (rn = route_top(ranges); rn; rn = route_next(rn)) {
|
||||
struct ospf_area_range *range;
|
||||
|
||||
range = rn->info;
|
||||
|
@ -1948,11 +1980,11 @@ static void ospf_abr_manage_discard_routes(struct ospf *ospf)
|
|||
OSPF_AREA_RANGE_ADVERTISE))
|
||||
ospf_add_discard_route(
|
||||
ospf, ospf->new_table, area,
|
||||
(struct prefix_ipv4 *)&rn->p);
|
||||
(struct prefix_ipv4 *)&rn->p, nssa);
|
||||
else
|
||||
ospf_delete_discard_route(
|
||||
ospf, ospf->new_table,
|
||||
(struct prefix_ipv4 *)&rn->p);
|
||||
(struct prefix_ipv4 *)&rn->p, nssa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1982,7 +2014,7 @@ static void ospf_abr_manage_discard_routes(struct ospf *ospf)
|
|||
For External Calculations, any NSSA areas use the Type-7 AREA-LSDB,
|
||||
any ABR-non-NSSA areas use the Type-5 GLOBAL-LSDB. */
|
||||
|
||||
static void ospf_abr_nssa_task(struct ospf *ospf) /* called only if any_nssa */
|
||||
void ospf_abr_nssa_task(struct ospf *ospf) /* called only if any_nssa */
|
||||
{
|
||||
if (ospf->gr_info.restart_in_progress)
|
||||
return;
|
||||
|
@ -2009,7 +2041,7 @@ static void ospf_abr_nssa_task(struct ospf *ospf) /* called only if any_nssa */
|
|||
/* RESET all Ranges in every Area, same as summaries */
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
zlog_debug("%s: NSSA initialize aggregates", __func__);
|
||||
ospf_abr_prepare_aggregates(ospf); /*TURNED OFF just for now */
|
||||
ospf_abr_prepare_aggregates(ospf, true);
|
||||
|
||||
/* For all NSSAs, Type-7s, translate to 5's, INSTALL/FLOOD, or
|
||||
* Aggregate as Type-7
|
||||
|
@ -2040,7 +2072,7 @@ static void ospf_abr_nssa_task(struct ospf *ospf) /* called only if any_nssa */
|
|||
zlog_debug("%s: remove unapproved translates", __func__);
|
||||
ospf_abr_remove_unapproved_translates(ospf);
|
||||
|
||||
ospf_abr_manage_discard_routes(ospf); /* same as normal...discard */
|
||||
ospf_abr_manage_discard_routes(ospf, true);
|
||||
|
||||
if (IS_DEBUG_OSPF_NSSA)
|
||||
zlog_debug("%s: Stop", __func__);
|
||||
|
@ -2069,7 +2101,7 @@ void ospf_abr_task(struct ospf *ospf)
|
|||
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s: prepare aggregates", __func__);
|
||||
ospf_abr_prepare_aggregates(ospf);
|
||||
ospf_abr_prepare_aggregates(ospf, false);
|
||||
|
||||
if (IS_OSPF_ABR(ospf)) {
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
|
@ -2112,7 +2144,7 @@ void ospf_abr_task(struct ospf *ospf)
|
|||
zlog_debug("%s: remove unapproved summaries", __func__);
|
||||
ospf_abr_remove_unapproved_summaries(ospf);
|
||||
|
||||
ospf_abr_manage_discard_routes(ospf);
|
||||
ospf_abr_manage_discard_routes(ospf, false);
|
||||
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s: Stop", __func__);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#define OSPF_AREA_RANGE_ADVERTISE (1 << 0)
|
||||
#define OSPF_AREA_RANGE_SUBSTITUTE (1 << 1)
|
||||
#define OSPF_AREA_RANGE_NSSA (1 << 2)
|
||||
|
||||
/* Area range. */
|
||||
struct ospf_area_range {
|
||||
|
@ -44,19 +45,19 @@ struct ospf_area_range {
|
|||
|
||||
/* Prototypes. */
|
||||
extern struct ospf_area_range *ospf_area_range_lookup(struct ospf_area *,
|
||||
struct route_table *,
|
||||
struct prefix_ipv4 *);
|
||||
|
||||
extern struct ospf_area_range *ospf_some_area_range_match(struct prefix_ipv4 *);
|
||||
|
||||
extern struct ospf_area_range *
|
||||
ospf_area_range_lookup_next(struct ospf_area *, struct in_addr *, int);
|
||||
|
||||
extern int ospf_area_range_set(struct ospf *, struct ospf_area *,
|
||||
struct prefix_ipv4 *, int);
|
||||
struct route_table *, struct prefix_ipv4 *, int,
|
||||
bool);
|
||||
extern int ospf_area_range_cost_set(struct ospf *, struct ospf_area *,
|
||||
struct prefix_ipv4 *, uint32_t);
|
||||
struct route_table *, struct prefix_ipv4 *,
|
||||
uint32_t);
|
||||
extern int ospf_area_range_unset(struct ospf *, struct ospf_area *,
|
||||
struct prefix_ipv4 *);
|
||||
struct route_table *, struct prefix_ipv4 *);
|
||||
extern int ospf_area_range_substitute_set(struct ospf *, struct ospf_area *,
|
||||
struct prefix_ipv4 *,
|
||||
struct prefix_ipv4 *);
|
||||
|
@ -69,6 +70,7 @@ extern int ospf_act_bb_connection(struct ospf *);
|
|||
|
||||
extern void ospf_check_abr_status(struct ospf *);
|
||||
extern void ospf_abr_task(struct ospf *);
|
||||
extern void ospf_abr_nssa_task(struct ospf *ospf);
|
||||
extern void ospf_schedule_abr_task(struct ospf *);
|
||||
|
||||
extern void ospf_abr_announce_network_to_area(struct prefix_ipv4 *, uint32_t,
|
||||
|
|
|
@ -1008,7 +1008,8 @@ void ospf_prune_unreachable_routers(struct route_table *rtrs)
|
|||
}
|
||||
|
||||
int ospf_add_discard_route(struct ospf *ospf, struct route_table *rt,
|
||||
struct ospf_area *area, struct prefix_ipv4 *p)
|
||||
struct ospf_area *area, struct prefix_ipv4 *p,
|
||||
bool nssa)
|
||||
{
|
||||
struct route_node *rn;
|
||||
struct ospf_route * or, *new_or;
|
||||
|
@ -1027,7 +1028,7 @@ int ospf_add_discard_route(struct ospf *ospf, struct route_table *rt,
|
|||
|
||||
or = rn->info;
|
||||
|
||||
if (or->path_type == OSPF_PATH_INTRA_AREA) {
|
||||
if (!nssa && or->path_type == OSPF_PATH_INTRA_AREA) {
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s: an intra-area route exists",
|
||||
__func__);
|
||||
|
@ -1054,7 +1055,10 @@ int ospf_add_discard_route(struct ospf *ospf, struct route_table *rt,
|
|||
new_or->cost = 0;
|
||||
new_or->u.std.area_id = area->area_id;
|
||||
new_or->u.std.external_routing = area->external_routing;
|
||||
new_or->path_type = OSPF_PATH_INTER_AREA;
|
||||
if (nssa)
|
||||
new_or->path_type = OSPF_PATH_TYPE2_EXTERNAL;
|
||||
else
|
||||
new_or->path_type = OSPF_PATH_INTER_AREA;
|
||||
rn->info = new_or;
|
||||
|
||||
ospf_zebra_add_discard(ospf, p);
|
||||
|
@ -1063,7 +1067,7 @@ int ospf_add_discard_route(struct ospf *ospf, struct route_table *rt,
|
|||
}
|
||||
|
||||
void ospf_delete_discard_route(struct ospf *ospf, struct route_table *rt,
|
||||
struct prefix_ipv4 *p)
|
||||
struct prefix_ipv4 *p, bool nssa)
|
||||
{
|
||||
struct route_node *rn;
|
||||
struct ospf_route * or ;
|
||||
|
@ -1081,7 +1085,7 @@ void ospf_delete_discard_route(struct ospf *ospf, struct route_table *rt,
|
|||
|
||||
or = rn->info;
|
||||
|
||||
if (or->path_type == OSPF_PATH_INTRA_AREA) {
|
||||
if (!nssa && or->path_type == OSPF_PATH_INTRA_AREA) {
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s: an intra-area route exists", __func__);
|
||||
return;
|
||||
|
|
|
@ -152,9 +152,10 @@ extern void ospf_route_subst_nexthops(struct ospf_route *, struct list *);
|
|||
extern void ospf_prune_unreachable_networks(struct route_table *);
|
||||
extern void ospf_prune_unreachable_routers(struct route_table *);
|
||||
extern int ospf_add_discard_route(struct ospf *, struct route_table *,
|
||||
struct ospf_area *, struct prefix_ipv4 *);
|
||||
struct ospf_area *, struct prefix_ipv4 *,
|
||||
bool);
|
||||
extern void ospf_delete_discard_route(struct ospf *, struct route_table *,
|
||||
struct prefix_ipv4 *);
|
||||
struct prefix_ipv4 *, bool);
|
||||
extern int ospf_route_match_same(struct route_table *, struct prefix_ipv4 *,
|
||||
struct ospf_route *);
|
||||
|
||||
|
|
|
@ -1112,7 +1112,7 @@ static struct ospf_area_range *ospfAreaRangeLookup(struct variable *v,
|
|||
oid2in_addr(offset, IN_ADDR_SIZE, range_net);
|
||||
p.prefix = *range_net;
|
||||
|
||||
return ospf_area_range_lookup(area, &p);
|
||||
return ospf_area_range_lookup(area, area->ranges, &p);
|
||||
} else {
|
||||
/* Set OID offset for Area ID. */
|
||||
offset = name + v->namelen;
|
||||
|
|
123
ospfd/ospf_vty.c
123
ospfd/ospf_vty.c
|
@ -626,10 +626,11 @@ DEFUN (ospf_area_range,
|
|||
area = ospf_area_get(ospf, area_id);
|
||||
ospf_area_display_format_set(ospf, area, format);
|
||||
|
||||
ospf_area_range_set(ospf, area, &p, OSPF_AREA_RANGE_ADVERTISE);
|
||||
ospf_area_range_set(ospf, area, area->ranges, &p,
|
||||
OSPF_AREA_RANGE_ADVERTISE, false);
|
||||
if (argc > 5) {
|
||||
cost = strtoul(argv[idx_cost]->arg, NULL, 10);
|
||||
ospf_area_range_cost_set(ospf, area, &p, cost);
|
||||
ospf_area_range_cost_set(ospf, area, area->ranges, &p, cost);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
|
@ -664,10 +665,11 @@ DEFUN (ospf_area_range_cost,
|
|||
area = ospf_area_get(ospf, area_id);
|
||||
ospf_area_display_format_set(ospf, area, format);
|
||||
|
||||
ospf_area_range_set(ospf, area, &p, OSPF_AREA_RANGE_ADVERTISE);
|
||||
ospf_area_range_set(ospf, area, area->ranges, &p,
|
||||
OSPF_AREA_RANGE_ADVERTISE, false);
|
||||
if (argv_find(argv, argc, "cost", &idx)) {
|
||||
cost = strtoul(argv[idx + 1]->arg, NULL, 10);
|
||||
ospf_area_range_cost_set(ospf, area, &p, cost);
|
||||
ospf_area_range_cost_set(ospf, area, area->ranges, &p, cost);
|
||||
}
|
||||
|
||||
idx = 4;
|
||||
|
@ -703,7 +705,7 @@ DEFUN (ospf_area_range_not_advertise,
|
|||
area = ospf_area_get(ospf, area_id);
|
||||
ospf_area_display_format_set(ospf, area, format);
|
||||
|
||||
ospf_area_range_set(ospf, area, &p, 0);
|
||||
ospf_area_range_set(ospf, area, area->ranges, &p, 0, false);
|
||||
ospf_area_range_substitute_unset(ospf, area, &p);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
|
@ -739,7 +741,7 @@ DEFUN (no_ospf_area_range,
|
|||
area = ospf_area_get(ospf, area_id);
|
||||
ospf_area_display_format_set(ospf, area, format);
|
||||
|
||||
ospf_area_range_unset(ospf, area, &p);
|
||||
ospf_area_range_unset(ospf, area, area->ranges, &p);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
@ -1573,6 +1575,82 @@ DEFPY (no_ospf_area_nssa,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (ospf_area_nssa_range,
|
||||
ospf_area_nssa_range_cmd,
|
||||
"area <A.B.C.D|(0-4294967295)>$area_str nssa range A.B.C.D/M$prefix [<not-advertise$not_adv|cost (0-16777215)$cost>]",
|
||||
"OSPF area parameters\n"
|
||||
"OSPF area ID in IP address format\n"
|
||||
"OSPF area ID as a decimal value\n"
|
||||
"Configure OSPF area as nssa\n"
|
||||
"Configured address range\n"
|
||||
"Specify IPv4 prefix\n"
|
||||
"Do not advertise\n"
|
||||
"User specified metric for this range\n"
|
||||
"Advertised metric for this range\n")
|
||||
{
|
||||
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
|
||||
struct ospf_area *area;
|
||||
struct in_addr area_id;
|
||||
int format;
|
||||
int advertise = 0;
|
||||
|
||||
VTY_GET_OSPF_AREA_ID(area_id, format, area_str);
|
||||
area = ospf_area_get(ospf, area_id);
|
||||
ospf_area_display_format_set(ospf, area, format);
|
||||
|
||||
if (area->external_routing != OSPF_AREA_NSSA) {
|
||||
vty_out(vty, "%% First configure %s as an NSSA area\n",
|
||||
area_str);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (!not_adv)
|
||||
advertise = OSPF_AREA_RANGE_ADVERTISE;
|
||||
|
||||
ospf_area_range_set(ospf, area, area->nssa_ranges,
|
||||
(struct prefix_ipv4 *)prefix, advertise, true);
|
||||
if (cost_str)
|
||||
ospf_area_range_cost_set(ospf, area, area->nssa_ranges,
|
||||
(struct prefix_ipv4 *)prefix, cost);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (no_ospf_area_nssa_range,
|
||||
no_ospf_area_nssa_range_cmd,
|
||||
"no area <A.B.C.D|(0-4294967295)>$area_str nssa range A.B.C.D/M$prefix [<not-advertise|cost (0-16777215)>]",
|
||||
NO_STR
|
||||
"OSPF area parameters\n"
|
||||
"OSPF area ID in IP address format\n"
|
||||
"OSPF area ID as a decimal value\n"
|
||||
"Configure OSPF area as nssa\n"
|
||||
"Configured address range\n"
|
||||
"Specify IPv4 prefix\n"
|
||||
"Do not advertise\n"
|
||||
"User specified metric for this range\n"
|
||||
"Advertised metric for this range\n")
|
||||
{
|
||||
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
|
||||
struct ospf_area *area;
|
||||
struct in_addr area_id;
|
||||
int format;
|
||||
|
||||
VTY_GET_OSPF_AREA_ID(area_id, format, area_str);
|
||||
area = ospf_area_get(ospf, area_id);
|
||||
ospf_area_display_format_set(ospf, area, format);
|
||||
|
||||
if (area->external_routing != OSPF_AREA_NSSA) {
|
||||
vty_out(vty, "%% First configure %s as an NSSA area\n",
|
||||
area_str);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
ospf_area_range_unset(ospf, area, area->nssa_ranges,
|
||||
(struct prefix_ipv4 *)prefix);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (ospf_area_default_cost,
|
||||
ospf_area_default_cost_cmd,
|
||||
"area <A.B.C.D|(0-4294967295)> default-cost (0-16777215)",
|
||||
|
@ -11927,14 +12005,13 @@ static int config_write_ospf_area(struct vty *vty, struct ospf *ospf)
|
|||
vty_out(vty,
|
||||
" default-information-originate");
|
||||
if (area->nssa_default_originate
|
||||
.metric_value
|
||||
!= -1)
|
||||
.metric_value != -1)
|
||||
vty_out(vty, " metric %d",
|
||||
area->nssa_default_originate
|
||||
.metric_value);
|
||||
if (area->nssa_default_originate
|
||||
.metric_type
|
||||
!= DEFAULT_METRIC_TYPE)
|
||||
.metric_type !=
|
||||
DEFAULT_METRIC_TYPE)
|
||||
vty_out(vty, " metric-type 1");
|
||||
}
|
||||
|
||||
|
@ -11943,6 +12020,30 @@ static int config_write_ospf_area(struct vty *vty, struct ospf *ospf)
|
|||
if (area->suppress_fa)
|
||||
vty_out(vty, " suppress-fa");
|
||||
vty_out(vty, "\n");
|
||||
|
||||
for (rn1 = route_top(area->nssa_ranges); rn1;
|
||||
rn1 = route_next(rn1)) {
|
||||
struct ospf_area_range *range;
|
||||
|
||||
range = rn1->info;
|
||||
if (!range)
|
||||
continue;
|
||||
|
||||
vty_out(vty, " area %s nssa range %pFX",
|
||||
buf, &rn1->p);
|
||||
|
||||
if (range->cost_config !=
|
||||
OSPF_AREA_RANGE_COST_UNSPEC)
|
||||
vty_out(vty, " cost %u",
|
||||
range->cost_config);
|
||||
|
||||
if (!CHECK_FLAG(
|
||||
range->flags,
|
||||
OSPF_AREA_RANGE_ADVERTISE))
|
||||
vty_out(vty, " not-advertise");
|
||||
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (area->default_cost != 1)
|
||||
|
@ -12969,6 +13070,8 @@ void ospf_vty_init(void)
|
|||
/* "area nssa" commands. */
|
||||
install_element(OSPF_NODE, &ospf_area_nssa_cmd);
|
||||
install_element(OSPF_NODE, &no_ospf_area_nssa_cmd);
|
||||
install_element(OSPF_NODE, &ospf_area_nssa_range_cmd);
|
||||
install_element(OSPF_NODE, &no_ospf_area_nssa_range_cmd);
|
||||
|
||||
install_element(OSPF_NODE, &ospf_area_default_cost_cmd);
|
||||
install_element(OSPF_NODE, &no_ospf_area_default_cost_cmd);
|
||||
|
|
|
@ -963,6 +963,7 @@ struct ospf_area *ospf_area_new(struct ospf *ospf, struct in_addr area_id)
|
|||
|
||||
new->oiflist = list_new();
|
||||
new->ranges = route_table_init();
|
||||
new->nssa_ranges = route_table_init();
|
||||
|
||||
if (area_id.s_addr == OSPF_AREA_BACKBONE)
|
||||
ospf->backbone = new;
|
||||
|
@ -1006,6 +1007,7 @@ static void ospf_area_free(struct ospf_area *area)
|
|||
ospf_lsa_unlock(&area->router_lsa_self);
|
||||
|
||||
route_table_finish(area->ranges);
|
||||
route_table_finish(area->nssa_ranges);
|
||||
list_delete(&area->oiflist);
|
||||
|
||||
if (EXPORT_NAME(area))
|
||||
|
@ -1029,13 +1031,14 @@ void ospf_area_check_free(struct ospf *ospf, struct in_addr area_id)
|
|||
struct ospf_area *area;
|
||||
|
||||
area = ospf_area_lookup_by_area_id(ospf, area_id);
|
||||
if (area && listcount(area->oiflist) == 0 && area->ranges->top == NULL
|
||||
&& !ospf_vl_count(ospf, area)
|
||||
&& area->shortcut_configured == OSPF_SHORTCUT_DEFAULT
|
||||
&& area->external_routing == OSPF_AREA_DEFAULT
|
||||
&& area->no_summary == 0 && area->default_cost == 1
|
||||
&& EXPORT_NAME(area) == NULL && IMPORT_NAME(area) == NULL
|
||||
&& area->auth_type == OSPF_AUTH_NULL) {
|
||||
if (area && listcount(area->oiflist) == 0 &&
|
||||
area->ranges->top == NULL && area->nssa_ranges->top == NULL &&
|
||||
!ospf_vl_count(ospf, area) &&
|
||||
area->shortcut_configured == OSPF_SHORTCUT_DEFAULT &&
|
||||
area->external_routing == OSPF_AREA_DEFAULT &&
|
||||
area->no_summary == 0 && area->default_cost == 1 &&
|
||||
EXPORT_NAME(area) == NULL && IMPORT_NAME(area) == NULL &&
|
||||
area->auth_type == OSPF_AUTH_NULL) {
|
||||
listnode_delete(ospf->areas, area);
|
||||
ospf_area_free(area);
|
||||
}
|
||||
|
|
|
@ -529,6 +529,7 @@ struct ospf_area {
|
|||
#define OSPF_TRANSIT_FALSE 0
|
||||
#define OSPF_TRANSIT_TRUE 1
|
||||
struct route_table *ranges; /* Configured Area Ranges. */
|
||||
struct route_table *nssa_ranges; /* Configured NSSA Area Ranges. */
|
||||
|
||||
/* RFC3137 stub router state flags for area */
|
||||
uint8_t stub_router_state;
|
||||
|
|
Loading…
Reference in a new issue