Skip to content

Commit

Permalink
ospf6d: Support for nssa in ospfv3
Browse files Browse the repository at this point in the history
The following is implemented.
1. Configuring area as NSSA.
2. Generating Type 7 LSA.
3. Conversion of Type 7 to Type 5 ( Default Behavior).
4. NSSA ABR selection.

Reviewed-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
Co-authored-by: Kaushik <kaushiknath.null@gmail.com>
Co-authored-by: Soman K.S <somanks@gmail.com>
Signed-off-by: Kaushik <kaushiknath.null@gmail.com>
  • Loading branch information
2 people authored and rzalamena committed Jun 4, 2021
1 parent 10ddcc3 commit ad500b2
Show file tree
Hide file tree
Showing 23 changed files with 2,167 additions and 85 deletions.
100 changes: 79 additions & 21 deletions ospf6d/ospf6_abr.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "ospf6_asbr.h"
#include "ospf6_abr.h"
#include "ospf6d.h"
#include "ospf6_nssa.h"

unsigned char conf_debug_ospf6_abr;

Expand All @@ -57,14 +58,29 @@ int ospf6_is_router_abr(struct ospf6 *o)
struct listnode *node;
struct ospf6_area *oa;
int area_count = 0;
bool is_backbone = false;

for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa))
for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa)) {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug("%s, area_id %pI4", __func__, &oa->area_id);
if (IS_AREA_ENABLED(oa))
area_count++;

if (area_count > 1)
if (o->backbone == oa)
is_backbone = true;
}

if ((area_count > 1) && (is_backbone)) {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug("%s : set flag OSPF6_FLAG_ABR", __func__);
SET_FLAG(o->flag, OSPF6_FLAG_ABR);
return 1;
return 0;
} else {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug("%s : reset flag OSPF6_FLAG_ABR", __func__);
UNSET_FLAG(o->flag, OSPF6_FLAG_ABR);
return 0;
}
}

static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route *route,
Expand Down Expand Up @@ -156,37 +172,72 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
uint16_t type;
int is_debug = 0;

if (IS_OSPF6_DEBUG_ABR)
zlog_debug("%s : start area %s, route %pFX", __func__,
area->name, &route->prefix);

if (route->type == OSPF6_DEST_TYPE_ROUTER)
summary_table = area->summary_router;
else
summary_table = area->summary_prefix;

summary = ospf6_route_lookup(&route->prefix, summary_table);
if (summary) {
old = ospf6_lsdb_lookup(summary->path.origin.type,
summary->path.origin.id,
area->ospf6->router_id, area->lsdb);
/* Reset the OSPF6_LSA_UNAPPROVED flag */
if (old)
UNSET_FLAG(old->flag, OSPF6_LSA_UNAPPROVED);
}

/* Only destination type network, range or ASBR are considered */
if (route->type != OSPF6_DEST_TYPE_NETWORK
&& route->type != OSPF6_DEST_TYPE_RANGE
&& ((route->type != OSPF6_DEST_TYPE_ROUTER)
|| !CHECK_FLAG(route->path.router_bits, OSPF6_ROUTER_BIT_E))) {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug(
"%s: Route type %d flag 0x%x is none of network, range nor ASBR, ignore",
__func__, route->type, route->path.router_bits);
return 0;
}

/* AS External routes are never considered */
if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
|| route->path.type == OSPF6_PATH_TYPE_EXTERNAL2) {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug("%s : Path type is external, skip",
__func__);
return 0;
}

/* do not generate if the path's area is the same as target area */
if (route->path.area_id == area->area_id) {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug(
"%s: The route is in the area itself, ignore",
__func__);
return 0;
}

/* do not generate if the nexthops belongs to the target area */
if (ospf6_abr_nexthops_belong_to_area(route, area)) {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug(
"%s: The route's nexthop is in the same area, ignore",
__func__);
return 0;
}

if (route->type == OSPF6_DEST_TYPE_ROUTER) {
if (ADV_ROUTER_IN_PREFIX(&route->prefix)
== area->ospf6->router_id) {
zlog_debug(
"%s: Skipping ASBR announcement for ABR (%pI4)",
__func__,
&ADV_ROUTER_IN_PREFIX(&route->prefix));
if (IS_OSPF6_DEBUG_ABR)
zlog_debug(
"%s: Skipping ASBR announcement for ABR (%pI4)",
__func__,
&ADV_ROUTER_IN_PREFIX(&route->prefix));
return 0;
}
}
Expand All @@ -195,12 +246,12 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
if (IS_OSPF6_DEBUG_ABR
|| IS_OSPF6_DEBUG_ORIGINATE(INTER_ROUTER)) {
is_debug++;
zlog_debug(
"Originating summary in area %s for ASBR %pI4",
area->name,
&ADV_ROUTER_IN_PREFIX(&route->prefix));
if (IS_OSPF6_DEBUG_ABR)
zlog_debug(
"Originating summary in area %s for ASBR %pI4",
area->name,
&ADV_ROUTER_IN_PREFIX(&route->prefix));
}
summary_table = area->summary_router;
} else {
if (IS_OSPF6_DEBUG_ABR
|| IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX))
Expand Down Expand Up @@ -235,15 +286,8 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
zlog_debug(
"Originating summary in area %s for %pFX cost %u",
area->name, &route->prefix, route->path.cost);
summary_table = area->summary_prefix;
}

