mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 01:43:38 +00:00 
			
		
		
		
	The ospf6_route_cmp_nexthops function was returning 0 for same and 1 for not same. Let's reverse the polarity and actually make the returns useful long term. Signed-off-by: Donald Sharp <sharpd@nvidia.com>
		
			
				
	
	
		
			1602 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1602 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Area Border Router function.
 | 
						|
 * Copyright (C) 2004 Yasuhiro Ohara
 | 
						|
 *
 | 
						|
 * This file is part of GNU Zebra.
 | 
						|
 *
 | 
						|
 * GNU Zebra is free software; you can redistribute it and/or modify it
 | 
						|
 * under the terms of the GNU General Public License as published by the
 | 
						|
 * Free Software Foundation; either version 2, or (at your option) any
 | 
						|
 * later version.
 | 
						|
 *
 | 
						|
 * GNU Zebra is distributed in the hope that it will be useful, but
 | 
						|
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
 * General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License along
 | 
						|
 * with this program; see the file COPYING; if not, write to the Free Software
 | 
						|
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 | 
						|
 */
 | 
						|
 | 
						|
#include <zebra.h>
 | 
						|
 | 
						|
#include "log.h"
 | 
						|
#include "prefix.h"
 | 
						|
#include "table.h"
 | 
						|
#include "vty.h"
 | 
						|
#include "linklist.h"
 | 
						|
#include "command.h"
 | 
						|
#include "thread.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_asbr.h"
 | 
						|
#include "ospf6_abr.h"
 | 
						|
#include "ospf6d.h"
 | 
						|
#include "ospf6_nssa.h"
 | 
						|
 | 
						|
unsigned char conf_debug_ospf6_abr;
 | 
						|
 | 
						|
int ospf6_ls_origin_same(struct ospf6_path *o_path, struct ospf6_path *r_path)
 | 
						|
{
 | 
						|
	if (((o_path->origin.type == r_path->origin.type)
 | 
						|
	     && (o_path->origin.id == r_path->origin.id)
 | 
						|
	     && (o_path->origin.adv_router == r_path->origin.adv_router)))
 | 
						|
		return 1;
 | 
						|
	else
 | 
						|
		return 0;
 | 
						|
}
 | 
						|
 | 
						|
