mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 03:29:06 +00:00 
			
		
		
		
	Include an event ptr-to-ptr in the event_execute() api call, like the various schedule api calls. This allows the execute() api to cancel an existing scheduled task if that task is being executed inline. Signed-off-by: Mark Stapp <mjs@labn.net>
		
			
				
	
	
		
			1484 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1484 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
						|
/*
 | 
						|
 * OSPFv3 Not So Stubby Area implementation.
 | 
						|
 *
 | 
						|
 * Copyright (C) 2021 Kaushik Nath
 | 
						|
 * Copyright (C) 2021 Soman K.S
 | 
						|
 */
 | 
						|
 | 
						|
#include <zebra.h>
 | 
						|
#include "log.h"
 | 
						|
#include "prefix.h"
 | 
						|
#include "table.h"
 | 
						|
#include "vty.h"
 | 
						|
#include "linklist.h"
 | 
						|
#include "command.h"
 | 
						|
#include "frrevent.h"
 | 
						|
#include "plist.h"
 | 
						|
#include "filter.h"
 | 
						|
 | 
						|
#include "ospf6_proto.h"
 | 
						|
#include "ospf6_route.h"
 | 
						|
#include "ospf6_lsa.h"
 | 
						|
#include "ospf6_route.h"
 | 
						|
#include "ospf6_lsdb.h"
 | 
						|
#include "ospf6_message.h"
 | 
						|
#include "ospf6_zebra.h"
 | 
						|
 | 
						|
#include "ospf6_top.h"
 | 
						|
#include "ospf6_area.h"
 | 
						|
#include "ospf6_interface.h"
 | 
						|
#include "ospf6_neighbor.h"
 | 
						|
 | 
						|
#include "ospf6_flood.h"
 | 
						|
#include "ospf6_intra.h"
 | 
						|
#include "ospf6_abr.h"
 | 
						|
#include "ospf6_asbr.h"
 | 
						|
#include "ospf6d.h"
 | 
						|
#include "ospf6_nssa.h"
 | 
						|
#include "ospf6d/ospf6_nssa_clippy.c"
 | 
						|
 | 
						|
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA,         "OSPF6 LSA");
 | 
						|
unsigned char config_debug_ospf6_nssa = 0;
 | 
						|
/* Determine whether this router is elected translator or not for area */
 | 
						|
static int ospf6_abr_nssa_am_elected(struct ospf6_area *oa)
 | 
						|
{
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
	struct ospf6_router_lsa *router_lsa;
 | 
						|
	in_addr_t *best = NULL;
 | 
						|
	uint16_t type;
 | 
						|
 | 
						|
	type = htons(OSPF6_LSTYPE_ROUTER);
 | 
						|
 | 
						|
	/* Verify all the router LSA to compare the router ID */
 | 
						|
	for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) {
 | 
						|
 | 
						|
		router_lsa = (struct ospf6_router_lsa
 | 
						|
				      *)((caddr_t)lsa->header
 | 
						|
					 + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
		/* ignore non-ABR routers */
 | 
						|
		if (!CHECK_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B))
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* Router has Nt flag - always translate */
 | 
						|
		if (CHECK_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_NT)) {
 | 
						|
			if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
				zlog_debug("%s: router %pI4 asserts Nt",
 | 
						|
					   __func__, &lsa->header->id);
 | 
						|
			return 1;
 | 
						|
		}
 | 
						|
 | 
						|
		if (best == NULL)
 | 
						|
			best = &lsa->header->adv_router;
 | 
						|
		else if (IPV4_ADDR_CMP(best, &lsa->header->adv_router) < 0)
 | 
						|
			best = &lsa->header->adv_router;
 | 
						|
	}
 | 
						|
 | 
						|
	if (best == NULL) {
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("%s: best electable ABR not found",
 | 
						|
				   __func__);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: best electable ABR is: %pI4", __func__, best);
 | 
						|
 | 
						|
	if (IPV4_ADDR_CMP(best, &oa->ospf6->router_id) <= 0) {
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("%s: elected ABR is: %pI4", __func__, best);
 | 
						|
		return 1;
 | 
						|
	} else {
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("%s: not elected best %pI4, router ID %pI4",
 | 
						|
				   __func__, best, &oa->ospf6->router_id);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* Flush the translated LSA when translation is disabled */
 | 
						|
static void ospf6_flush_translated_lsa(struct ospf6_area *area)
 | 
						|
{
 | 
						|
	uint16_t type;
 | 
						|
	struct ospf6_lsa *type7;
 | 
						|
	struct ospf6_lsa *type5;
 | 
						|
	struct ospf6 *ospf6 = area->ospf6;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: start area %s", __func__, area->name);
 | 
						|
 | 
						|
	type = htons(OSPF6_LSTYPE_TYPE_7);
 | 
						|
	for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id, type7)) {
 | 
						|
		type5 = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
 | 
						|
					  type7->external_lsa_id,
 | 
						|
					  ospf6->router_id, ospf6->lsdb);
 | 
						|
		if (type5 && CHECK_FLAG(type5->flag, OSPF6_LSA_LOCAL_XLT))
 | 
						|
			ospf6_lsa_premature_aging(type5);
 | 
						|
	}
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: finish area %s", __func__, area->name);
 | 
						|
}
 | 
						|
 | 
						|
/* Check NSSA status for all nssa areas */
 | 
						|