summary = ospf6_route_lookup(&route->prefix, summary_table);
if (summary)
old = ospf6_lsdb_lookup(summary->path.origin.type,
summary->path.origin.id,
area->ospf6->router_id, area->lsdb);

/* if this route has just removed, remove corresponding LSA */
if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)) {
if (is_debug)
Expand Down Expand Up @@ -496,9 +540,15 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
/* create LSA */
lsa = ospf6_lsa_create(lsa_header);

/* Reset the unapproved flag */
UNSET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);

/* Originate */
ospf6_lsa_originate_area(lsa, area);

if (IS_OSPF6_DEBUG_ABR)
zlog_debug("%s : finish area %s", __func__, area->name);

return 1;
}

Expand Down Expand Up @@ -566,8 +616,7 @@ ospf6_abr_range_summary_needs_update(struct ospf6_route *range, uint32_t cost)
return (redo_summary);
}

static void ospf6_abr_range_update(struct ospf6_route *range,
struct ospf6 *ospf6)
void ospf6_abr_range_update(struct ospf6_route *range, struct ospf6 *ospf6)
{
uint32_t cost = 0;
struct listnode *node, *nnode;
Expand All @@ -579,6 +628,10 @@ static void ospf6_abr_range_update(struct ospf6_route *range,
/* update range's cost and active flag */
cost = ospf6_abr_range_compute_cost(range, ospf6);

if (IS_OSPF6_DEBUG_ABR)
zlog_debug("%s: range %pFX, cost %d", __func__, &range->prefix,
cost);

/* Non-zero cost is a proxy for active longer prefixes in this range.
* If there are active routes covered by this range AND either the
* configured
Expand All @@ -595,6 +648,9 @@ static void ospf6_abr_range_update(struct ospf6_route *range,
*/

if (ospf6_abr_range_summary_needs_update(range, cost)) {
if (IS_OSPF6_DEBUG_ABR)
zlog_debug("%s: range %pFX update", __func__,
&range->prefix);
for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa))
summary_orig +=
ospf6_abr_originate_summary_to_area(range, oa);
Expand Down Expand Up @@ -628,6 +684,8 @@ void ospf6_abr_originate_summary(struct ospf6_route *route, struct ospf6 *ospf6)
struct ospf6_area *oa;
struct ospf6_route *range = NULL;

if (IS_OSPF6_DEBUG_ABR)
zlog_debug("%s: route %pFX", __func__, &route->prefix);

if (route->type == OSPF6_DEST_TYPE_NETWORK) {
oa = ospf6_area_lookup(route->path.area_id, ospf6);
Expand Down
4 changes: 4 additions & 0 deletions ospf6d/ospf6_abr.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct ospf6_inter_router_lsa {
}

#define OSPF6_ABR_RANGE_CLEAR_COST(range) (range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC)
#define IS_OSPF6_ABR(o) ((o)->flag & OSPF6_FLAG_ABR)

extern int ospf6_is_router_abr(struct ospf6 *o);

Expand Down Expand Up @@ -88,5 +89,8 @@ extern void ospf6_abr_old_path_update(struct ospf6_route *old_route,
struct ospf6_route_table *table);
extern void ospf6_abr_init(void);
extern void ospf6_abr_reexport(struct ospf6_area *oa);
extern void ospf6_abr_range_update(struct ospf6_route *range,
struct ospf6 *ospf6);
extern void ospf6_abr_remove_unapproved_summaries(struct ospf6 *ospf6);

#endif /*OSPF6_ABR_H*/
68 changes: 68 additions & 0 deletions ospf6d/ospf6_area.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,25 @@
#include "ospf6_asbr.h"
#include "ospf6d.h"
#include "lib/json.h"
#include "ospf6_nssa.h"

DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA, "OSPF6 area");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name");

/* Utility functions. */
int str2area_id(const char *str, struct in_addr *area_id, int *area_id_fmt)
{
char *ep;

area_id->s_addr = htonl(strtoul(str, &ep, 10));
if (*ep && !inet_aton(str, area_id))
return -1;

*area_id_fmt = *ep ? OSPF6_AREA_FMT_DECIMAL : OSPF6_AREA_FMT_DOTTEDQUAD;

return 0;
}

int ospf6_area_cmp(void *va, void *vb)
{
struct ospf6_area *oa = (struct ospf6_area *)va;
Expand All @@ -60,6 +75,7 @@ int ospf6_area_cmp(void *va, void *vb)
static void ospf6_area_lsdb_hook_add(struct ospf6_lsa *lsa)
{
switch (ntohs(lsa->header->type)) {

case OSPF6_LSTYPE_ROUTER:
case OSPF6_LSTYPE_NETWORK:
if (IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type)) {
Expand All @@ -82,6 +98,10 @@ static void ospf6_area_lsdb_hook_add(struct ospf6_lsa *lsa)
(struct ospf6_area *)lsa->lsdb->data);
break;

case OSPF6_LSTYPE_TYPE_7:
ospf6_asbr_lsa_add(lsa);
break;

default:
break;
}
Expand Down Expand Up @@ -611,6 +631,8 @@ void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6)
else
vty_out(vty, " area %s stub\n", oa->name);
}
if (IS_AREA_NSSA(oa))
vty_out(vty, " area %s nssa\n", oa->name);
if (PREFIX_NAME_IN(oa))
vty_out(vty, " area %s filter-list prefix %s in\n",
oa->name, PREFIX_NAME_IN(oa));
Expand Down Expand Up @@ -1216,6 +1238,48 @@ DEFUN (no_ospf6_area_stub_no_summary,
return CMD_SUCCESS;
}

