ospf6d: add support for NSSA totally stub areas

Add a knob to turn a NSSA area into a totally stub area. In this
configuration a Type-3 default summary route is generated by default.

Syntax: `area A.B.C.D nssa no-summary`.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
Renato Westphal 2021-08-24 17:35:21 -03:00
parent b44f7c3f6d
commit 8a60820f70
5 changed files with 68 additions and 24 deletions

View file

@ -176,9 +176,9 @@ OSPF6 area
The `not-advertise` option, when present, prevents the summary route from The `not-advertise` option, when present, prevents the summary route from
being advertised, effectively filtering the summarized routes. being advertised, effectively filtering the summarized routes.
.. clicmd:: area A.B.C.D nssa .. clicmd:: area A.B.C.D nssa [no-summary]
.. clicmd:: area (0-4294967295) nssa .. clicmd:: area (0-4294967295) nssa [no-summary]
Configure the area to be a NSSA (Not-So-Stubby Area). Configure the area to be a NSSA (Not-So-Stubby Area).
@ -194,6 +194,10 @@ OSPF6 area
4. Support for NSSA Translator functionality when there are multiple NSSA 4. Support for NSSA Translator functionality when there are multiple NSSA
ABR in an area. ABR in an area.
An NSSA ABR can be configured with the `no-summary` option to prevent the
advertisement of summaries into the area. In that case, a single Type-3 LSA
containing a default route is originated into the NSSA.
.. _ospf6-interface: .. _ospf6-interface:
OSPF6 interface OSPF6 interface

View file

@ -748,7 +748,15 @@ void ospf6_abr_defaults_to_stub(struct ospf6 *o)
def->path.cost = metric_value(o, type, 0); def->path.cost = metric_value(o, type, 0);
for (ALL_LIST_ELEMENTS(o->area_list, node, nnode, oa)) { for (ALL_LIST_ELEMENTS(o->area_list, node, nnode, oa)) {
if (!IS_AREA_STUB(oa)) { if (IS_AREA_STUB(oa) || (IS_AREA_NSSA(oa) && oa->no_summary)) {
/* announce defaults to stubby areas */
if (IS_OSPF6_DEBUG_ABR)
zlog_debug(
"Announcing default route into stubby area %s",
oa->name);
UNSET_FLAG(def->flag, OSPF6_ROUTE_REMOVE);
ospf6_abr_originate_summary_to_area(def, oa);
} else {
/* withdraw defaults when an area switches from stub to /* withdraw defaults when an area switches from stub to
* non-stub */ * non-stub */
route = ospf6_route_lookup(&def->prefix, route = ospf6_route_lookup(&def->prefix,
@ -762,14 +770,6 @@ void ospf6_abr_defaults_to_stub(struct ospf6 *o)
SET_FLAG(def->flag, OSPF6_ROUTE_REMOVE); SET_FLAG(def->flag, OSPF6_ROUTE_REMOVE);
ospf6_abr_originate_summary_to_area(def, oa); ospf6_abr_originate_summary_to_area(def, oa);
} }
} else {
/* announce defaults to stubby areas */
if (IS_OSPF6_DEBUG_ABR)
zlog_debug(
"Announcing default route into stubby area %s",
oa->name);
UNSET_FLAG(def->flag, OSPF6_ROUTE_REMOVE);
ospf6_abr_originate_summary_to_area(def, oa);
} }
} }
ospf6_route_delete(def); ospf6_route_delete(def);

View file