void ospf6_abr_nssa_check_status(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct ospf6_area *area;
 | 
						|
	struct listnode *lnode, *nnode;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, nnode, area)) {
 | 
						|
		uint8_t old_state = area->NSSATranslatorState;
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("%s: checking area %s flag %x", __func__,
 | 
						|
				   area->name, area->flag);
 | 
						|
 | 
						|
		if (!IS_AREA_NSSA(area))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (!CHECK_FLAG(area->ospf6->flag, OSPF6_FLAG_ABR)) {
 | 
						|
			if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
				zlog_debug("%s: not ABR", __func__);
 | 
						|
			area->NSSATranslatorState =
 | 
						|
				OSPF6_NSSA_TRANSLATE_DISABLED;
 | 
						|
			ospf6_flush_translated_lsa(area);
 | 
						|
		} else {
 | 
						|
			/* Router is ABR */
 | 
						|
			if (area->NSSATranslatorRole == OSPF6_NSSA_ROLE_ALWAYS)
 | 
						|
				area->NSSATranslatorState =
 | 
						|
					OSPF6_NSSA_TRANSLATE_ENABLED;
 | 
						|
			else {
 | 
						|
				/* We are a candidate for Translation */
 | 
						|
				if (ospf6_abr_nssa_am_elected(area) > 0) {
 | 
						|
					area->NSSATranslatorState =
 | 
						|
						OSPF6_NSSA_TRANSLATE_ENABLED;
 | 
						|
					if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
						zlog_debug(
 | 
						|
							"%s: elected translator",
 | 
						|
							__func__);
 | 
						|
				} else {
 | 
						|
					area->NSSATranslatorState =
 | 
						|
						OSPF6_NSSA_TRANSLATE_DISABLED;
 | 
						|
					ospf6_flush_translated_lsa(area);
 | 
						|
					if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
						zlog_debug("%s: not elected",
 | 
						|
							   __func__);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/* RFC3101, 3.1:
 | 
						|
		 * All NSSA border routers must set the E-bit in the Type-1
 | 
						|
		 * router-LSAs of their directly attached non-stub areas, even
 | 
						|
		 * when they are not translating.
 | 
						|
		 */
 | 
						|
		if (old_state != area->NSSATranslatorState) {
 | 
						|
			if (old_state == OSPF6_NSSA_TRANSLATE_DISABLED) {
 | 
						|
				++ospf6->redist_count;
 | 
						|
				ospf6_asbr_status_update(ospf6,
 | 
						|
							 ospf6->redist_count);
 | 
						|
			} else {
 | 
						|
				--ospf6->redist_count;
 | 
						|
				ospf6_asbr_status_update(ospf6,
 | 
						|
							 ospf6->redist_count);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* Mark the summary LSA's as unapproved, when ABR status changes.*/
 | 
						|
static void ospf6_abr_unapprove_summaries(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_area *area;
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
	uint16_t type;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("%s : Start", __func__);
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
 | 
						|
		if (IS_OSPF6_DEBUG_ABR)
 | 
						|
			zlog_debug("%s : considering area %pI4", __func__,
 | 
						|
				   &area->area_id);
 | 
						|
		/* Inter area router LSA */
 | 
						|
		type = htons(OSPF6_LSTYPE_INTER_ROUTER);
 | 
						|
		for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id,
 | 
						|
					   lsa)) {
 | 
						|
			if (IS_OSPF6_DEBUG_ABR)
 | 
						|
				zlog_debug(
 | 
						|
					"%s : approved unset on summary link id %pI4",
 | 
						|
					__func__, &lsa->header->id);
 | 
						|
			SET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
 | 
						|
		}
 | 
						|
		/* Inter area prefix LSA */
 | 
						|
		type = htons(OSPF6_LSTYPE_INTER_PREFIX);
 | 
						|
		for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id,
 | 
						|
					   lsa)) {
 | 
						|
			if (IS_OSPF6_DEBUG_ABR)
 | 
						|
				zlog_debug(
 | 
						|
					"%s : approved unset on asbr-summary link id %pI4",
 | 
						|
					__func__, &lsa->header->id);
 | 
						|
			SET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("%s : Stop", __func__);
 | 
						|
}
 | 
						|
 | 
						|
/* Re-advertise inter-area router LSA's */
 | 
						|
void ospf6_asbr_prefix_readvertise(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct ospf6_route *brouter;
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_area *oa;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("Re-examining Inter-Router prefixes");
 | 
						|
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) {
 | 
						|
		for (brouter = ospf6_route_head(oa->ospf6->brouter_table);
 | 
						|
		     brouter; brouter = ospf6_route_next(brouter))
 | 
						|
			ospf6_abr_originate_summary_to_area(brouter, oa);
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("Finished re-examining Inter-Router prefixes");
 | 
						|
}
 | 
						|
 | 
						|
/* Advertise prefixes configured using area <area-id> range command */
 | 
						|
static void ospf6_abr_announce_aggregates(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct ospf6_area *area;
 | 
						|
	struct ospf6_route *range;
 | 
						|
	struct listnode *node;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("%s: Start", __func__);
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
 | 
						|
		if (IS_OSPF6_DEBUG_ABR)
 | 
						|
			zlog_debug(
 | 
						|
				"ospf_abr_announce_aggregates(): looking at area %pI4",
 | 
						|
				&area->area_id);
 | 
						|
 | 
						|
		for (range = ospf6_route_head(area->range_table); range;
 | 
						|
		     range = ospf6_route_next(range))
 | 
						|
			ospf6_abr_range_update(range, ospf6);
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("%s: Stop", __func__);
 | 
						|
}
 | 
						|
 | 
						|
/* Flush the summary LSA's which are not approved.*/
 | 
						|
void ospf6_abr_remove_unapproved_summaries(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_area *area;
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
	uint16_t type;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("%s : Start", __func__);
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
 | 
						|
		if (IS_OSPF6_DEBUG_ABR)
 | 
						|
			zlog_debug("%s : looking at area %pI4", __func__,
 | 
						|
				   &area->area_id);
 | 
						|
 | 
						|
		/* Inter area router LSA */
 | 
						|
		type = htons(OSPF6_LSTYPE_INTER_ROUTER);
 | 
						|
		for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id,
 | 
						|
					   lsa)) {
 | 
						|
			if (CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED))
 | 
						|
				ospf6_lsa_premature_aging(lsa);
 | 
						|
		}
 | 
						|
 | 
						|
		/* Inter area prefix LSA */
 | 
						|
		type = htons(OSPF6_LSTYPE_INTER_PREFIX);
 | 
						|
		for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id,
 | 
						|
					   lsa)) {
 | 
						|
			if (CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED))
 | 
						|
				ospf6_lsa_premature_aging(lsa);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("%s : Stop", __func__);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * This is the function taking care about ABR stuff, i.e.
 | 
						|
 * summary-LSA origination and flooding.
 | 
						|
 */
 | 
						|
static void ospf6_abr_task(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("%s : Start", __func__);
 | 
						|
 | 
						|
	if (ospf6->route_table == NULL || ospf6->brouter_table == NULL) {
 | 
						|
		if (IS_OSPF6_DEBUG_ABR)
 | 
						|
			zlog_debug("%s : Routing tables are not yet ready",
 | 
						|
				   __func__);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	ospf6_abr_unapprove_summaries(ospf6);
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("%s : prepare aggregates", __func__);
 | 
						|
 | 
						|
	ospf6_abr_range_reset_cost(ospf6);
 | 
						|
 | 
						|
	if (IS_OSPF6_ABR(ospf6)) {
 | 
						|
		if (IS_OSPF6_DEBUG_ABR)
 | 
						|
			zlog_debug("%s : process network RT", __func__);
 | 
						|
		ospf6_abr_prefix_resummarize(ospf6);
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_ABR)
 | 
						|
			zlog_debug("%s : process router RT", __func__);
 | 
						|
		ospf6_asbr_prefix_readvertise(ospf6);
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_ABR)
 | 
						|
			zlog_debug("%s : announce aggregates", __func__);
 | 
						|
		ospf6_abr_announce_aggregates(ospf6);
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_ABR)
 | 
						|
			zlog_debug("%s : announce stub defaults", __func__);
 | 
						|
		ospf6_abr_defaults_to_stub(ospf6);
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_ABR)
 | 
						|
			zlog_debug("%s : announce NSSA Type-7 defaults",
 | 
						|
				   __func__);
 | 
						|
		ospf6_abr_nssa_type_7_defaults(ospf6);
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("%s : remove unapproved summaries", __func__);
 | 
						|
	ospf6_abr_remove_unapproved_summaries(ospf6);
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("%s : Stop", __func__);
 | 
						|
}
 | 
						|
 | 
						|
/* For NSSA Translations
 | 
						|
 * Mark the translated LSA's as unapproved. */
 | 
						|
static void ospf6_abr_unapprove_translates(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
	uint16_t type;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: Start", __func__);
 | 
						|
 | 
						|
	type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
 | 
						|
	for (ALL_LSDB_TYPED(ospf6->lsdb, type, lsa)) {
 | 
						|
		if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT)) {
 | 
						|
			SET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
 | 
						|
			if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
				zlog_debug(
 | 
						|
					"%s : approved unset on link id %pI4",
 | 
						|
					__func__, &lsa->header->id);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: Stop", __func__);
 | 
						|
}
 | 
						|
 | 
						|
/* Generate the translated external lsa from NSSA lsa */
 | 
						|