DEFUN(ospf6_area_nssa, ospf6_area_nssa_cmd,
"area <A.B.C.D|(0-4294967295)> nssa",
"OSPF6 area parameters\n"
"OSPF6 area ID in IP address format\n"
"OSPF6 area ID as a decimal value\n"
"Configure OSPF6 area as nssa\n")
{
int idx_ipv4_number = 1;
struct ospf6_area *area;

VTY_DECLVAR_CONTEXT(ospf6, ospf6);
OSPF6_CMD_AREA_GET(argv[idx_ipv4_number]->arg, area, ospf6);

if (!ospf6_area_nssa_set(ospf6, area)) {
vty_out(vty,
"First deconfigure all virtual link through this area\n");
return CMD_WARNING_CONFIG_FAILED;
}

return CMD_SUCCESS;
}

DEFUN(no_ospf6_area_nssa, no_ospf6_area_nssa_cmd,
"no area <A.B.C.D|(0-4294967295)> nssa",
NO_STR
"OSPF6 area parameters\n"
"OSPF6 area ID in IP address format\n"
"OSPF6 area ID as a decimal value\n"
"Configure OSPF6 area as nssa\n")
{
int idx_ipv4_number = 2;
struct ospf6_area *area;

VTY_DECLVAR_CONTEXT(ospf6, ospf6);
OSPF6_CMD_AREA_GET(argv[idx_ipv4_number]->arg, area, ospf6);

ospf6_area_nssa_unset(ospf6, area);

return CMD_SUCCESS;
}


void ospf6_area_init(void)
{
install_element(VIEW_NODE, &show_ipv6_ospf6_spf_tree_cmd);
Expand All @@ -1237,6 +1301,10 @@ void ospf6_area_init(void)

install_element(OSPF6_NODE, &area_filter_list_cmd);
install_element(OSPF6_NODE, &no_area_filter_list_cmd);

/* "area nssa" commands. */
install_element(OSPF6_NODE, &ospf6_area_nssa_cmd);
install_element(OSPF6_NODE, &no_ospf6_area_nssa_cmd);
}

void ospf6_area_interface_delete(struct ospf6_interface *oi)
Expand Down
11 changes: 11 additions & 0 deletions ospf6d/ospf6_area.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,27 @@ struct ospf6_area {

uint32_t full_nbrs; /* Fully adjacent neighbors. */
uint8_t intra_prefix_originate; /* Force intra_prefix lsa originate */
uint8_t NSSATranslatorRole; /* NSSA configured role */
#define OSPF6_NSSA_ROLE_NEVER 0
#define OSPF6_NSSA_ROLE_CANDIDATE 1
#define OSPF6_NSSA_ROLE_ALWAYS 2
uint8_t NSSATranslatorState; /* NSSA operational role */
#define OSPF6_NSSA_TRANSLATE_DISABLED 0
#define OSPF6_NSSA_TRANSLATE_ENABLED 1
};

#define OSPF6_AREA_DEFAULT 0x00
#define OSPF6_AREA_ENABLE 0x01
#define OSPF6_AREA_ACTIVE 0x02
#define OSPF6_AREA_TRANSIT 0x04 /* TransitCapability */
#define OSPF6_AREA_STUB 0x08
#define OSPF6_AREA_NSSA 0x10

#define IS_AREA_ENABLED(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ENABLE))
#define IS_AREA_ACTIVE(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ACTIVE))
#define IS_AREA_TRANSIT(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_TRANSIT))
#define IS_AREA_STUB(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_STUB))
#define IS_AREA_NSSA(oa) (CHECK_FLAG((oa)->flag, OSPF6_AREA_NSSA))

#define OSPF6_CMD_AREA_GET(str, oa, ospf6) \
{ \
Expand Down Expand Up @@ -153,5 +163,6 @@ extern void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6);
extern void ospf6_area_init(void);
struct ospf6_interface;
extern void ospf6_area_interface_delete(struct ospf6_interface *oi);
int str2area_id(const char *str, struct in_addr *area_id, int *area_id_fmt);

#endif /* OSPF_AREA_H */
Loading

0 comments on commit ad500b2

Please sign in to comment.