bool ospf6_check_and_set_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)) {
 | 
						|
		if (IS_OSPF6_DEBUG_ABR)
 | 
						|
			zlog_debug("%s, area_id %pI4", __func__, &oa->area_id);
 | 
						|
		if (IS_AREA_ENABLED(oa))
 | 
						|
			area_count++;
 | 
						|
 | 
						|
		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 true;
 | 
						|
	} else {
 | 
						|
		if (IS_OSPF6_DEBUG_ABR)
 | 
						|
			zlog_debug("%s : reset flag OSPF6_FLAG_ABR", __func__);
 | 
						|
		UNSET_FLAG(o->flag, OSPF6_FLAG_ABR);
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route *route,
 | 
						|
					     struct ospf6_area *area)
 | 
						|
{
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
 | 
						|
	oi = ospf6_interface_lookup_by_ifindex(
 | 
						|
		ospf6_route_get_first_nh_index(route), area->ospf6->vrf_id);
 | 
						|
	if (oi && oi->area && oi->area == area)
 | 
						|
		return 1;
 | 
						|
	else
 | 
						|
		return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_abr_delete_route(struct ospf6_route *summary,
 | 
						|
				   struct ospf6_route_table *summary_table,
 | 
						|
				   struct ospf6_lsa *old)
 | 
						|
{
 | 
						|
	if (summary) {
 | 
						|
		ospf6_route_remove(summary, summary_table);
 | 
						|
	}
 | 
						|
 | 
						|
	if (old && !OSPF6_LSA_IS_MAXAGE(old))
 | 
						|
		ospf6_lsa_purge(old);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_abr_enable_area(struct ospf6_area *area)
 | 
						|
{
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(area->ospf6->area_list, node, nnode, oa))
 | 
						|
		/* update B bit for each area */
 | 
						|
		OSPF6_ROUTER_LSA_SCHEDULE(oa);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_abr_disable_area(struct ospf6_area *area)
 | 
						|
{
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	struct ospf6_route *ro, *nro;
 | 
						|
	struct ospf6_lsa *old;
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
 | 
						|
	/* Withdraw all summary prefixes previously originated */
 | 
						|
	for (ro = ospf6_route_head(area->summary_prefix); ro; ro = nro) {
 | 
						|
		nro = ospf6_route_next(ro);
 | 
						|
		old = ospf6_lsdb_lookup(ro->path.origin.type,
 | 
						|
					ro->path.origin.id,
 | 
						|
					area->ospf6->router_id, area->lsdb);
 | 
						|
		if (old)
 | 
						|
			ospf6_lsa_purge(old);
 | 
						|
		ospf6_route_remove(ro, area->summary_prefix);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Withdraw all summary router-routes previously originated */
 | 
						|
	for (ro = ospf6_route_head(area->summary_router); ro; ro = nro) {
 | 
						|
		nro = ospf6_route_next(ro);
 | 
						|
		old = ospf6_lsdb_lookup(ro->path.origin.type,
 | 
						|
					ro->path.origin.id,
 | 
						|
					area->ospf6->router_id, area->lsdb);
 | 
						|
		if (old)
 | 
						|
			ospf6_lsa_purge(old);
 | 
						|
		ospf6_route_remove(ro, area->summary_router);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Schedule Router-LSA for each area (ABR status may change) */
 | 
						|
	for (ALL_LIST_ELEMENTS(area->ospf6->area_list, node, nnode, oa))
 | 
						|
		/* update B bit for each area */
 | 
						|
		OSPF6_ROUTER_LSA_SCHEDULE(oa);
 | 
						|
}
 | 
						|
 | 
						|
/* RFC 2328 12.4.3. Summary-LSAs */
 | 
						|
/* Returns 1 if a summary LSA has been generated for the area */
 | 
						|
/* This is used by the area/range logic to add/remove blackhole routes */
 | 
						|
int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
 | 
						|
					struct ospf6_area *area)
 | 
						|
{
 | 
						|
	struct ospf6_lsa *lsa, *old = NULL;
 | 
						|
	struct ospf6_route *summary, *range = NULL;
 | 
						|
	struct ospf6_area *route_area;
 | 
						|
	char buffer[OSPF6_MAX_LSASIZE];
 | 
						|
	struct ospf6_lsa_header *lsa_header;
 | 
						|
	caddr_t p;
 | 
						|
	struct ospf6_inter_prefix_lsa *prefix_lsa;
 | 
						|
	struct ospf6_inter_router_lsa *router_lsa;
 | 
						|
	struct ospf6_route_table *summary_table = NULL;
 | 
						|
	uint16_t type;
 | 
						|
	int is_debug = 0;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR) {
 | 
						|
		char buf[BUFSIZ];
 | 
						|
 | 
						|
		if (route->type == OSPF6_DEST_TYPE_ROUTER)
 | 
						|
			inet_ntop(AF_INET,
 | 
						|
				  &ADV_ROUTER_IN_PREFIX(&route->prefix), buf,
 | 
						|
				  sizeof(buf));
 | 
						|
		else
 | 
						|
			prefix2str(&route->prefix, buf, sizeof(buf));
 | 
						|
 | 
						|
		zlog_debug("%s : start area %s, route %s", __func__, area->name,
 | 
						|
			   buf);
 | 
						|
	}
 | 
						|
 | 
						|
	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;
 | 
						|
	}
 | 
						|
 | 
						|
	if (route->type == OSPF6_DEST_TYPE_NETWORK) {
 | 
						|
		bool filter = false;
 | 
						|
 | 
						|
		route_area =
 | 
						|
			ospf6_area_lookup(route->path.area_id, area->ospf6);
 | 
						|
		assert(route_area);
 | 
						|
 | 
						|
		/* Check export-list */
 | 
						|
		if (EXPORT_LIST(route_area)
 | 
						|
		    && access_list_apply(EXPORT_LIST(route_area),
 | 
						|
					 &route->prefix)
 | 
						|
			       == FILTER_DENY) {
 | 
						|
			if (IS_OSPF6_DEBUG_ABR)
 | 
						|
				zlog_debug(
 | 
						|
					"%s: prefix %pFX was denied by export-list",
 | 
						|
					__func__, &route->prefix);
 | 
						|
			filter = true;
 | 
						|
		}
 | 
						|
 | 
						|
		/* Check output prefix-list */
 | 
						|
		if (PREFIX_LIST_OUT(route_area)
 | 
						|
		    && prefix_list_apply(PREFIX_LIST_OUT(route_area),
 | 
						|
					 &route->prefix)
 | 
						|
			       != PREFIX_PERMIT) {
 | 
						|
			if (IS_OSPF6_DEBUG_ABR)
 | 
						|
				zlog_debug(
 | 
						|
					"%s: prefix %pFX was denied by prefix-list out",
 | 
						|
					__func__, &route->prefix);
 | 
						|
			filter = true;
 | 
						|
		}
 | 
						|
 | 
						|
		/* Check import-list */
 | 
						|
		if (IMPORT_LIST(area)
 | 
						|
		    && access_list_apply(IMPORT_LIST(area), &route->prefix)
 | 
						|
			       == FILTER_DENY) {
 | 
						|
			if (IS_OSPF6_DEBUG_ABR)
 | 
						|
				zlog_debug(
 | 
						|
					"%s: prefix %pFX was denied by import-list",
 | 
						|
					__func__, &route->prefix);
 | 
						|
			filter = true;
 | 
						|
		}
 | 
						|
 | 
						|
		/* Check input prefix-list */
 | 
						|
		if (PREFIX_LIST_IN(area)
 | 
						|
		    && prefix_list_apply(PREFIX_LIST_IN(area), &route->prefix)
 | 
						|
			       != PREFIX_PERMIT) {
 | 
						|
			if (IS_OSPF6_DEBUG_ABR)
 | 
						|
				zlog_debug(
 | 
						|
					"%s: prefix %pFX was denied by prefix-list in",
 | 
						|
					__func__, &route->prefix);
 | 
						|
			filter = true;
 | 
						|
		}
 | 
						|
 | 
						|
		if (filter) {
 | 
						|
			if (summary) {
 | 
						|
				ospf6_route_remove(summary, summary_table);
 | 
						|
				if (old)
 | 
						|
					ospf6_lsa_purge(old);
 | 
						|
			}
 | 
						|
			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) {
 | 
						|
			if (IS_OSPF6_DEBUG_ABR)
 | 
						|
				zlog_debug(
 | 
						|
					"%s: Skipping ASBR announcement for ABR (%pI4)",
 | 
						|
					__func__,
 | 
						|
					&ADV_ROUTER_IN_PREFIX(&route->prefix));
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (route->type == OSPF6_DEST_TYPE_ROUTER) {
 | 
						|
		if (IS_OSPF6_DEBUG_ABR
 | 
						|
		    || IS_OSPF6_DEBUG_ORIGINATE(INTER_ROUTER)) {
 | 
						|
			is_debug++;
 | 
						|
			if (IS_OSPF6_DEBUG_ABR)
 | 
						|
				zlog_debug(
 | 
						|
					"Originating summary in area %s for ASBR %pI4",
 | 
						|
					area->name,
 | 
						|
					&ADV_ROUTER_IN_PREFIX(&route->prefix));
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		if (IS_OSPF6_DEBUG_ABR
 | 
						|
		    || IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX))
 | 
						|
			is_debug++;
 | 
						|
 | 
						|
		if (route->type == OSPF6_DEST_TYPE_NETWORK &&
 | 
						|
		    route->path.origin.type ==
 | 
						|
		    htons(OSPF6_LSTYPE_INTER_PREFIX)) {
 | 
						|
			if (!CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST)) {
 | 
						|
				if (is_debug)
 | 
						|
					zlog_debug(
 | 
						|
						"%s: route %pFX with cost %u is not best, ignore.",
 | 
						|
						__func__, &route->prefix,
 | 
						|
						route->path.cost);
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (route->path.origin.type ==
 | 
						|
		    htons(OSPF6_LSTYPE_INTRA_PREFIX)) {
 | 
						|
			if (!CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST)) {
 | 
						|
				if (is_debug)
 | 
						|
					zlog_debug(
 | 
						|
						"%s: intra-prefix route %pFX with cost %u is not best, ignore.",
 | 
						|
						__func__, &route->prefix,
 | 
						|
						route->path.cost);
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"Originating summary in area %s for %pFX cost %u",
 | 
						|
				area->name, &route->prefix, route->path.cost);
 | 
						|
	}
 | 
						|
 | 
						|
	/* if this route has just removed, remove corresponding LSA */
 | 
						|
	if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"The route has just removed, purge previous LSA");
 | 
						|
 | 
						|
		if (route->type == OSPF6_DEST_TYPE_RANGE) {
 | 
						|
			/* Whether the route have active longer prefix */
 | 
						|
			if (!CHECK_FLAG(route->flag,
 | 
						|
					OSPF6_ROUTE_ACTIVE_SUMMARY)) {
 | 
						|
				if (is_debug)
 | 
						|
					zlog_debug(
 | 
						|
						"The range is not active. withdraw");
 | 
						|
 | 
						|
				ospf6_abr_delete_route(summary, summary_table,
 | 
						|
						       old);
 | 
						|
			}
 | 
						|
		} else if (old) {
 | 
						|
			ospf6_route_remove(summary, summary_table);
 | 
						|
			ospf6_lsa_purge(old);
 | 
						|
		}
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if ((route->type == OSPF6_DEST_TYPE_ROUTER)
 | 
						|
	    && (IS_AREA_STUB(area) || IS_AREA_NSSA(area))) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"Area has been stubbed, purge Inter-Router LSA");
 | 
						|
 | 
						|
		ospf6_abr_delete_route(summary, summary_table, old);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if (area->no_summary
 | 
						|
	    && (route->path.subtype != OSPF6_PATH_SUBTYPE_DEFAULT_RT)) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug("Area has been stubbed, purge prefix LSA");
 | 
						|
 | 
						|
		ospf6_abr_delete_route(summary, summary_table, old);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* do not generate if the route cost is greater or equal to LSInfinity
 | 
						|
	 */
 | 
						|
	if (route->path.cost >= OSPF_LS_INFINITY) {
 | 
						|
		/* When we're clearing the range route because all active
 | 
						|
		 * prefixes
 | 
						|
		 * under the range are gone, we set the range's cost to
 | 
						|
		 * OSPF_AREA_RANGE_COST_UNSPEC, which is > OSPF_LS_INFINITY. We
 | 
						|
		 * don't want to trigger the code here for that. This code is
 | 
						|
		 * for
 | 
						|
		 * handling routes that have gone to infinity. The range removal
 | 
						|
		 * happens
 | 
						|
		 * elsewhere.
 | 
						|
		 */
 | 
						|
		if ((route->type != OSPF6_DEST_TYPE_RANGE)
 | 
						|
		    && (route->path.cost != OSPF_AREA_RANGE_COST_UNSPEC)) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"The cost exceeds LSInfinity, withdraw");
 | 
						|
			if (old)
 | 
						|
				ospf6_lsa_purge(old);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* if this is a route to ASBR */
 | 
						|
	if (route->type == OSPF6_DEST_TYPE_ROUTER) {
 | 
						|
		/* Only the preferred best path is considered */
 | 
						|
		if (!CHECK_FLAG(route->flag, OSPF6_ROUTE_BEST)) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"This is the secondary path to the ASBR, ignore");
 | 
						|
			ospf6_abr_delete_route(summary, summary_table, old);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
 | 
						|
		/* Do not generate if area is NSSA */
 | 
						|
		route_area =
 | 
						|
			ospf6_area_lookup(route->path.area_id, area->ospf6);
 | 
						|
		assert(route_area);
 | 
						|
 | 
						|
		if (IS_AREA_NSSA(route_area)) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"%s: The route comes from NSSA area, skip",
 | 
						|
					__func__);
 | 
						|
			ospf6_abr_delete_route(summary, summary_table, old);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
 | 
						|
		/* Do not generate if the area is stub */
 | 
						|
		/* XXX */
 | 
						|
	}
 | 
						|
 | 
						|
	/* if this is an intra-area route, this may be suppressed by aggregation
 | 
						|
	 */
 | 
						|
	if (route->type == OSPF6_DEST_TYPE_NETWORK
 | 
						|
	    && route->path.type == OSPF6_PATH_TYPE_INTRA) {
 | 
						|
		/* search for configured address range for the route's area */
 | 
						|
		route_area =
 | 
						|
			ospf6_area_lookup(route->path.area_id, area->ospf6);
 | 
						|
		assert(route_area);
 | 
						|
		range = ospf6_route_lookup_bestmatch(&route->prefix,
 | 
						|
						     route_area->range_table);
 | 
						|
 | 
						|
		/* ranges are ignored when originate backbone routes to transit
 | 
						|
		   area.
 | 
						|
		   Otherwise, if ranges are configured, the route is suppressed.
 | 
						|
		   */
 | 
						|
		if (range && !CHECK_FLAG(range->flag, OSPF6_ROUTE_REMOVE)
 | 
						|
		    && (route->path.area_id != OSPF_AREA_BACKBONE
 | 
						|
			|| !IS_AREA_TRANSIT(area))) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"Suppressed by range %pFX of area %s",
 | 
						|
					&range->prefix, route_area->name);
 | 
						|
			/* The existing summary route could be a range, don't
 | 
						|
			 * remove it in this case
 | 
						|
			 */
 | 
						|
			if (summary && summary->type != OSPF6_DEST_TYPE_RANGE)
 | 
						|
				ospf6_abr_delete_route(summary, summary_table,
 | 
						|
						       old);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* If this is a configured address range */
 | 
						|
	if (route->type == OSPF6_DEST_TYPE_RANGE) {
 | 
						|
		/* If DoNotAdvertise is set */
 | 
						|
		if (CHECK_FLAG(route->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"This is the range with DoNotAdvertise set. ignore");
 | 
						|
			ospf6_abr_delete_route(summary, summary_table, old);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
 | 
						|
		/* If there are no active prefixes in this range, remove */
 | 
						|
		if (!CHECK_FLAG(route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug("The range is not active. withdraw");
 | 
						|
			ospf6_abr_delete_route(summary, summary_table, old);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* the route is going to be originated. store it in area's summary_table
 | 
						|
	 */
 | 
						|
	if (summary == NULL) {
 | 
						|
		summary = ospf6_route_copy(route);
 | 
						|
		summary->path.origin.adv_router = area->ospf6->router_id;
 | 
						|
 | 
						|
		if (route->type == OSPF6_DEST_TYPE_ROUTER) {
 | 
						|
			summary->path.origin.type =
 | 
						|
				htons(OSPF6_LSTYPE_INTER_ROUTER);
 | 
						|
			summary->path.origin.id =
 | 
						|
				ADV_ROUTER_IN_PREFIX(&route->prefix);
 | 
						|
		} else {
 | 
						|
			summary->path.origin.type =
 | 
						|
				htons(OSPF6_LSTYPE_INTER_PREFIX);
 | 
						|
			summary->path.origin.id = ospf6_new_ls_id(
 | 
						|
				summary->path.origin.type,
 | 
						|
				summary->path.origin.adv_router, area->lsdb);
 | 
						|
		}
 | 
						|
		summary = ospf6_route_add(summary, summary_table);
 | 
						|
	} else {
 | 
						|
		summary->type = route->type;
 | 
						|
		monotime(&summary->changed);
 | 
						|
	}
 | 
						|
 | 
						|
	summary->prefix_options = route->prefix_options;
 | 
						|
	summary->path.router_bits = route->path.router_bits;
 | 
						|
	summary->path.options[0] = route->path.options[0];
 | 
						|
	summary->path.options[1] = route->path.options[1];
 | 
						|
	summary->path.options[2] = route->path.options[2];
 | 
						|
	summary->path.area_id = area->area_id;
 | 
						|
	summary->path.type = OSPF6_PATH_TYPE_INTER;
 | 
						|
	summary->path.subtype = route->path.subtype;
 | 
						|
	summary->path.cost = route->path.cost;
 | 
						|
	/* summary->nexthop[0] = route->nexthop[0]; */
 | 
						|
 | 
						|
	/* prepare buffer */
 | 
						|
	memset(buffer, 0, sizeof(buffer));
 | 
						|
	lsa_header = (struct ospf6_lsa_header *)buffer;
 | 
						|
 | 
						|
	if (route->type == OSPF6_DEST_TYPE_ROUTER) {
 | 
						|
		router_lsa = (struct ospf6_inter_router_lsa
 | 
						|
				      *)((caddr_t)lsa_header
 | 
						|
					 + sizeof(struct ospf6_lsa_header));
 | 
						|
		p = (caddr_t)router_lsa + sizeof(struct ospf6_inter_router_lsa);
 | 
						|
 | 
						|
		/* Fill Inter-Area-Router-LSA */
 | 
						|
		router_lsa->options[0] = route->path.options[0];
 | 
						|
		router_lsa->options[1] = route->path.options[1];
 | 
						|
		router_lsa->options[2] = route->path.options[2];
 | 
						|
		OSPF6_ABR_SUMMARY_METRIC_SET(router_lsa, route->path.cost);
 | 
						|
		router_lsa->router_id = ADV_ROUTER_IN_PREFIX(&route->prefix);
 | 
						|
		type = htons(OSPF6_LSTYPE_INTER_ROUTER);
 | 
						|
	} else {
 | 
						|
		prefix_lsa = (struct ospf6_inter_prefix_lsa
 | 
						|
				      *)((caddr_t)lsa_header
 | 
						|
					 + sizeof(struct ospf6_lsa_header));
 | 
						|
		p = (caddr_t)prefix_lsa + sizeof(struct ospf6_inter_prefix_lsa);
 | 
						|
 | 
						|
		/* Fill Inter-Area-Prefix-LSA */
 | 
						|
		OSPF6_ABR_SUMMARY_METRIC_SET(prefix_lsa, route->path.cost);
 | 
						|
		prefix_lsa->prefix.prefix_length = route->prefix.prefixlen;
 | 
						|
		prefix_lsa->prefix.prefix_options = route->prefix_options;
 | 
						|
 | 
						|
		/* set Prefix */
 | 
						|
		memcpy(p, &route->prefix.u.prefix6,
 | 
						|
		       OSPF6_PREFIX_SPACE(route->prefix.prefixlen));
 | 
						|
		ospf6_prefix_apply_mask(&prefix_lsa->prefix);
 | 
						|
		p += OSPF6_PREFIX_SPACE(route->prefix.prefixlen);
 | 
						|
		type = htons(OSPF6_LSTYPE_INTER_PREFIX);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Fill LSA Header */
 | 
						|
	lsa_header->age = 0;
 | 
						|
	lsa_header->type = type;
 | 
						|
	lsa_header->id = summary->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);
 | 
						|
 | 
						|
	/* 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;
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_abr_range_reset_cost(struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	struct ospf6_route *range;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) {
 | 
						|
		for (range = ospf6_route_head(oa->range_table); range;
 | 
						|
		     range = ospf6_route_next(range))
 | 
						|
			OSPF6_ABR_RANGE_CLEAR_COST(range);
 | 
						|
		for (range = ospf6_route_head(oa->nssa_range_table); range;
 | 
						|
		     range = ospf6_route_next(range))
 | 
						|
			OSPF6_ABR_RANGE_CLEAR_COST(range);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static inline uint32_t ospf6_abr_range_compute_cost(struct ospf6_route *range,
 | 
						|
						    struct ospf6 *o)
 | 
						|
{
 | 
						|
	struct ospf6_route *ro;
 | 
						|
	uint32_t cost = 0;
 | 
						|
 | 
						|
	for (ro = ospf6_route_match_head(&range->prefix, o->route_table); ro;
 | 
						|
	     ro = ospf6_route_match_next(&range->prefix, ro)) {
 | 
						|
		if (CHECK_FLAG(ro->flag, OSPF6_ROUTE_REMOVE))
 | 
						|
			continue;
 | 
						|
		if (ro->path.area_id != range->path.area_id)
 | 
						|
			continue;
 | 
						|
		if (CHECK_FLAG(range->flag, OSPF6_ROUTE_NSSA_RANGE)
 | 
						|
		    && ro->path.type != OSPF6_PATH_TYPE_EXTERNAL1
 | 
						|
		    && ro->path.type != OSPF6_PATH_TYPE_EXTERNAL2)
 | 
						|
			continue;
 | 
						|
		if (!CHECK_FLAG(range->flag, OSPF6_ROUTE_NSSA_RANGE)
 | 
						|
		    && ro->path.type != OSPF6_PATH_TYPE_INTRA)
 | 
						|
			continue;
 | 
						|
 | 
						|
		cost = MAX(cost, ro->path.cost);
 | 
						|
	}
 | 
						|
 | 
						|
	return cost;
 | 
						|
}
 | 
						|
 | 
						|
static inline int
 | 
						|
ospf6_abr_range_summary_needs_update(struct ospf6_route *range, uint32_t cost)
 | 
						|
{
 | 
						|
	int redo_summary = 0;
 | 
						|
 | 
						|
	if (CHECK_FLAG(range->flag, OSPF6_ROUTE_REMOVE)) {
 | 
						|
		UNSET_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
 | 
						|
		redo_summary = 1;
 | 
						|
	} else if (CHECK_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) {
 | 
						|
		if (range->path.cost != 0) {
 | 
						|
			range->path.cost = 0;
 | 
						|
			redo_summary = 1;
 | 
						|
		}
 | 
						|
	} else if (cost) {
 | 
						|
		if ((OSPF6_PATH_COST_IS_CONFIGURED(range->path)
 | 
						|
		     && range->path.cost != range->path.u.cost_config)) {
 | 
						|
			range->path.cost = range->path.u.cost_config;
 | 
						|
			SET_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
 | 
						|
			redo_summary = 1;
 | 
						|
		} else if (!OSPF6_PATH_COST_IS_CONFIGURED(range->path)
 | 
						|
			   && range->path.cost != cost) {
 | 
						|
			range->path.cost = cost;
 | 
						|
			SET_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
 | 
						|
			redo_summary = 1;
 | 
						|
		}
 | 
						|
	} else if (CHECK_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) {
 | 
						|
		/* Cost is zero, meaning no active range */
 | 
						|
		UNSET_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY);
 | 
						|
		range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC;
 | 
						|
		redo_summary = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	return (redo_summary);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_abr_range_update(struct ospf6_route *range, struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	uint32_t cost = 0;
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	int summary_orig = 0;
 | 
						|
 | 
						|
	assert(range->type == OSPF6_DEST_TYPE_RANGE);
 | 
						|
	oa = ospf6_area_lookup(range->path.area_id, ospf6);
 | 
						|
	assert(oa);
 | 
						|
 | 
						|
	/* 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
 | 
						|
	 * cost has changed or the summarized cost has changed then redo
 | 
						|
	 * summaries.
 | 
						|
	 * Alternately, if there are no longer active prefixes and there are
 | 
						|
	 * summary announcements, withdraw those announcements.
 | 
						|
	 *
 | 
						|
	 * The don't advertise code relies on the path.cost being set to UNSPEC
 | 
						|
	 * to
 | 
						|
	 * work the first time. Subsequent times the path.cost is not 0 anyway
 | 
						|
	 * if there
 | 
						|
	 * were active ranges.
 | 
						|
	 */
 | 
						|
	if (!ospf6_abr_range_summary_needs_update(range, cost))
 | 
						|
		return;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("%s: range %pFX update", __func__, &range->prefix);
 | 
						|
 | 
						|
	if (CHECK_FLAG(range->flag, OSPF6_ROUTE_NSSA_RANGE)) {
 | 
						|
		if (CHECK_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)
 | 
						|
		    && !CHECK_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) {
 | 
						|
			ospf6_nssa_lsa_originate(range, oa, true);
 | 
						|
			summary_orig = 1;
 | 
						|
		} else {
 | 
						|
			struct ospf6_lsa *lsa;
 | 
						|
 | 
						|
			lsa = ospf6_lsdb_lookup(range->path.origin.type,
 | 
						|
						range->path.origin.id,
 | 
						|
						ospf6->router_id, oa->lsdb);
 | 
						|
			if (lsa)
 | 
						|
				ospf6_lsa_premature_aging(lsa);
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) {
 | 
						|
			summary_orig +=
 | 
						|
				ospf6_abr_originate_summary_to_area(range, oa);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (CHECK_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)
 | 
						|
	    && summary_orig) {
 | 
						|
		if (!CHECK_FLAG(range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
 | 
						|
			if (IS_OSPF6_DEBUG_ABR)
 | 
						|
				zlog_debug("Add discard route");
 | 
						|
 | 
						|
			ospf6_zebra_add_discard(range, ospf6);
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		/* Summary removed or no summary generated as no
 | 
						|
		 * specifics exist */
 | 
						|
		if (CHECK_FLAG(range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
 | 
						|
			if (IS_OSPF6_DEBUG_ABR)
 | 
						|
				zlog_debug("Delete discard route");
 | 
						|
 | 
						|
			ospf6_zebra_delete_discard(range, ospf6);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_abr_originate_summary(struct ospf6_route *route, struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	struct ospf6_route *range = NULL;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR) {
 | 
						|
		char buf[BUFSIZ];
 | 
						|
 | 
						|
		if (route->type == OSPF6_DEST_TYPE_ROUTER)
 | 
						|
			inet_ntop(AF_INET,
 | 
						|
				  &ADV_ROUTER_IN_PREFIX(&route->prefix), buf,
 | 
						|
				  sizeof(buf));
 | 
						|
		else
 | 
						|
			prefix2str(&route->prefix, buf, sizeof(buf));
 | 
						|
 | 
						|
		zlog_debug("%s: route %s", __func__, buf);
 | 
						|
	}
 | 
						|
 | 
						|
	if (route->type == OSPF6_DEST_TYPE_NETWORK) {
 | 
						|
		oa = ospf6_area_lookup(route->path.area_id, ospf6);
 | 
						|
		if (!oa) {
 | 
						|
			zlog_err("OSPFv6 area lookup failed");
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		range = ospf6_route_lookup_bestmatch(&route->prefix,
 | 
						|
						     oa->range_table);
 | 
						|
		if (range) {
 | 
						|
			ospf6_abr_range_update(range, ospf6);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa))
 | 
						|
		ospf6_abr_originate_summary_to_area(route, oa);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_abr_defaults_to_stub(struct ospf6 *o)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	struct ospf6_route *def, *route;
 | 
						|
	int type = DEFAULT_ROUTE;
 | 
						|
 | 
						|
	if (!o->backbone)
 | 
						|
		return;
 | 
						|
 | 
						|
	def = ospf6_route_create(o);
 | 
						|
	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.type = OSPF6_PATH_TYPE_INTER;
 | 
						|
	def->path.subtype = OSPF6_PATH_SUBTYPE_DEFAULT_RT;
 | 
						|
	def->path.area_id = o->backbone->area_id;
 | 
						|
	def->path.metric_type = metric_type(o, type, 0);
 | 
						|
	def->path.cost = metric_value(o, type, 0);
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(o->area_list, node, nnode, 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
 | 
						|
			 * non-stub */
 | 
						|
			route = ospf6_route_lookup(&def->prefix,
 | 
						|
						   oa->summary_prefix);
 | 
						|
			if (route
 | 
						|
			    && (route->path.subtype == def->path.subtype)) {
 | 
						|
				if (IS_OSPF6_DEBUG_ABR)
 | 
						|
					zlog_debug(
 | 
						|
						"Withdrawing default route from non-stubby area %s",
 | 
						|
						oa->name);
 | 
						|
				SET_FLAG(def->flag, OSPF6_ROUTE_REMOVE);
 | 
						|
				ospf6_abr_originate_summary_to_area(def, oa);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	ospf6_route_delete(def);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_abr_old_path_update(struct ospf6_route *old_route,
 | 
						|
			       struct ospf6_route *route,
 | 
						|
			       struct ospf6_route_table *table)
 | 
						|
{
 | 
						|
	struct ospf6_path *o_path = NULL;
 | 
						|
	struct listnode *anode, *anext;
 | 
						|
	struct listnode *nnode, *rnode, *rnext;
 | 
						|
	struct ospf6_nexthop *nh, *rnh;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext, o_path)) {
 | 
						|
		if (o_path->area_id != route->path.area_id
 | 
						|
		    || !ospf6_ls_origin_same(o_path, &route->path))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if ((o_path->cost == route->path.cost) &&
 | 
						|
		    (o_path->u.cost_e2 == route->path.u.cost_e2))
 | 
						|
			continue;
 | 
						|
 | 
						|
		for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
 | 
						|
			for (ALL_LIST_ELEMENTS(old_route->nh_list, rnode,
 | 
						|
					       rnext, rnh)) {
 | 
						|
				if (!ospf6_nexthop_is_same(rnh, nh))
 | 
						|
					continue;
 | 
						|
				listnode_delete(old_route->nh_list, rnh);
 | 
						|
				ospf6_nexthop_delete(rnh);
 | 
						|
			}
 | 
						|
 | 
						|
		}
 | 
						|
 | 
						|
		listnode_delete(old_route->paths, o_path);
 | 
						|
		ospf6_path_free(o_path);
 | 
						|
 | 
						|
		for (ALL_LIST_ELEMENTS(old_route->paths, anode,
 | 
						|
				       anext, o_path)) {
 | 
						|
			ospf6_merge_nexthops(old_route->nh_list,
 | 
						|
					     o_path->nh_list);
 | 
						|
		}
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX))
 | 
						|
			zlog_debug("%s: paths %u nh %u", __func__,
 | 
						|
				   old_route->paths
 | 
						|
					   ? listcount(old_route->paths)
 | 
						|
					   : 0,
 | 
						|
				   old_route->nh_list
 | 
						|
					   ? listcount(old_route->nh_list)
 | 
						|
					   : 0);
 | 
						|
 | 
						|
		if (table->hook_add)
 | 
						|
			(*table->hook_add)(old_route);
 | 
						|
 | 
						|
		if (old_route->path.origin.id == route->path.origin.id &&
 | 
						|
		    old_route->path.origin.adv_router ==
 | 
						|
		    route->path.origin.adv_router) {
 | 
						|
			struct ospf6_path *h_path;
 | 
						|
 | 
						|
			h_path = (struct ospf6_path *)
 | 
						|
			listgetdata(listhead(old_route->paths));
 | 
						|
			old_route->path.origin.type = h_path->origin.type;
 | 
						|
			old_route->path.origin.id = h_path->origin.id;
 | 
						|
			old_route->path.origin.adv_router =
 | 
						|
				h_path->origin.adv_router;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_abr_old_route_remove(struct ospf6_lsa *lsa, struct ospf6_route *old,
 | 
						|
				struct ospf6_route_table *table)
 | 
						|
{
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("%s: route %pFX, paths %d", __func__, &old->prefix,
 | 
						|
			   listcount(old->paths));
 | 
						|
 | 
						|
	if (listcount(old->paths) > 1) {
 | 
						|
		struct listnode *anode, *anext, *nnode, *rnode, *rnext;
 | 
						|
		struct ospf6_path *o_path;
 | 
						|
		struct ospf6_nexthop *nh, *rnh;
 | 
						|
		bool nh_updated = false;
 | 
						|
 | 
						|
		for (ALL_LIST_ELEMENTS(old->paths, anode, anext, o_path)) {
 | 
						|
			if (o_path->origin.adv_router != lsa->header->adv_router
 | 
						|
			    || o_path->origin.id != lsa->header->id)
 | 
						|
				continue;
 | 
						|
			for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
 | 
						|
				for (ALL_LIST_ELEMENTS(old->nh_list,
 | 
						|
							rnode, rnext, rnh)) {
 | 
						|
					if (!ospf6_nexthop_is_same(rnh, nh))
 | 
						|
						continue;
 | 
						|
					if (IS_OSPF6_DEBUG_ABR)
 | 
						|
						zlog_debug("deleted nexthop");
 | 
						|
					listnode_delete(old->nh_list, rnh);
 | 
						|
					ospf6_nexthop_delete(rnh);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			listnode_delete(old->paths, o_path);
 | 
						|
			ospf6_path_free(o_path);
 | 
						|
			nh_updated = true;
 | 
						|
		}
 | 
						|
 | 
						|
		if (nh_updated) {
 | 
						|
			if (listcount(old->paths)) {
 | 
						|
				if (IS_OSPF6_DEBUG_ABR
 | 
						|
				    || IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX))
 | 
						|
					zlog_debug("%s: old %pFX updated nh %u",
 | 
						|
						   __func__, &old->prefix,
 | 
						|
						   old->nh_list ? listcount(
 | 
						|
							   old->nh_list)
 | 
						|
								: 0);
 | 
						|
 | 
						|
				if (table->hook_add)
 | 
						|
					(*table->hook_add)(old);
 | 
						|
 | 
						|
				if ((old->path.origin.id == lsa->header->id) &&
 | 
						|
				    (old->path.origin.adv_router
 | 
						|
						 == lsa->header->adv_router)) {
 | 
						|
					struct ospf6_path *h_path;
 | 
						|
 | 
						|
					h_path = (struct ospf6_path *)
 | 
						|
						listgetdata(
 | 
						|
							listhead(old->paths));
 | 
						|
					old->path.origin.type =
 | 
						|
						h_path->origin.type;
 | 
						|
					old->path.origin.id = h_path->origin.id;
 | 
						|
					old->path.origin.adv_router =
 | 
						|
						h_path->origin.adv_router;
 | 
						|
				}
 | 
						|
			} else
 | 
						|
				ospf6_route_remove(old, table);
 | 
						|
		}
 | 
						|
	} else
 | 
						|
		ospf6_route_remove(old, table);
 | 
						|
}
 | 
						|
 | 
						|
/* RFC 2328 16.2. Calculating the inter-area routes */
 | 
						|
void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
 | 
						|
{
 | 
						|
	struct prefix prefix, abr_prefix;
 | 
						|
	struct ospf6_route_table *table = NULL;
 | 
						|
	struct ospf6_route *range, *route, *old = NULL, *old_route;
 | 
						|
	struct ospf6_route *abr_entry;
 | 
						|
	uint8_t type = 0;
 | 
						|
	char options[3] = {0, 0, 0};
 | 
						|
	uint8_t prefix_options = 0;
 | 
						|
	uint32_t cost = 0;
 | 
						|
	uint8_t router_bits = 0;
 | 
						|
	char buf[PREFIX2STR_BUFFER];
 | 
						|
	int is_debug = 0;
 | 
						|
	struct ospf6_inter_prefix_lsa *prefix_lsa = NULL;
 | 
						|
	struct ospf6_inter_router_lsa *router_lsa = NULL;
 | 
						|
	bool old_entry_updated = false;
 | 
						|
	struct ospf6_path *path, *o_path, *ecmp_path;
 | 
						|
	struct listnode *anode;
 | 
						|
	bool add_route = false;
 | 
						|
 | 
						|
	memset(&prefix, 0, sizeof(prefix));
 | 
						|
 | 
						|
	if (lsa->header->type == htons(OSPF6_LSTYPE_INTER_PREFIX)) {
 | 
						|
		if (IS_OSPF6_DEBUG_EXAMIN(INTER_PREFIX)) {
 | 
						|
			is_debug++;
 | 
						|
			zlog_debug("%s: LSA %s age %d in area %s", __func__,
 | 
						|
				   lsa->name, ospf6_lsa_age_current(lsa),
 | 
						|
				   oa->name);
 | 
						|
		}
 | 
						|
 | 
						|
		prefix_lsa =
 | 
						|
			(struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END(
 | 
						|
				lsa->header);
 | 
						|
		prefix.family = AF_INET6;
 | 
						|
		prefix.prefixlen = prefix_lsa->prefix.prefix_length;
 | 
						|
		ospf6_prefix_in6_addr(&prefix.u.prefix6, prefix_lsa,
 | 
						|
				      &prefix_lsa->prefix);
 | 
						|
		if (is_debug)
 | 
						|
			prefix2str(&prefix, buf, sizeof(buf));
 | 
						|
		table = oa->ospf6->route_table;
 | 
						|
		type = OSPF6_DEST_TYPE_NETWORK;
 | 
						|
		prefix_options = prefix_lsa->prefix.prefix_options;
 | 
						|
		cost = OSPF6_ABR_SUMMARY_METRIC(prefix_lsa);
 | 
						|
	} else if (lsa->header->type == htons(OSPF6_LSTYPE_INTER_ROUTER)) {
 | 
						|
		if (IS_OSPF6_DEBUG_EXAMIN(INTER_ROUTER)) {
 | 
						|
			is_debug++;
 | 
						|
			zlog_debug("%s: LSA %s age %d in area %s", __func__,
 | 
						|
				   lsa->name, ospf6_lsa_age_current(lsa),
 | 
						|
				   oa->name);
 | 
						|
		}
 | 
						|
 | 
						|
		router_lsa =
 | 
						|
			(struct ospf6_inter_router_lsa *)OSPF6_LSA_HEADER_END(
 | 
						|
				lsa->header);
 | 
						|
		ospf6_linkstate_prefix(router_lsa->router_id, htonl(0),
 | 
						|
				       &prefix);
 | 
						|
		if (is_debug)
 | 
						|
			inet_ntop(AF_INET, &router_lsa->router_id, buf,
 | 
						|
				  sizeof(buf));
 | 
						|
 | 
						|
		table = oa->ospf6->brouter_table;
 | 
						|
		type = OSPF6_DEST_TYPE_ROUTER;
 | 
						|
		options[0] = router_lsa->options[0];
 | 
						|
		options[1] = router_lsa->options[1];
 | 
						|
		options[2] = router_lsa->options[2];
 | 
						|
		cost = OSPF6_ABR_SUMMARY_METRIC(router_lsa);
 | 
						|
		SET_FLAG(router_bits, OSPF6_ROUTER_BIT_E);
 | 
						|
	} else
 | 
						|
		assert(0);
 | 
						|
 | 
						|
	/* Find existing route */
 | 
						|
	route = ospf6_route_lookup(&prefix, table);
 | 
						|
	if (route) {
 | 
						|
		ospf6_route_lock(route);
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug("%s: route %pFX, paths %d", __func__,
 | 
						|
				   &prefix, listcount(route->paths));
 | 
						|
	}
 | 
						|
	while (route && ospf6_route_is_prefix(&prefix, route)) {
 | 
						|
		if (route->path.area_id == oa->area_id
 | 
						|
		    && route->path.origin.type == lsa->header->type
 | 
						|
		    && !CHECK_FLAG(route->flag, OSPF6_ROUTE_WAS_REMOVED)) {
 | 
						|
			/* LSA adv. router could be part of route's
 | 
						|
			 * paths list. Find the existing path and set
 | 
						|
			 * old as the route.
 | 
						|
			 */
 | 
						|
			if (listcount(route->paths) > 1) {
 | 
						|
				for (ALL_LIST_ELEMENTS_RO(route->paths, anode,
 | 
						|
							  o_path)) {
 | 
						|
					if (o_path->origin.id == lsa->header->id
 | 
						|
					    && o_path->origin.adv_router ==
 | 
						|
					    lsa->header->adv_router) {
 | 
						|
						old = route;
 | 
						|
 | 
						|
						if (is_debug)
 | 
						|
							zlog_debug(
 | 
						|
								"%s: old entry found in paths, adv_router %pI4",
 | 
						|
								__func__,
 | 
						|
								&o_path->origin.adv_router);
 | 
						|
 | 
						|
						break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			} else if (route->path.origin.id == lsa->header->id &&
 | 
						|
				   route->path.origin.adv_router ==
 | 
						|
				   lsa->header->adv_router)
 | 
						|
				old = route;
 | 
						|
		}
 | 
						|
		route = ospf6_route_next(route);
 | 
						|
	}
 | 
						|
	if (route)
 | 
						|
		ospf6_route_unlock(route);
 | 
						|
 | 
						|
	/* (1) if cost == LSInfinity or if the LSA is MaxAge */
 | 
						|
	if (cost == OSPF_LS_INFINITY) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug("cost is LS_INFINITY, ignore");
 | 
						|
		if (old)
 | 
						|
			ospf6_abr_old_route_remove(lsa, old, table);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	if (OSPF6_LSA_IS_MAXAGE(lsa)) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug("%s: LSA %s is MaxAge, ignore", __func__,
 | 
						|
				   lsa->name);
 | 
						|
		if (old)
 | 
						|
			ospf6_abr_old_route_remove(lsa, old, table);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	/* (2) if the LSA is self-originated, ignore */
 | 
						|
	if (lsa->header->adv_router == oa->ospf6->router_id) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug("LSA %s is self-originated, ignore",
 | 
						|
				   lsa->name);
 | 
						|
		if (old)
 | 
						|
			ospf6_route_remove(old, table);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* (3) if the prefix is equal to an active configured address range */
 | 
						|
	/*     or if the NU bit is set in the prefix */
 | 
						|
	if (lsa->header->type == htons(OSPF6_LSTYPE_INTER_PREFIX)) {
 | 
						|
		/* must have been set in previous block */
 | 
						|
		assert(prefix_lsa);
 | 
						|
 | 
						|
		range = ospf6_route_lookup(&prefix, oa->range_table);
 | 
						|
		if (range) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"Prefix is equal to address range, ignore");
 | 
						|
			if (old)
 | 
						|
				ospf6_route_remove(old, table);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		if (CHECK_FLAG(prefix_lsa->prefix.prefix_options,
 | 
						|
			       OSPF6_PREFIX_OPTION_NU)
 | 
						|
		    || CHECK_FLAG(prefix_lsa->prefix.prefix_options,
 | 
						|
				  OSPF6_PREFIX_OPTION_LA)) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug("Prefix has NU/LA bit set, ignore");
 | 
						|
			if (old)
 | 
						|
				ospf6_route_remove(old, table);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (lsa->header->type == htons(OSPF6_LSTYPE_INTER_ROUTER)) {
 | 
						|
		/* To pass test suites */
 | 
						|
		assert(router_lsa);
 | 
						|
		if (!OSPF6_OPT_ISSET(router_lsa->options, OSPF6_OPT_R)
 | 
						|
		    || !OSPF6_OPT_ISSET(router_lsa->options, OSPF6_OPT_V6)) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug("Prefix has NU/LA bit set, ignore");
 | 
						|
			if (old)
 | 
						|
				ospf6_route_remove(old, table);
 | 
						|
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		/* Avoid infinite recursion if someone has maliciously announced
 | 
						|
		   an
 | 
						|
		   Inter-Router LSA for an ABR
 | 
						|
		*/
 | 
						|
		if (lsa->header->adv_router == router_lsa->router_id) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"Ignoring Inter-Router LSA for an ABR (%s)",
 | 
						|
					buf);
 | 
						|
			if (old)
 | 
						|
				ospf6_route_remove(old, table);
 | 
						|
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* (4) if the routing table entry for the ABR does not exist */
 | 
						|
	ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0), &abr_prefix);
 | 
						|
	abr_entry = ospf6_route_lookup(&abr_prefix, oa->ospf6->brouter_table);
 | 
						|
	if (abr_entry == NULL || abr_entry->path.area_id != oa->area_id
 | 
						|
	    || CHECK_FLAG(abr_entry->flag, OSPF6_ROUTE_REMOVE)
 | 
						|
	    || !CHECK_FLAG(abr_entry->path.router_bits, OSPF6_ROUTER_BIT_B)) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"%s: ABR router entry %pFX does not exist, ignore",
 | 
						|
				__func__, &abr_prefix);
 | 
						|
		if (old) {
 | 
						|
			if (old->type == OSPF6_DEST_TYPE_ROUTER &&
 | 
						|
			    oa->intra_brouter_calc) {
 | 
						|
				if (is_debug)
 | 
						|
					zlog_debug(
 | 
						|
						"%s: intra_brouter_calc is on, skip brouter remove: %s (%p)",
 | 
						|
						__func__, buf, (void *)old);
 | 
						|
			} else {
 | 
						|
				if (is_debug)
 | 
						|
					zlog_debug(
 | 
						|
						"%s: remove old entry: %s %p ",
 | 
						|
						__func__, buf, (void *)old);
 | 
						|
				ospf6_abr_old_route_remove(lsa, old, table);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* (5),(6): the path preference is handled by the sorting
 | 
						|
	   in the routing table. Always install the path by substituting
 | 
						|
	   old route (if any). */
 | 
						|
	route = ospf6_route_create(oa->ospf6);
 | 
						|
 | 
						|
	route->type = type;
 | 
						|
	route->prefix = prefix;
 | 
						|
	route->prefix_options = prefix_options;
 | 
						|
	route->path.origin.type = lsa->header->type;
 | 
						|
	route->path.origin.id = lsa->header->id;
 | 
						|
	route->path.origin.adv_router = lsa->header->adv_router;
 | 
						|
	route->path.router_bits = router_bits;
 | 
						|
	route->path.options[0] = options[0];
 | 
						|
	route->path.options[1] = options[1];
 | 
						|
	route->path.options[2] = options[2];
 | 
						|
	route->path.area_id = oa->area_id;
 | 
						|
	route->path.type = OSPF6_PATH_TYPE_INTER;
 | 
						|
	route->path.cost = abr_entry->path.cost + cost;
 | 
						|
 | 
						|
	/* copy brouter rechable nexthops into the route. */
 | 
						|
	ospf6_route_copy_nexthops(route, abr_entry);
 | 
						|
 | 
						|
	/* (7) If the routes are identical, copy the next hops over to existing
 | 
						|
	   route. ospf6's route table implementation will otherwise string both
 | 
						|
	   routes, but keep the older one as the best route since the routes
 | 
						|
	   are identical.
 | 
						|
	*/
 | 
						|
	old = ospf6_route_lookup(&prefix, table);
 | 
						|
	if (old) {
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug("%s: found old route %pFX, paths %d",
 | 
						|
				   __func__, &prefix, listcount(old->paths));
 | 
						|
	}
 | 
						|
	for (old_route = old; old_route; old_route = old_route->next) {
 | 
						|
 | 
						|
		/* The route linked-list is grouped in batches of prefix.
 | 
						|
		 * If the new prefix is not the same as the one of interest
 | 
						|
		 * then we have walked over the end of the batch and so we
 | 
						|
		 * should break rather than continuing unnecessarily.
 | 
						|
		 */
 | 
						|
		if (!ospf6_route_is_same(old_route, route))
 | 
						|
			break;
 | 
						|
		if ((old_route->type != route->type)
 | 
						|
		    || (old_route->path.type != route->path.type))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if ((ospf6_route_cmp(route, old_route) != 0)) {
 | 
						|
			if (is_debug)
 | 
						|
				zlog_debug(
 | 
						|
					"%s: old %p %pFX cost %u new route cost %u are not same",
 | 
						|
					__func__, (void *)old_route, &prefix,
 | 
						|
					old_route->path.cost, route->path.cost);
 | 
						|
 | 
						|
			/* Check new route's adv. router is same in one of
 | 
						|
			 * the paths with differed cost, if so remove the
 | 
						|
			 * old path as later new route will be added.
 | 
						|
			 */
 | 
						|
			if (listcount(old_route->paths) > 1)
 | 
						|
				ospf6_abr_old_path_update(old_route, route,
 | 
						|
							  table);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		list_delete_all_node(old_route->nh_list);
 | 
						|
		ospf6_route_copy_nexthops(old_route, route);
 | 
						|
		old_entry_updated = true;
 | 
						|
 | 
						|
		for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
 | 
						|
						  o_path)) {
 | 
						|
			if (o_path->area_id == route->path.area_id
 | 
						|
			    && ospf6_ls_origin_same(o_path, &route->path))
 | 
						|
				break;
 | 
						|
		}
 | 
						|
 | 
						|
		/* New adv. router for a existing path add to paths list */
 | 
						|
		if (o_path == NULL) {
 | 
						|
			ecmp_path = ospf6_path_dup(&route->path);
 | 
						|
 | 
						|
			/* Add a nh_list to new ecmp path */
 | 
						|
			ospf6_copy_nexthops(ecmp_path->nh_list, route->nh_list);
 | 
						|
 | 
						|
			/* Add the new path to route's path list */
 | 
						|
			listnode_add_sort(old_route->paths, ecmp_path);
 | 
						|
 | 
						|
			if (is_debug) {
 | 
						|
				zlog_debug(
 | 
						|
					"%s: route %pFX cost %u another path %pI4 added with nh %u, effective paths %u nh %u",
 | 
						|
					__func__, &route->prefix,
 | 
						|
					old_route->path.cost,
 | 
						|
					&ecmp_path->origin.adv_router,
 | 
						|
					listcount(ecmp_path->nh_list),
 | 
						|
					old_route->paths
 | 
						|
						? listcount(old_route->paths)
 | 
						|
						: 0,
 | 
						|
					listcount(old_route->nh_list));
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			struct ospf6_route *tmp_route;
 | 
						|
 | 
						|
			tmp_route = ospf6_route_create(oa->ospf6);
 | 
						|
 | 
						|
			ospf6_copy_nexthops(tmp_route->nh_list,
 | 
						|
					    o_path->nh_list);
 | 
						|
 | 
						|
			if (!ospf6_route_cmp_nexthops(tmp_route, route)) {
 | 
						|
				/* adv. router exists in the list, update nhs */
 | 
						|
				list_delete_all_node(o_path->nh_list);
 | 
						|
				ospf6_copy_nexthops(o_path->nh_list,
 | 
						|
						    route->nh_list);
 | 
						|
				ospf6_route_delete(tmp_route);
 | 
						|
			} else {
 | 
						|
				/* adv. router has no change in nhs */
 | 
						|
				old_entry_updated = false;
 | 
						|
				ospf6_route_delete(tmp_route);
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (is_debug)
 | 
						|
			zlog_debug(
 | 
						|
				"%s: Update route: %s %p old cost %u new cost %u nh %u",
 | 
						|
				__func__, buf, (void *)old_route,
 | 
						|
				old_route->path.cost, route->path.cost,
 | 
						|
				listcount(old_route->nh_list));
 | 
						|
 | 
						|
		/* For Inter-Prefix route: Update RIB/FIB,
 | 
						|
		 * For Inter-Router trigger summary update
 | 
						|
		 */
 | 
						|
		if (table->hook_add)
 | 
						|
			(*table->hook_add)(old_route);
 | 
						|
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* If the old entry is not updated and old entry not found or old entry
 | 
						|
	 * does not match with the new entry then add the new route
 | 
						|
	 */
 | 
						|
	if (old_entry_updated == false) {
 | 
						|
		if ((old == NULL) || (old->type != route->type)
 | 
						|
		    || (old->path.type != route->path.type)
 | 
						|
		    || (old->path.cost != route->path.cost))
 | 
						|
			add_route = true;
 | 
						|
	}
 | 
						|
 | 
						|
	if (add_route) {
 | 
						|
		if (is_debug) {
 | 
						|
			zlog_debug(
 | 
						|
				"%s: Install new route: %s cost %u nh %u adv_router %pI4",
 | 
						|
				__func__, buf, route->path.cost,
 | 
						|
				listcount(route->nh_list),
 | 
						|
				&route->path.origin.adv_router);
 | 
						|
		}
 | 
						|
 | 
						|
		path = ospf6_path_dup(&route->path);
 | 
						|
		ospf6_copy_nexthops(path->nh_list, abr_entry->nh_list);
 | 
						|
		listnode_add_sort(route->paths, path);
 | 
						|
		/* ospf6_ia_add_nw_route (table, &prefix, route); */
 | 
						|
		ospf6_route_add(route, table);
 | 
						|
	} else
 | 
						|
		/* if we did not add the route remove it */
 | 
						|
		ospf6_route_delete(route);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_abr_examin_brouter(uint32_t router_id, struct ospf6_route *route,
 | 
						|
			      struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	uint16_t type;
 | 
						|
 | 
						|
	oa = ospf6_area_lookup(route->path.area_id, ospf6);
 | 
						|
	/*
 | 
						|
	 * It is possible to designate a non backbone
 | 
						|
	 * area first.  If that is the case safely
 | 
						|
	 * fall out of this function.
 | 
						|
	 */
 | 
						|
	if (oa == NULL)
 | 
						|
		return;
 | 
						|
 | 
						|
	type = htons(OSPF6_LSTYPE_INTER_ROUTER);
 | 
						|
	for (ALL_LSDB_TYPED_ADVRTR(oa->lsdb, type, router_id, lsa))
 | 
						|
		ospf6_abr_examin_summary(lsa, oa);
 | 
						|
 | 
						|
	type = htons(OSPF6_LSTYPE_INTER_PREFIX);
 | 
						|
	for (ALL_LSDB_TYPED_ADVRTR(oa->lsdb, type, router_id, lsa))
 | 
						|
		ospf6_abr_examin_summary(lsa, oa);
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_abr_prefix_resummarize(struct ospf6 *o)
 | 
						|
{
 | 
						|
	struct ospf6_route *route;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("Re-examining Inter-Prefix Summaries");
 | 
						|
 | 
						|
	for (route = ospf6_route_head(o->route_table); route;
 | 
						|
	     route = ospf6_route_next(route))
 | 
						|
		ospf6_abr_originate_summary(route, o);
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		zlog_debug("Finished re-examining Inter-Prefix Summaries");
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Display functions */
 | 
						|
static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,
 | 
						|
							char *buf, int buflen,
 | 
						|
							int pos)
 | 
						|
{
 | 
						|
	struct ospf6_inter_prefix_lsa *prefix_lsa;
 | 
						|
	struct in6_addr in6;
 | 
						|
	char tbuf[16];
 | 
						|
 | 
						|
	if (lsa != NULL) {
 | 
						|
		prefix_lsa =
 | 
						|
			(struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END(
 | 
						|
				lsa->header);
 | 
						|
 | 
						|
		ospf6_prefix_in6_addr(&in6, prefix_lsa, &prefix_lsa->prefix);
 | 
						|
		if (buf) {
 | 
						|
			inet_ntop(AF_INET6, &in6, buf, buflen);
 | 
						|
			snprintf(tbuf, sizeof(tbuf), "/%d",
 | 
						|
				 prefix_lsa->prefix.prefix_length);
 | 
						|
			strlcat(buf, tbuf, buflen);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return (buf);
 | 
						|
}
 | 
						|
 | 
						|
static int ospf6_inter_area_prefix_lsa_show(struct vty *vty,
 | 
						|
					    struct ospf6_lsa *lsa,
 | 
						|
					    json_object *json_obj,
 | 
						|
					    bool use_json)
 | 
						|
{
 | 
						|
	struct ospf6_inter_prefix_lsa *prefix_lsa;
 | 
						|
	char buf[INET6_ADDRSTRLEN];
 | 
						|
 | 
						|
	prefix_lsa = (struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END(
 | 
						|
		lsa->header);
 | 
						|
 | 
						|
	if (use_json) {
 | 
						|
		json_object_int_add(
 | 
						|
			json_obj, "metric",
 | 
						|
			(unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa));
 | 
						|
		ospf6_prefix_options_printbuf(prefix_lsa->prefix.prefix_options,
 | 
						|
					      buf, sizeof(buf));
 | 
						|
		json_object_string_add(json_obj, "prefixOptions", buf);
 | 
						|
		json_object_string_add(
 | 
						|
			json_obj, "prefix",
 | 
						|
			ospf6_inter_area_prefix_lsa_get_prefix_str(
 | 
						|
				lsa, buf, sizeof(buf), 0));
 | 
						|
	} else {
 | 
						|
		vty_out(vty, "     Metric: %lu\n",
 | 
						|
			(unsigned long)OSPF6_ABR_SUMMARY_METRIC(prefix_lsa));
 | 
						|
 | 
						|
		ospf6_prefix_options_printbuf(prefix_lsa->prefix.prefix_options,
 | 
						|
					      buf, sizeof(buf));
 | 
						|
		vty_out(vty, "     Prefix Options: %s\n", buf);
 | 
						|
 | 
						|
		vty_out(vty, "     Prefix: %s\n",
 | 
						|
			ospf6_inter_area_prefix_lsa_get_prefix_str(
 | 
						|
				lsa, buf, sizeof(buf), 0));
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static char *ospf6_inter_area_router_lsa_get_prefix_str(struct ospf6_lsa *lsa,
 | 
						|
							char *buf, int buflen,
 | 
						|
							int pos)
 | 
						|
{
 | 
						|
	struct ospf6_inter_router_lsa *router_lsa;
 | 
						|
 | 
						|
	if (lsa != NULL) {
 | 
						|
		router_lsa =
 | 
						|
			(struct ospf6_inter_router_lsa *)OSPF6_LSA_HEADER_END(
 | 
						|
				lsa->header);
 | 
						|
 | 
						|
 | 
						|
		if (buf)
 | 
						|
			inet_ntop(AF_INET, &router_lsa->router_id, buf, buflen);
 | 
						|
	}
 | 
						|
 | 
						|
	return (buf);
 | 
						|
}
 | 
						|
 | 
						|
static int ospf6_inter_area_router_lsa_show(struct vty *vty,
 | 
						|
					    struct ospf6_lsa *lsa,
 | 
						|
					    json_object *json_obj,
 | 
						|
					    bool use_json)
 | 
						|
{
 | 
						|
	struct ospf6_inter_router_lsa *router_lsa;
 | 
						|
	char buf[64];
 | 
						|
 | 
						|
	router_lsa = (struct ospf6_inter_router_lsa *)OSPF6_LSA_HEADER_END(
 | 
						|
		lsa->header);
 | 
						|
 | 
						|
	ospf6_options_printbuf(router_lsa->options, buf, sizeof(buf));
 | 
						|
	if (use_json) {
 | 
						|
		json_object_string_add(json_obj, "options", buf);
 | 
						|
		json_object_int_add(
 | 
						|
			json_obj, "metric",
 | 
						|
			(unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa));
 | 
						|
	} else {
 | 
						|
		vty_out(vty, "     Options: %s\n", buf);
 | 
						|
		vty_out(vty, "     Metric: %lu\n",
 | 
						|
			(unsigned long)OSPF6_ABR_SUMMARY_METRIC(router_lsa));
 | 
						|
	}
 | 
						|
 | 
						|
	inet_ntop(AF_INET, &router_lsa->router_id, buf, sizeof(buf));
 | 
						|
	if (use_json)
 | 
						|
		json_object_string_add(json_obj, "destinationRouterId", buf);
 | 
						|
	else
 | 
						|
		vty_out(vty, "     Destination Router ID: %s\n", buf);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Debug commands */
 | 
						|
DEFUN (debug_ospf6_abr,
 | 
						|
       debug_ospf6_abr_cmd,
 | 
						|
       "debug ospf6 abr",
 | 
						|
       DEBUG_STR
 | 
						|
       OSPF6_STR
 | 
						|
       "Debug OSPFv3 ABR function\n"
 | 
						|
      )
 | 
						|
{
 | 
						|
	OSPF6_DEBUG_ABR_ON();
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
DEFUN (no_debug_ospf6_abr,
 | 
						|
       no_debug_ospf6_abr_cmd,
 | 
						|
       "no debug ospf6 abr",
 | 
						|
       NO_STR
 | 
						|
       DEBUG_STR
 | 
						|
       OSPF6_STR
 | 
						|
       "Debug OSPFv3 ABR function\n"
 | 
						|
      )
 | 
						|
{
 | 
						|
	OSPF6_DEBUG_ABR_OFF();
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int config_write_ospf6_debug_abr(struct vty *vty)
 | 
						|
{
 | 
						|
	if (IS_OSPF6_DEBUG_ABR)
 | 
						|
		vty_out(vty, "debug ospf6 abr\n");
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void install_element_ospf6_debug_abr(void)
 | 
						|
{
 | 
						|
	install_element(ENABLE_NODE, &debug_ospf6_abr_cmd);
 | 
						|
	install_element(ENABLE_NODE, &no_debug_ospf6_abr_cmd);
 | 
						|
	install_element(CONFIG_NODE, &debug_ospf6_abr_cmd);
 | 
						|
	install_element(CONFIG_NODE, &no_debug_ospf6_abr_cmd);
 | 
						|
}
 | 
						|
 | 
						|
static struct ospf6_lsa_handler inter_prefix_handler = {
 | 
						|
	.lh_type = OSPF6_LSTYPE_INTER_PREFIX,
 | 
						|
	.lh_name = "Inter-Prefix",
 | 
						|
	.lh_short_name = "IAP",
 | 
						|
	.lh_show = ospf6_inter_area_prefix_lsa_show,
 | 
						|
	.lh_get_prefix_str = ospf6_inter_area_prefix_lsa_get_prefix_str,
 | 
						|
	.lh_debug = 0};
 | 
						|
 | 
						|
static struct ospf6_lsa_handler inter_router_handler = {
 | 
						|
	.lh_type = OSPF6_LSTYPE_INTER_ROUTER,
 | 
						|
	.lh_name = "Inter-Router",
 | 
						|
	.lh_short_name = "IAR",
 | 
						|
	.lh_show = ospf6_inter_area_router_lsa_show,
 | 
						|
	.lh_get_prefix_str = ospf6_inter_area_router_lsa_get_prefix_str,
 | 
						|
	.lh_debug = 0};
 | 
						|
 | 
						|
void ospf6_abr_init(void)
 | 
						|
{
 | 
						|
	ospf6_install_lsa_handler(&inter_prefix_handler);
 | 
						|
	ospf6_install_lsa_handler(&inter_router_handler);
 | 
						|
}
 |