static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area,
 | 
						|
						       struct ospf6_lsa *type7)
 | 
						|
{
 | 
						|
	char buffer[OSPF6_MAX_LSASIZE];
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
	struct ospf6_as_external_lsa *ext, *extnew;
 | 
						|
	struct ospf6_lsa_header *lsa_header;
 | 
						|
	caddr_t old_ptr, new_ptr;
 | 
						|
	struct ospf6_as_external_lsa *nssa;
 | 
						|
	struct prefix prefix;
 | 
						|
	struct ospf6 *ospf6 = area->ospf6;
 | 
						|
	ptrdiff_t tag_offset = 0;
 | 
						|
	route_tag_t network_order;
 | 
						|
	struct ospf6_route *range;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s : Start", __func__);
 | 
						|
 | 
						|
	if (area->NSSATranslatorState == OSPF6_NSSA_TRANSLATE_DISABLED) {
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("%s: Translation disabled for area %s",
 | 
						|
				   __func__, area->name);
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	/* find the translated Type-5 for this Type-7 */
 | 
						|
	nssa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
 | 
						|
		type7->header);
 | 
						|
	prefix.family = AF_INET6;
 | 
						|
	prefix.prefixlen = nssa->prefix.prefix_length;
 | 
						|
	ospf6_prefix_in6_addr(&prefix.u.prefix6, nssa, &nssa->prefix);
 | 
						|
 | 
						|
	/* Check if the Type-7 LSA should be suppressed by aggregation. */
 | 
						|
	range = ospf6_route_lookup_bestmatch(&prefix, area->nssa_range_table);
 | 
						|
	if (range && !prefix_same(&prefix, &range->prefix)
 | 
						|
	    && !CHECK_FLAG(range->flag, OSPF6_ROUTE_REMOVE)) {
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug(
 | 
						|
				"%s: LSA %s suppressed by range %pFX of area %s",
 | 
						|
				__func__, type7->name, &range->prefix,
 | 
						|
				area->name);
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	/* prepare buffer */
 | 
						|
	memset(buffer, 0, sizeof(buffer));
 | 
						|
	lsa_header = (struct ospf6_lsa_header *)buffer;
 | 
						|
	extnew = (struct ospf6_as_external_lsa
 | 
						|
			  *)((caddr_t)lsa_header
 | 
						|
			     + sizeof(struct ospf6_lsa_header));
 | 
						|
	ext = (struct ospf6_as_external_lsa
 | 
						|
		       *)((caddr_t)(type7->header)
 | 
						|
			  + sizeof(struct ospf6_lsa_header));
 | 
						|
	old_ptr =
 | 
						|
		(caddr_t)((caddr_t)ext + sizeof(struct ospf6_as_external_lsa));
 | 
						|
	new_ptr = (caddr_t)((caddr_t)extnew
 | 
						|
			    + sizeof(struct ospf6_as_external_lsa));
 | 
						|
 | 
						|
	memcpy(extnew, ext, sizeof(struct ospf6_as_external_lsa));
 | 
						|
 | 
						|
	/* set Prefix */
 | 
						|
	memcpy(new_ptr, old_ptr, OSPF6_PREFIX_SPACE(ext->prefix.prefix_length));
 | 
						|
	ospf6_prefix_apply_mask(&extnew->prefix);
 | 
						|
	new_ptr += OSPF6_PREFIX_SPACE(extnew->prefix.prefix_length);
 | 
						|
 | 
						|
	tag_offset =
 | 
						|
		sizeof(*ext) + OSPF6_PREFIX_SPACE(ext->prefix.prefix_length);
 | 
						|
 | 
						|
	/* Forwarding address */
 | 
						|
	if (CHECK_FLAG(ext->bits_metric, OSPF6_ASBR_BIT_F)) {
 | 
						|
		memcpy(new_ptr, (caddr_t)ext + tag_offset,
 | 
						|
		       sizeof(struct in6_addr));
 | 
						|
		new_ptr += sizeof(struct in6_addr);
 | 
						|
		tag_offset += sizeof(struct in6_addr);
 | 
						|
	}
 | 
						|
	/* External Route Tag */
 | 
						|
	if (CHECK_FLAG(ext->bits_metric, OSPF6_ASBR_BIT_T)) {
 | 
						|
		memcpy(&network_order, (caddr_t)ext + tag_offset,
 | 
						|
		       sizeof(network_order));
 | 
						|
		network_order = htonl(network_order);
 | 
						|
		memcpy(new_ptr, &network_order, sizeof(network_order));
 | 
						|
		new_ptr += sizeof(network_order);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Fill LSA Header */
 | 
						|
	lsa_header->age = 0;
 | 
						|
	lsa_header->type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
 | 
						|
	lsa_header->id = htonl(ospf6->external_id);
 | 
						|
	ospf6->external_id++;
 | 
						|
	lsa_header->adv_router = ospf6->router_id;
 | 
						|
	lsa_header->seqnum =
 | 
						|
		ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
 | 
						|
				    lsa_header->adv_router, ospf6->lsdb);
 | 
						|
	lsa_header->length = htons((caddr_t)new_ptr - (caddr_t)lsa_header);
 | 
						|
	type7->external_lsa_id = lsa_header->id;
 | 
						|
 | 
						|
	/* LSA checksum */
 | 
						|
	ospf6_lsa_checksum(lsa_header);
 | 
						|
 | 
						|
	/* create LSA */
 | 
						|
	lsa = ospf6_lsa_create(lsa_header);
 | 
						|
 | 
						|
	SET_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT);
 | 
						|
	UNSET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
 | 
						|
 | 
						|
	/* Originate */
 | 
						|
	ospf6_lsa_originate_process(lsa, ospf6);
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: Originated type5 LSA id %pI4", __func__,
 | 
						|
			   &lsa_header->id);
 | 
						|
	return lsa;
 | 
						|
}
 | 
						|
 | 
						|
/* Delete LSA from retransmission list */
 | 
						|
static void ospf6_ls_retransmit_delete_nbr_as(struct ospf6 *ospf6,
 | 
						|
					      struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_area *area;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s : start lsa %s", __func__, lsa->name);
 | 
						|
 | 
						|
	/*The function ospf6_flood_clear_area removes LSA from
 | 
						|
	 * retransmit list.
 | 
						|
	 */
 | 
						|
	for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area))
 | 
						|
		ospf6_flood_clear_area(lsa, area);
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s : finish lsa %s", __func__, lsa->name);
 | 
						|
}
 | 
						|
 | 
						|
/* Refresh translated AS-external-LSA. */
 | 
						|
struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area,
 | 
						|
						struct ospf6_lsa *type7,
 | 
						|
						struct ospf6_lsa *type5)
 | 
						|
{
 | 
						|
	struct ospf6_lsa *new = NULL;
 | 
						|
	struct prefix prefix;
 | 
						|
	struct ospf6 *ospf6 = area->ospf6;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s : start area %s", __func__, area->name);
 | 
						|
 | 
						|
	/* Sanity checks. */
 | 
						|
	assert(type7);
 | 
						|
 | 
						|
	/* Find the AS external LSA */
 | 
						|
	if (type5 == NULL) {
 | 
						|
		struct ospf6_as_external_lsa *ext_lsa;
 | 
						|
		struct ospf6_route *match;
 | 
						|
 | 
						|
		/* Find the AS external LSA from Type-7 LSA */
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug(
 | 
						|
				"%s: try to find translated Type-5 LSA for %s",
 | 
						|
				__func__, type7->name);
 | 
						|
 | 
						|
		ext_lsa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
 | 
						|
			type7->header);
 | 
						|
		prefix.family = AF_INET6;
 | 
						|
		prefix.prefixlen = ext_lsa->prefix.prefix_length;
 | 
						|
		ospf6_prefix_in6_addr(&prefix.u.prefix6, ext_lsa,
 | 
						|
				      &ext_lsa->prefix);
 | 
						|
 | 
						|
		match = ospf6_route_lookup(&prefix, ospf6->external_table);
 | 
						|
		if (match)
 | 
						|
			type5 = ospf6_lsdb_lookup(
 | 
						|
				htons(OSPF6_LSTYPE_AS_EXTERNAL),
 | 
						|
				match->path.origin.id, ospf6->router_id,
 | 
						|
				ospf6->lsdb);
 | 
						|
	}
 | 
						|
 | 
						|
	if (type5) {
 | 
						|
		if (CHECK_FLAG(type5->flag, OSPF6_LSA_LOCAL_XLT)) {
 | 
						|
			/* Delete LSA from neighbor retransmit-list. */
 | 
						|
			ospf6_ls_retransmit_delete_nbr_as(ospf6, type5);
 | 
						|
 | 
						|
			/* Flush the LSA */
 | 
						|
			ospf6_lsa_premature_aging(type5);
 | 
						|
		} else {
 | 
						|
			if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
				zlog_debug("%s: Invalid translated LSA %s",
 | 
						|
					   __func__, type5->name);
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* create new translated LSA */
 | 
						|
	if (ospf6_lsa_age_current(type7) != OSPF_LSA_MAXAGE) {
 | 
						|
		if ((new = ospf6_lsa_translated_nssa_new(area, type7))
 | 
						|
		    == NULL) {
 | 
						|
			if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
				zlog_debug(
 | 
						|
					"%s: Could not translate Type-7 for %pI4",
 | 
						|
					__func__, &type7->header->id);
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: finish", __func__);
 | 
						|
 | 
						|
	return new;
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_abr_translate_nssa(struct ospf6_area *area,
 | 
						|
				     struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	/* Incoming Type-7 or aggregated Type-7
 | 
						|
	 *
 | 
						|
	 * LSA is skipped if P-bit is off.
 | 
						|
	 *
 | 
						|
	 * The Type-7 is translated, Installed/Approved as a Type-5 into
 | 
						|
	 * global LSDB, then Flooded through AS
 | 
						|
	 *
 | 
						|
	 *  Later, any Unapproved Translated Type-5's are flushed/discarded
 | 
						|
	 */
 | 
						|
 | 
						|
	struct ospf6_lsa *old = NULL;
 | 
						|
	struct ospf6_as_external_lsa *nssa_lsa;
 | 
						|
	struct prefix prefix;
 | 
						|
	struct ospf6_route *match;
 | 
						|
	struct ospf6 *ospf6;
 | 
						|
 | 
						|
	ospf6 = area->ospf6;
 | 
						|
	nssa_lsa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
 | 
						|
		lsa->header);
 | 
						|
 | 
						|
	if (!CHECK_FLAG(nssa_lsa->prefix.prefix_options,
 | 
						|
			OSPF6_PREFIX_OPTION_P)) {
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug(
 | 
						|
				"%s : LSA Id %pI4, P-bit off, NO Translation",
 | 
						|
				__func__, &lsa->header->id);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug(
 | 
						|
			"%s : LSA Id %pI4 external ID %pI4, Translating type 7 to 5",
 | 
						|
			__func__, &lsa->header->id, &lsa->external_lsa_id);
 | 
						|
 | 
						|
	prefix.family = AF_INET6;
 | 
						|
	prefix.prefixlen = nssa_lsa->prefix.prefix_length;
 | 
						|
	ospf6_prefix_in6_addr(&prefix.u.prefix6, nssa_lsa, &nssa_lsa->prefix);
 | 
						|
 | 
						|
	if (!CHECK_FLAG(nssa_lsa->bits_metric, OSPF6_ASBR_BIT_F)) {
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug(
 | 
						|
				"%s : LSA Id %pI4, Forward address is 0, NO Translation",
 | 
						|
				__func__, &lsa->header->id);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Find the type-5 LSA in the area-range table */
 | 
						|
	match = ospf6_route_lookup_bestmatch(&prefix, area->nssa_range_table);
 | 
						|
	if (match && CHECK_FLAG(match->flag, OSPF6_ROUTE_NSSA_RANGE)) {
 | 
						|
		if (prefix_same(&prefix, &match->prefix)) {
 | 
						|
			/* The prefix range is being removed,
 | 
						|
			 * no need to refresh
 | 
						|
			 */
 | 
						|
			if
 | 
						|
				CHECK_FLAG(match->flag, OSPF6_ROUTE_REMOVE)
 | 
						|
			return;
 | 
						|
		} else {
 | 
						|
			if (!CHECK_FLAG(match->flag, OSPF6_ROUTE_REMOVE)) {
 | 
						|
				if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
					zlog_debug(
 | 
						|
						"%s: LSA Id %pI4 suppressed by range %pFX of area %s",
 | 
						|
						__func__, &lsa->header->id,
 | 
						|
						&match->prefix, area->name);
 | 
						|
				/* LSA will be suppressed by area-range command,
 | 
						|
				 * no need to refresh
 | 
						|
				 */
 | 
						|
				return;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* Find the existing AS-External LSA for this prefix */
 | 
						|
	match = ospf6_route_lookup(&prefix, ospf6->route_table);
 | 
						|
	if (match) {
 | 
						|
		old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
 | 
						|
					lsa->external_lsa_id, ospf6->router_id,
 | 
						|
					ospf6->lsdb);
 | 
						|
	}
 | 
						|
 | 
						|
	if (OSPF6_LSA_IS_MAXAGE(lsa)) {
 | 
						|
		if (old)
 | 
						|
			ospf6_lsa_premature_aging(old);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (old && !OSPF6_LSA_IS_MAXAGE(old)) {
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug(
 | 
						|
				"%s : found old translated LSA Id %pI4, skip",
 | 
						|
				__func__, &old->header->id);
 | 
						|
 | 
						|
		UNSET_FLAG(old->flag, OSPF6_LSA_UNAPPROVED);
 | 
						|
		return;
 | 
						|
 | 
						|
	} else {
 | 
						|
		/* no existing external route for this LSA Id
 | 
						|
		 * originate translated LSA
 | 
						|
		 */
 | 
						|
 | 
						|
		if (ospf6_lsa_translated_nssa_new(area, lsa) == NULL) {
 | 
						|
			if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
				zlog_debug(
 | 
						|
					"%s : Could not translate Type-7 for %pI4 to Type-5",
 | 
						|
					__func__, &lsa->header->id);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_abr_process_nssa_translates(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	/* Scan through all NSSA_LSDB records for all areas;
 | 
						|
	 * If P-bit is on, translate all Type-7's to 5's and aggregate or
 | 
						|
	 * flood install as approved in Type-5 LSDB with XLATE Flag on
 | 
						|
	 * later, do same for all aggregates...  At end, DISCARD all
 | 
						|
	 * remaining UNAPPROVED Type-5's (Aggregate is for future ) */
 | 
						|
 | 
						|
	struct listnode *node;
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
	int type;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s : Start", __func__);
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
 | 
						|
		if (!IS_AREA_NSSA(oa))
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* skip if not translator */
 | 
						|
		if (oa->NSSATranslatorState == OSPF6_NSSA_TRANSLATE_DISABLED) {
 | 
						|
			zlog_debug("%s area %pI4 NSSATranslatorState %d",
 | 
						|
				   __func__, &oa->area_id,
 | 
						|
				   oa->NSSATranslatorState);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("%s : looking at area %pI4", __func__,
 | 
						|
				   &oa->area_id);
 | 
						|
 | 
						|
		type = htons(OSPF6_LSTYPE_TYPE_7);
 | 
						|
		for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) {
 | 
						|
			zlog_debug("%s : lsa %s , id %pI4 , adv router %pI4",
 | 
						|
				   __func__, lsa->name, &lsa->header->id,
 | 
						|
				   &lsa->header->adv_router);
 | 
						|
			ospf6_abr_translate_nssa(oa, lsa);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s : Stop", __func__);
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_abr_send_nssa_aggregates(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct listnode *node;
 | 
						|
	struct ospf6_area *area;
 | 
						|
	struct ospf6_route *range;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: Start", __func__);
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
 | 
						|
		if (area->NSSATranslatorState == OSPF6_NSSA_TRANSLATE_DISABLED)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("%s: looking at area %pI4", __func__,
 | 
						|
				   &area->area_id);
 | 
						|
 | 
						|
		for (range = ospf6_route_head(area->nssa_range_table); range;
 | 
						|
		     range = ospf6_route_next(range))
 | 
						|
			ospf6_abr_range_update(range, ospf6);
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: Stop", __func__);
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_abr_remove_unapproved_translates(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
	uint16_t type;
 | 
						|
 | 
						|
	/* All AREA PROCESS should have APPROVED necessary LSAs */
 | 
						|
	/* Remove any left over and not APPROVED */
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: Start", __func__);
 | 
						|
 | 
						|
	type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
 | 
						|
	for (ALL_LSDB_TYPED(ospf6->lsdb, type, lsa)) {
 | 
						|
		if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT)
 | 
						|
		    && CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED)) {
 | 
						|
			zlog_debug(
 | 
						|
				"%s : removing unapproved translates, lsa : %s",
 | 
						|
				__func__, lsa->name);
 | 
						|
 | 
						|
			ospf6_lsa_premature_aging(lsa);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: Stop", __func__);
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_abr_nssa_type_7_default_create(struct ospf6 *ospf6,
 | 
						|
						 struct ospf6_area *oa)
 | 
						|
{
 | 
						|
	struct ospf6_route *def;
 | 
						|
	int metric;
 | 
						|
	int metric_type;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("Announcing Type-7 default route into NSSA area %s",
 | 
						|
			   oa->name);
 | 
						|
 | 
						|
	def = ospf6_route_create(ospf6);
 | 
						|
	def->type = OSPF6_DEST_TYPE_NETWORK;
 | 
						|
	def->prefix.family = AF_INET6;
 | 
						|
	def->prefix.prefixlen = 0;
 | 
						|
	memset(&def->prefix.u.prefix6, 0, sizeof(struct in6_addr));
 | 
						|
	def->type = OSPF6_DEST_TYPE_NETWORK;
 | 
						|
	def->path.subtype = OSPF6_PATH_SUBTYPE_DEFAULT_RT;
 | 
						|
	if (CHECK_FLAG(ospf6->flag, OSPF6_FLAG_ABR))
 | 
						|
		def->path.area_id = ospf6->backbone->area_id;
 | 
						|
	else
 | 
						|
		def->path.area_id = oa->area_id;
 | 
						|
 | 
						|
	/* Compute default route type and metric. */
 | 
						|
	if (oa->nssa_default_originate.metric_value != -1)
 | 
						|
		metric = oa->nssa_default_originate.metric_value;
 | 
						|
	else
 | 
						|
		metric = DEFAULT_DEFAULT_ALWAYS_METRIC;
 | 
						|
	if (oa->nssa_default_originate.metric_type != -1)
 | 
						|
		metric_type = oa->nssa_default_originate.metric_type;
 | 
						|
	else
 | 
						|
		metric_type = DEFAULT_METRIC_TYPE;
 | 
						|
	def->path.metric_type = metric_type;
 | 
						|
	def->path.cost = metric;
 | 
						|
	if (metric_type == 1)
 | 
						|
		def->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
 | 
						|
	else
 | 
						|
		def->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
 | 
						|
 | 
						|
	ospf6_nssa_lsa_originate(def, oa, false);
 | 
						|
	ospf6_route_delete(def);
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_abr_nssa_type_7_default_delete(struct ospf6 *ospf6,
 | 
						|
						 struct ospf6_area *oa)
 | 
						|
{
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
 | 
						|
	lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7), 0,
 | 
						|
				oa->ospf6->router_id, oa->lsdb);
 | 
						|
	if (lsa && !OSPF6_LSA_IS_MAXAGE(lsa)) {
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug(
 | 
						|
				"Withdrawing Type-7 default route from area %s",
 | 
						|
				oa->name);
 | 
						|
 | 
						|
		ospf6_lsa_purge(lsa);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* NSSA Type-7 default route. */
 | 
						|
void ospf6_abr_nssa_type_7_defaults(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct listnode *node;
 | 
						|
	struct ospf6_area *oa;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
 | 
						|
		if (IS_AREA_NSSA(oa) && oa->nssa_default_originate.enabled
 | 
						|
		    && (IS_OSPF6_ABR(ospf6)
 | 
						|
			|| (IS_OSPF6_ASBR(ospf6)
 | 
						|
			    && ospf6->nssa_default_import_check.status)))
 | 
						|
			ospf6_abr_nssa_type_7_default_create(ospf6, oa);
 | 
						|
		else
 | 
						|
			ospf6_abr_nssa_type_7_default_delete(ospf6, oa);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_abr_nssa_task(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("Check for NSSA-ABR Tasks():");
 | 
						|
 | 
						|
	if (!IS_OSPF6_ABR(ospf6)) {
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("%s  Not ABR", __func__);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!ospf6->anyNSSA) {
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("%s  Not NSSA", __func__);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Each area must confirm TranslatorRole */
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: Start", __func__);
 | 
						|
 | 
						|
	/* For all Global Entries flagged "local-translate", unset APPROVED */
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: unapprove translates", __func__);
 | 
						|
 | 
						|
	ospf6_abr_unapprove_translates(ospf6);
 | 
						|
 | 
						|
	/* Originate Type-7 aggregates */
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: send NSSA aggregates", __func__);
 | 
						|
	ospf6_abr_send_nssa_aggregates(ospf6);
 | 
						|
 | 
						|
	/* For all NSSAs, Type-7s, translate to 5's, INSTALL/FLOOD, or
 | 
						|
	 *  Aggregate as Type-7
 | 
						|
	 * Install or Approve in Type-5 Global LSDB
 | 
						|
	 */
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: process translates", __func__);
 | 
						|
	ospf6_abr_process_nssa_translates(ospf6);
 | 
						|
 | 
						|
	/* Flush any unapproved previous translates from Global Data Base */
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: remove unapproved translates", __func__);
 | 
						|
	ospf6_abr_remove_unapproved_translates(ospf6);
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: Stop", __func__);
 | 
						|
}
 | 
						|
 | 
						|
int ospf6_redistribute_check(struct ospf6 *ospf6, struct ospf6_route *route,
 | 
						|
			     int type)
 | 
						|
{
 | 
						|
	route_map_result_t ret;
 | 
						|
	struct prefix *prefix;
 | 
						|
	struct ospf6_redist *red;
 | 
						|
 | 
						|
	if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
 | 
						|
		return 0;
 | 
						|
 | 
						|
	prefix = &route->prefix;
 | 
						|
 | 
						|
	red = ospf6_redist_lookup(ospf6, type, 0);
 | 
						|
	if (!red)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	/* Change to new redist structure */
 | 
						|
	if (ROUTEMAP_NAME(red)) {
 | 
						|
		if (ROUTEMAP(red) == NULL)
 | 
						|
			ospf6_asbr_routemap_update(NULL);
 | 
						|
		if (ROUTEMAP(red) == NULL) {
 | 
						|
			zlog_warn(
 | 
						|
				"route-map \"%s\" not found, suppress redistributing",
 | 
						|
				ROUTEMAP_NAME(red));
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/*  Change to new redist structure */
 | 
						|
	if (ROUTEMAP(red)) {
 | 
						|
		ret = route_map_apply(ROUTEMAP(red), prefix, route);
 | 
						|
		if (ret == RMAP_DENYMATCH) {
 | 
						|
			if (IS_OSPF6_DEBUG_ASBR)
 | 
						|
				zlog_debug("Denied by route-map \"%s\"",
 | 
						|
					   ROUTEMAP_NAME(red));
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
/* This function performs ABR related processing */
 | 
						|
static void ospf6_abr_task_timer(struct event *thread)
 | 
						|
{
 | 
						|
	struct ospf6 *ospf6 = EVENT_ARG(thread);
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("Running ABR task on timer");
 | 
						|
 | 
						|
	(void)ospf6_check_and_set_router_abr(ospf6);
 | 
						|
	ospf6_abr_nssa_check_status(ospf6);
 | 
						|
	ospf6_abr_task(ospf6);
 | 
						|
	/* if nssa-abr, then scan Type-7 LSDB */
 | 
						|
	ospf6_abr_nssa_task(ospf6);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_schedule_abr_task(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	if (event_is_scheduled(ospf6->t_abr_task)) {
 | 
						|
		if (IS_OSPF6_DEBUG_ABR)
 | 
						|
			zlog_debug("ABR task already scheduled");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("Scheduling ABR task");
 | 
						|
 | 
						|
	event_add_timer(master, ospf6_abr_task_timer, ospf6,
 | 
						|
			OSPF6_ABR_TASK_DELAY, &ospf6->t_abr_task);
 | 
						|
}
 | 
						|
 | 
						|
/* Flush the NSSA LSAs from the area */
 | 
						|
static void ospf6_nssa_flush_area(struct ospf6_area *area)
 | 
						|
{
 | 
						|
	uint16_t type;
 | 
						|
	struct ospf6_lsa *lsa = NULL, *type5 = NULL;
 | 
						|
	struct ospf6 *ospf6 = area->ospf6;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s: area %s", __func__, area->name);
 | 
						|
 | 
						|
	/* Flush the NSSA LSA */
 | 
						|
	type = htons(OSPF6_LSTYPE_TYPE_7);
 | 
						|
	for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id, lsa)) {
 | 
						|
		lsa->header->age = htons(OSPF_LSA_MAXAGE);
 | 
						|
		SET_FLAG(lsa->flag, OSPF6_LSA_FLUSH);
 | 
						|
		ospf6_flood(NULL, lsa);
 | 
						|
 | 
						|
		/* Flush the translated LSA */
 | 
						|
		if (ospf6_check_and_set_router_abr(ospf6)) {
 | 
						|
			type5 = ospf6_lsdb_lookup(
 | 
						|
				htons(OSPF6_LSTYPE_AS_EXTERNAL),
 | 
						|
				lsa->external_lsa_id, ospf6->router_id,
 | 
						|
				ospf6->lsdb);
 | 
						|
			if (type5
 | 
						|
			    && CHECK_FLAG(type5->flag, OSPF6_LSA_LOCAL_XLT)) {
 | 
						|
				type5->header->age = htons(OSPF_LSA_MAXAGE);
 | 
						|
				SET_FLAG(type5->flag, OSPF6_LSA_FLUSH);
 | 
						|
				ospf6_flood(NULL, type5);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
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)) {
 | 
						|
		struct ospf6_external_info *info = route->route_option;
 | 
						|
 | 
						|
		/* This means the Type-5 LSA was originated for this route */
 | 
						|
		if (route->path.origin.id != 0 && info->type != DEFAULT_ROUTE)
 | 
						|
			ospf6_nssa_lsa_originate(route, area, true);
 | 
						|
	}
 | 
						|
 | 
						|
	/* 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, true);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_ase_lsa_refresh(struct ospf6 *o)
 | 
						|
{
 | 
						|
	struct ospf6_lsa *old;
 | 
						|
 | 
						|
	for (struct ospf6_route *route = ospf6_route_head(o->external_table);
 | 
						|
	     route; route = ospf6_route_next(route)) {
 | 
						|
		old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
 | 
						|
					route->path.origin.id, o->router_id,
 | 
						|
					o->lsdb);
 | 
						|
		if (old) {
 | 
						|
			EVENT_OFF(old->refresh);
 | 
						|
			event_add_event(master, ospf6_lsa_refresh, old, 0,
 | 
						|
					&old->refresh);
 | 
						|
		} else {
 | 
						|
			ospf6_as_external_lsa_originate(route, o);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_area_nssa_update(struct ospf6_area *area)
 | 
						|
{
 | 
						|
	if (IS_AREA_NSSA(area)) {
 | 
						|
		OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
 | 
						|
		area->ospf6->anyNSSA++;
 | 
						|
		OSPF6_OPT_SET(area->options, OSPF6_OPT_N);
 | 
						|
		area->NSSATranslatorRole = OSPF6_NSSA_ROLE_CANDIDATE;
 | 
						|
	} else if (IS_AREA_ENABLED(area)) {
 | 
						|
		if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
 | 
						|
			zlog_debug("Normal area for if %s", area->name);
 | 
						|
		OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_N);
 | 
						|
		OSPF6_OPT_SET(area->options, OSPF6_OPT_E);
 | 
						|
		area->ospf6->anyNSSA--;
 | 
						|
		area->NSSATranslatorState = OSPF6_NSSA_TRANSLATE_DISABLED;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Refresh router LSA */
 | 
						|
	if (IS_AREA_NSSA(area)) {
 | 
						|
		OSPF6_ROUTER_LSA_SCHEDULE(area);
 | 
						|
 | 
						|
		/* Flush external LSAs. */
 | 
						|
		ospf6_asbr_remove_externals_from_area(area);
 | 
						|
 | 
						|
		/* Check if router is ABR */
 | 
						|
		if (ospf6_check_and_set_router_abr(area->ospf6)) {
 | 
						|
			if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
				zlog_debug("Router is ABR area %s", area->name);
 | 
						|
			ospf6_schedule_abr_task(area->ospf6);
 | 
						|
		} else {
 | 
						|
			/* Router is not ABR */
 | 
						|
			if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
				zlog_debug("NSSA area %s", area->name);
 | 
						|
 | 
						|
			/* Originate NSSA LSA */
 | 
						|
			ospf6_check_and_originate_type7_lsa(area);
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		/* Disable NSSA */
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("Normal area %s", area->name);
 | 
						|
		ospf6_nssa_flush_area(area);
 | 
						|
 | 
						|
		/* Check if router is ABR */
 | 
						|
		if (ospf6_check_and_set_router_abr(area->ospf6)) {
 | 
						|
			if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
				zlog_debug("Router is ABR area %s", area->name);
 | 
						|
			ospf6_schedule_abr_task(area->ospf6);
 | 
						|
			ospf6_ase_lsa_refresh(area->ospf6);
 | 
						|
		} else {
 | 
						|
			uint16_t type;
 | 
						|
			struct ospf6_lsa *lsa = NULL;
 | 
						|
 | 
						|
			/*
 | 
						|
			 * Refresh all type-5 LSAs so they get installed
 | 
						|
			 * in the converted ares
 | 
						|
			 */
 | 
						|
			if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
				zlog_debug("Refresh type-5 LSAs, area %s",
 | 
						|
					   area->name);
 | 
						|
 | 
						|
			type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
 | 
						|
			for (ALL_LSDB_TYPED_ADVRTR(area->ospf6->lsdb, type,
 | 
						|
						   area->ospf6->router_id,
 | 
						|
						   lsa)) {
 | 
						|
				if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
					ospf6_lsa_header_print(lsa);
 | 
						|
				EVENT_OFF(lsa->refresh);
 | 
						|
				event_add_event(master, ospf6_lsa_refresh, lsa,
 | 
						|
						0, &lsa->refresh);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int ospf6_area_nssa_set(struct ospf6 *ospf6, struct ospf6_area *area)
 | 
						|
{
 | 
						|
 | 
						|
	if (!IS_AREA_NSSA(area)) {
 | 
						|
		/* Disable stub first. */
 | 
						|
		ospf6_area_stub_unset(ospf6, area);
 | 
						|
 | 
						|
		SET_FLAG(area->flag, OSPF6_AREA_NSSA);
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("area %s nssa set", area->name);
 | 
						|
		ospf6_area_nssa_update(area);
 | 
						|
	}
 | 
						|
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
int ospf6_area_nssa_unset(struct ospf6 *ospf6, struct ospf6_area *area)
 | 
						|
{
 | 
						|
	if (IS_AREA_NSSA(area)) {
 | 
						|
		UNSET_FLAG(area->flag, OSPF6_AREA_NSSA);
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("area %s nssa reset", area->name);
 | 
						|
 | 
						|
		/* Clear the table of NSSA ranges. */
 | 
						|
		ospf6_route_table_delete(area->nssa_range_table);
 | 
						|
		area->nssa_range_table =
 | 
						|
			OSPF6_ROUTE_TABLE_CREATE(AREA, PREFIX_RANGES);
 | 
						|
		area->nssa_range_table->scope = area;
 | 
						|
 | 
						|
		ospf6_area_nssa_update(area);
 | 
						|
	}
 | 
						|
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
/* Find the NSSA forwarding address */
 | 
						|
static struct in6_addr *ospf6_get_nssa_fwd_addr(struct ospf6_area *oa)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
 | 
						|
		struct in6_addr *addr;
 | 
						|
 | 
						|
		if (!if_is_operative(oi->interface))
 | 
						|
			continue;
 | 
						|
 | 
						|
		addr = ospf6_interface_get_global_address(oi->interface);
 | 
						|
		if (addr)
 | 
						|
			return addr;
 | 
						|
	}
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_nssa_lsa_originate(struct ospf6_route *route,
 | 
						|
			      struct ospf6_area *area, bool p_bit)
 | 
						|
{
 | 
						|
	char buffer[OSPF6_MAX_LSASIZE];
 | 
						|
	struct ospf6_lsa_header *lsa_header;
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
	struct ospf6_external_info *info = route->route_option;
 | 
						|
	struct in6_addr *fwd_addr;
 | 
						|
 | 
						|
	struct ospf6_as_external_lsa *as_external_lsa;
 | 
						|
	caddr_t p;
 | 
						|
 | 
						|
	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));
 | 
						|
	lsa_header = (struct ospf6_lsa_header *)buffer;
 | 
						|
	as_external_lsa = (struct ospf6_as_external_lsa
 | 
						|
				   *)((caddr_t)lsa_header
 | 
						|
				      + sizeof(struct ospf6_lsa_header));
 | 
						|
	p = (caddr_t)((caddr_t)as_external_lsa
 | 
						|
		      + sizeof(struct ospf6_as_external_lsa));
 | 
						|
 | 
						|
	/* Fill AS-External-LSA */
 | 
						|
	/* Metric type */
 | 
						|
	if (route->path.metric_type == 2)
 | 
						|
		SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
 | 
						|
	else
 | 
						|
		UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
 | 
						|
 | 
						|
	/* external route tag */
 | 
						|
	if (info && info->tag)
 | 
						|
		SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
 | 
						|
	else
 | 
						|
		UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
 | 
						|
 | 
						|
	/* Set metric */
 | 
						|
	OSPF6_ASBR_METRIC_SET(as_external_lsa, route->path.cost);
 | 
						|
 | 
						|
	/* prefixlen */
 | 
						|
	as_external_lsa->prefix.prefix_length = route->prefix.prefixlen;
 | 
						|
 | 
						|
	/* PrefixOptions */
 | 
						|
	as_external_lsa->prefix.prefix_options = route->prefix_options;
 | 
						|
 | 
						|
	/* Set the P bit */
 | 
						|
	if (p_bit)
 | 
						|
		as_external_lsa->prefix.prefix_options |= OSPF6_PREFIX_OPTION_P;
 | 
						|
 | 
						|
	/* don't use refer LS-type */
 | 
						|
	as_external_lsa->prefix.prefix_refer_lstype = htons(0);
 | 
						|
 | 
						|
	/* set Prefix */
 | 
						|
	memcpy(p, &route->prefix.u.prefix6,
 | 
						|
	       OSPF6_PREFIX_SPACE(route->prefix.prefixlen));
 | 
						|
	ospf6_prefix_apply_mask(&as_external_lsa->prefix);
 | 
						|
	p += OSPF6_PREFIX_SPACE(route->prefix.prefixlen);
 | 
						|
 | 
						|
	/* Forwarding address */
 | 
						|
	fwd_addr = ospf6_get_nssa_fwd_addr(area);
 | 
						|
	if (fwd_addr) {
 | 
						|
		memcpy(p, fwd_addr, sizeof(struct in6_addr));
 | 
						|
		p += sizeof(struct in6_addr);
 | 
						|
		SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
 | 
						|
	} else
 | 
						|
		UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
 | 
						|
 | 
						|
	/* External Route Tag */
 | 
						|
	if (info
 | 
						|
	    && CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) {
 | 
						|
		route_tag_t network_order = htonl(info->tag);
 | 
						|
 | 
						|
		memcpy(p, &network_order, sizeof(network_order));
 | 
						|
		p += sizeof(network_order);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Fill LSA Header */
 | 
						|
	lsa_header->age = 0;
 | 
						|
	lsa_header->type = htons(OSPF6_LSTYPE_TYPE_7);
 | 
						|
	lsa_header->id = route->path.origin.id;
 | 
						|
	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->lsdb);
 | 
						|
	lsa_header->length = htons((caddr_t)p - (caddr_t)lsa_header);
 | 
						|
 | 
						|
	/* LSA checksum */
 | 
						|
	ospf6_lsa_checksum(lsa_header);
 | 
						|
	/* create LSA */
 | 
						|
	lsa = ospf6_lsa_create(lsa_header);
 | 
						|
 | 
						|
	/* Originate */
 | 
						|
	ospf6_lsa_originate_area(lsa, area);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_abr_check_translate_nssa(struct ospf6_area *area,
 | 
						|
				    struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	struct ospf6_lsa *type5 = NULL;
 | 
						|
	struct ospf6 *ospf6 = area->ospf6;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		zlog_debug("%s : start", __func__);
 | 
						|
 | 
						|
	if (!ospf6_check_and_set_router_abr(ospf6))
 | 
						|
		return;
 | 
						|
 | 
						|
	type5 = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
 | 
						|
				  lsa->external_lsa_id, ospf6->router_id,
 | 
						|
				  ospf6->lsdb);
 | 
						|
	if (!type5) {
 | 
						|
		if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
			zlog_debug("%s : Originating type5 LSA", __func__);
 | 
						|
		ospf6_lsa_translated_nssa_new(area, lsa);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
DEFPY (area_nssa_range,
 | 
						|
       area_nssa_range_cmd,
 | 
						|
       "area <A.B.C.D|(0-4294967295)>$area nssa range X:X::X:X/M$prefix [<not-advertise$not_adv|cost (0-16777215)$cost>]",
 | 
						|
       "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"
 | 
						|
       "Configured address range\n"
 | 
						|
       "Specify IPv6 prefix\n"
 | 
						|
       "Do not advertise\n"
 | 
						|
       "User specified metric for this range\n"
 | 
						|
       "Advertised metric for this range\n")
 | 
						|
{
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	struct ospf6_route *range;
 | 
						|
 | 
						|
	VTY_DECLVAR_CONTEXT(ospf6, ospf6);
 | 
						|
 | 
						|
	OSPF6_CMD_AREA_GET(area, oa, ospf6);
 | 
						|
 | 
						|
	if (!IS_AREA_NSSA(oa)) {
 | 
						|
		vty_out(vty, "%% First configure %s as an NSSA area\n", area);
 | 
						|
		return CMD_WARNING;
 | 
						|
	}
 | 
						|
 | 
						|
	range = ospf6_route_lookup((struct prefix *)prefix,
 | 
						|
				   oa->nssa_range_table);
 | 
						|
	if (range == NULL) {
 | 
						|
		range = ospf6_route_create(ospf6);
 | 
						|
		range->type = OSPF6_DEST_TYPE_RANGE;
 | 
						|
		SET_FLAG(range->flag, OSPF6_ROUTE_NSSA_RANGE);
 | 
						|
		prefix_copy(&range->prefix, prefix);
 | 
						|
		range->path.area_id = oa->area_id;
 | 
						|
		range->path.metric_type = 2;
 | 
						|
		range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC;
 | 
						|
		range->path.origin.type = htons(OSPF6_LSTYPE_TYPE_7);
 | 
						|
		range->path.origin.id = htonl(ospf6->external_id++);
 | 
						|
		range->path.origin.adv_router = ospf6->router_id;
 | 
						|
		ospf6_route_add(range, oa->nssa_range_table);
 | 
						|
	}
 | 
						|
 | 
						|
	/* process "not-advertise" */
 | 
						|
	if (not_adv)
 | 
						|
		SET_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
 | 
						|
	else
 | 
						|
		UNSET_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE);
 | 
						|
 | 
						|
	/* process "cost" */
 | 
						|
	if (!cost_str)
 | 
						|
		cost = OSPF_AREA_RANGE_COST_UNSPEC;
 | 
						|
	range->path.u.cost_config = cost;
 | 
						|
 | 
						|
	/* Redo summaries if required */
 | 
						|
	if (ospf6_check_and_set_router_abr(ospf6))
 | 
						|
		ospf6_schedule_abr_task(ospf6);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
DEFPY (no_area_nssa_range,
 | 
						|
       no_area_nssa_range_cmd,
 | 
						|
       "no area <A.B.C.D|(0-4294967295)>$area nssa range X:X::X:X/M$prefix [<not-advertise|cost (0-16777215)>]",
 | 
						|
       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"
 | 
						|
       "Configured address range\n"
 | 
						|
       "Specify IPv6 prefix\n"
 | 
						|
       "Do not advertise\n"
 | 
						|
       "User specified metric for this range\n"
 | 
						|
       "Advertised metric for this range\n")
 | 
						|
{
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	struct ospf6_route *range;
 | 
						|
 | 
						|
	VTY_DECLVAR_CONTEXT(ospf6, ospf6);
 | 
						|
 | 
						|
	OSPF6_CMD_AREA_GET(area, oa, ospf6);
 | 
						|
 | 
						|
	range = ospf6_route_lookup((struct prefix *)prefix,
 | 
						|
				   oa->nssa_range_table);
 | 
						|
	if (range == NULL) {
 | 
						|
		vty_out(vty, "%% range %s does not exist.\n", prefix_str);
 | 
						|
		return CMD_SUCCESS;
 | 
						|
	}
 | 
						|
 | 
						|
	if (ospf6_check_and_set_router_abr(oa->ospf6)) {
 | 
						|
		/* Blow away the aggregated LSA and route */
 | 
						|
		SET_FLAG(range->flag, OSPF6_ROUTE_REMOVE);
 | 
						|
 | 
						|
		/* Redo summaries if required */
 | 
						|
		event_execute(master, ospf6_abr_task_timer, ospf6, 0, NULL);
 | 
						|
	}
 | 
						|
 | 
						|
	ospf6_route_remove(range, oa->nssa_range_table);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
DEFUN(debug_ospf6_nssa, debug_ospf6_nssa_cmd,
 | 
						|
      "debug ospf6 nssa",
 | 
						|
      DEBUG_STR
 | 
						|
      OSPF6_STR
 | 
						|
      "Debug OSPFv3 NSSA function\n")
 | 
						|
{
 | 
						|
	OSPF6_DEBUG_NSSA_ON();
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
DEFUN(no_debug_ospf6_nssa, no_debug_ospf6_nssa_cmd,
 | 
						|
      "no debug ospf6 nssa",
 | 
						|
      NO_STR
 | 
						|
      DEBUG_STR
 | 
						|
      OSPF6_STR
 | 
						|
      "Debug OSPFv3 NSSA function\n")
 | 
						|
{
 | 
						|
	OSPF6_DEBUG_NSSA_OFF();
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
void config_write_ospf6_debug_nssa(struct vty *vty)
 | 
						|
{
 | 
						|
	if (IS_OSPF6_DEBUG_NSSA)
 | 
						|
		vty_out(vty, "debug ospf6 nssa\n");
 | 
						|
}
 | 
						|
 | 
						|
void install_element_ospf6_debug_nssa(void)
 | 
						|
{
 | 
						|
	install_element(OSPF6_NODE, &area_nssa_range_cmd);
 | 
						|
	install_element(OSPF6_NODE, &no_area_nssa_range_cmd);
 | 
						|
 | 
						|
	install_element(ENABLE_NODE, &debug_ospf6_nssa_cmd);
 | 
						|
	install_element(ENABLE_NODE, &no_debug_ospf6_nssa_cmd);
 | 
						|
	install_element(CONFIG_NODE, &debug_ospf6_nssa_cmd);
 | 
						|
	install_element(CONFIG_NODE, &no_debug_ospf6_nssa_cmd);
 | 
						|
}
 |