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:
Renato Westphal 2023-03-07 21:13:53 -03:00
parent 271588ace0
commit f07ff222f8
9 changed files with 262 additions and 102 deletions

View file

@ -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)

View file

@ -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__);

View file

@ -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,

View file

@ -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;

View file

@ -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 *);

View file

@ -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;

View file

@ -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);

View file

@ -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);
}

View file

@ -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;