@ -46,6 +46,9 @@
#include "ospf6d.h" #include "ospf6d.h"
#include "lib/json.h" #include "lib/json.h"
#include "ospf6_nssa.h" #include "ospf6_nssa.h"
#ifndef VTYSH_EXTRACT_PL
#include "ospf6d/ospf6_area_clippy.c"
#endif
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA, "OSPF6 area"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA, "OSPF6 area");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name");
@ -643,8 +646,12 @@ void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6)
else else
vty_out(vty, " area %s stub\n", oa->name); vty_out(vty, " area %s stub\n", oa->name);
} }
if (IS_AREA_NSSA(oa)) if (IS_AREA_NSSA(oa)) {
vty_out(vty, " area %s nssa\n", oa->name); vty_out(vty, " area %s nssa", oa->name);
if (oa->no_summary)
vty_out(vty, " no-summary");
vty_out(vty, "\n");
}
if (PREFIX_NAME_IN(oa)) if (PREFIX_NAME_IN(oa))
vty_out(vty, " area %s filter-list prefix %s in\n", vty_out(vty, " area %s filter-list prefix %s in\n",
oa->name, PREFIX_NAME_IN(oa)); oa->name, PREFIX_NAME_IN(oa));
@ -1250,18 +1257,18 @@ DEFUN (no_ospf6_area_stub_no_summary,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(ospf6_area_nssa, ospf6_area_nssa_cmd, DEFPY(ospf6_area_nssa, ospf6_area_nssa_cmd,
"area <A.B.C.D|(0-4294967295)> nssa", "area <A.B.C.D|(0-4294967295)>$area_str nssa [no-summary$no_summary]",
"OSPF6 area parameters\n" "OSPF6 area parameters\n"
"OSPF6 area ID in IP address format\n" "OSPF6 area ID in IP address format\n"
"OSPF6 area ID as a decimal value\n" "OSPF6 area ID as a decimal value\n"
"Configure OSPF6 area as nssa\n") "Configure OSPF6 area as nssa\n"
"Do not inject inter-area routes into area\n")
{ {
int idx_ipv4_number = 1;
struct ospf6_area *area; struct ospf6_area *area;
VTY_DECLVAR_CONTEXT(ospf6, ospf6); VTY_DECLVAR_CONTEXT(ospf6, ospf6);
OSPF6_CMD_AREA_GET(argv[idx_ipv4_number]->arg, area, ospf6); OSPF6_CMD_AREA_GET(area_str, area, ospf6);
if (!ospf6_area_nssa_set(ospf6, area)) { if (!ospf6_area_nssa_set(ospf6, area)) {
vty_out(vty, vty_out(vty,
@ -1269,26 +1276,32 @@ DEFUN(ospf6_area_nssa, ospf6_area_nssa_cmd,
return CMD_WARNING_CONFIG_FAILED; return CMD_WARNING_CONFIG_FAILED;
} }
ospf6_area_no_summary_unset(ospf6, area); if (no_summary)
ospf6_area_no_summary_set(ospf6, area);
else
ospf6_area_no_summary_unset(ospf6, area);
if (ospf6_check_and_set_router_abr(ospf6))
ospf6_abr_defaults_to_stub(ospf6);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(no_ospf6_area_nssa, no_ospf6_area_nssa_cmd, DEFPY(no_ospf6_area_nssa, no_ospf6_area_nssa_cmd,
"no area <A.B.C.D|(0-4294967295)> nssa", "no area <A.B.C.D|(0-4294967295)>$area_str nssa [no-summary$no_summary]",
NO_STR NO_STR
"OSPF6 area parameters\n" "OSPF6 area parameters\n"
"OSPF6 area ID in IP address format\n" "OSPF6 area ID in IP address format\n"
"OSPF6 area ID as a decimal value\n" "OSPF6 area ID as a decimal value\n"
"Configure OSPF6 area as nssa\n") "Configure OSPF6 area as nssa\n"
"Do not inject inter-area routes into area\n")
{ {
int idx_ipv4_number = 2;
struct ospf6_area *area; struct ospf6_area *area;
VTY_DECLVAR_CONTEXT(ospf6, ospf6); VTY_DECLVAR_CONTEXT(ospf6, ospf6);
OSPF6_CMD_AREA_GET(argv[idx_ipv4_number]->arg, area, ospf6); OSPF6_CMD_AREA_GET(area_str, area, ospf6);
ospf6_area_nssa_unset(ospf6, area); ospf6_area_nssa_unset(ospf6, area);
ospf6_area_no_summary_unset(ospf6, area);
return CMD_SUCCESS; return CMD_SUCCESS;
} }

View file

@ -588,6 +588,32 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
} }
} }
/*
* RFC 3101 - Section 2.5:
* "If the destination is a Type-7 default route (destination ID =
* DefaultDestination) and one of the following is true, then do
* nothing with this LSA and consider the next in the list:
*
* o The calculating router is a border router and the LSA has
* its P-bit clear. Appendix E describes a technique
* whereby an NSSA border router installs a Type-7 default
* LSA without propagating it.
*
* o The calculating router is a border router and is
* suppressing the import of summary routes as Type-3
* summary-LSAs".
*/
if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7
&& external->prefix.prefix_length == 0
&& CHECK_FLAG(ospf6->flag, OSPF6_FLAG_ABR)
&& (CHECK_FLAG(external->prefix.prefix_options,
OSPF6_PREFIX_OPTION_P)
|| oa->no_summary)) {
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
zlog_debug("Skipping Type-7 default route");
return;
}
/* Check the forwarding address */ /* Check the forwarding address */
if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) { if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
offset = sizeof(*external) offset = sizeof(*external)

View file

@ -92,6 +92,7 @@ ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la
clippy_scan += \ clippy_scan += \
ospf6d/ospf6_top.c \ ospf6d/ospf6_top.c \
ospf6d/ospf6_area.c \
ospf6d/ospf6_asbr.c \ ospf6d/ospf6_asbr.c \
ospf6d/ospf6_lsa.c \ ospf6d/ospf6_lsa.c \
ospf6d/ospf6_gr_helper.c \ ospf6d/ospf6_gr_helper.c \