mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 11:45:06 +00:00 
			
		
		
		
	We should probably prevent any type of namespace collision with something else. Signed-off-by: Donald Sharp <sharpd@nvidia.com>
		
			
				
	
	
		
			2521 lines
		
	
	
		
			72 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2521 lines
		
	
	
		
			72 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
						|
/*
 | 
						|
 * Copyright (C) 2003 Yasuhiro Ohara
 | 
						|
 */
 | 
						|
 | 
						|
#include <zebra.h>
 | 
						|
 | 
						|
#include "log.h"
 | 
						|
#include "linklist.h"
 | 
						|
#include "frrevent.h"
 | 
						|
#include "memory.h"
 | 
						|
#include "if.h"
 | 
						|
#include "prefix.h"
 | 
						|
#include "table.h"
 | 
						|
#include "vty.h"
 | 
						|
#include "command.h"
 | 
						|
#include "vrf.h"
 | 
						|
 | 
						|
#include "ospf6_proto.h"
 | 
						|
#include "ospf6_message.h"
 | 
						|
#include "ospf6_route.h"
 | 
						|
#include "ospf6_lsa.h"
 | 
						|
#include "ospf6_lsdb.h"
 | 
						|
 | 
						|
#include "ospf6_top.h"
 | 
						|
#include "ospf6_area.h"
 | 
						|
#include "ospf6_interface.h"
 | 
						|
#include "ospf6_neighbor.h"
 | 
						|
#include "ospf6_intra.h"
 | 
						|
#include "ospf6_asbr.h"
 | 
						|
#include "ospf6_abr.h"
 | 
						|
#include "ospf6_flood.h"
 | 
						|
#include "ospf6d.h"
 | 
						|
#include "ospf6_spf.h"
 | 
						|
#include "ospf6_gr.h"
 | 
						|
 | 
						|
unsigned char conf_debug_ospf6_brouter = 0;
 | 
						|
uint32_t conf_debug_ospf6_brouter_specific_router_id;
 | 
						|
uint32_t conf_debug_ospf6_brouter_specific_area_id;
 | 
						|
 | 
						|
#define MAX_LSA_PAYLOAD   (1024 + 256)
 | 
						|
/******************************/
 | 
						|
/* RFC2740 3.4.3.1 Router-LSA */
 | 
						|
/******************************/
 | 
						|
 | 
						|
static char *ospf6_router_lsa_get_nbr_id(struct ospf6_lsa *lsa, char *buf,
 | 
						|
					 int buflen, int pos)
 | 
						|
{
 | 
						|
	struct ospf6_router_lsa *router_lsa;
 | 
						|
	struct ospf6_router_lsdesc *lsdesc;
 | 
						|
	char *start, *end;
 | 
						|
	char buf1[INET_ADDRSTRLEN], buf2[INET_ADDRSTRLEN];
 | 
						|
 | 
						|
	if (lsa) {
 | 
						|
		router_lsa = (struct ospf6_router_lsa
 | 
						|
				      *)((char *)lsa->header
 | 
						|
					 + sizeof(struct ospf6_lsa_header));
 | 
						|
		start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
 | 
						|
		end = (char *)lsa->header + ntohs(lsa->header->length);
 | 
						|
 | 
						|
		lsdesc = (struct ospf6_router_lsdesc
 | 
						|
				  *)(start
 | 
						|
				     + pos * (sizeof(struct
 | 
						|
						     ospf6_router_lsdesc)));
 | 
						|
		if ((char *)lsdesc + sizeof(struct ospf6_router_lsdesc)
 | 
						|
		    <= end) {
 | 
						|
			if (buf && (buflen > INET_ADDRSTRLEN * 2)) {
 | 
						|
				inet_ntop(AF_INET,
 | 
						|
					  &lsdesc->neighbor_interface_id, buf1,
 | 
						|
					  sizeof(buf1));
 | 
						|
				inet_ntop(AF_INET, &lsdesc->neighbor_router_id,
 | 
						|
					  buf2, sizeof(buf2));
 | 
						|
				snprintf(buf, buflen, "%s/%s", buf2, buf1);
 | 
						|
 | 
						|
				return buf;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static int ospf6_router_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
 | 
						|
				 json_object *json_obj, bool use_json)
 | 
						|
{
 | 
						|
	char *start, *end, *current;
 | 
						|
	char buf[32], name[32], bits[16], options[32];
 | 
						|
	struct ospf6_router_lsa *router_lsa;
 | 
						|
	struct ospf6_router_lsdesc *lsdesc;
 | 
						|
	json_object *json_arr;
 | 
						|
	json_object *json_loop;
 | 
						|
 | 
						|
	router_lsa =
 | 
						|
		(struct ospf6_router_lsa *)((char *)lsa->header
 | 
						|
					    + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
	ospf6_capability_printbuf(router_lsa->bits, bits, sizeof(bits));
 | 
						|
	ospf6_options_printbuf(router_lsa->options, options, sizeof(options));
 | 
						|
	if (use_json) {
 | 
						|
		json_object_string_add(json_obj, "bits", bits);
 | 
						|
		json_object_string_add(json_obj, "options", options);
 | 
						|
		json_arr = json_object_new_array();
 | 
						|
	} else
 | 
						|
		vty_out(vty, "    Bits: %s Options: %s\n", bits, options);
 | 
						|
 | 
						|
	start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
 | 
						|
	end = (char *)lsa->header + ntohs(lsa->header->length);
 | 
						|
	for (current = start;
 | 
						|
	     current + sizeof(struct ospf6_router_lsdesc) <= end;
 | 
						|
	     current += sizeof(struct ospf6_router_lsdesc)) {
 | 
						|
		lsdesc = (struct ospf6_router_lsdesc *)current;
 | 
						|
 | 
						|
		if (lsdesc->type == OSPF6_ROUTER_LSDESC_POINTTOPOINT)
 | 
						|
			snprintf(name, sizeof(name), "Point-To-Point");
 | 
						|
		else if (lsdesc->type == OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK)
 | 
						|
			snprintf(name, sizeof(name), "Transit-Network");
 | 
						|
		else if (lsdesc->type == OSPF6_ROUTER_LSDESC_STUB_NETWORK)
 | 
						|
			snprintf(name, sizeof(name), "Stub-Network");
 | 
						|
		else if (lsdesc->type == OSPF6_ROUTER_LSDESC_VIRTUAL_LINK)
 | 
						|
			snprintf(name, sizeof(name), "Virtual-Link");
 | 
						|
		else
 | 
						|
			snprintf(name, sizeof(name), "Unknown (%#x)",
 | 
						|
				 lsdesc->type);
 | 
						|
 | 
						|
		if (use_json) {
 | 
						|
			json_loop = json_object_new_object();
 | 
						|
			json_object_string_add(json_loop, "type", name);
 | 
						|
			json_object_int_add(json_loop, "metric",
 | 
						|
					    ntohs(lsdesc->metric));
 | 
						|
			json_object_string_addf(
 | 
						|
				json_loop, "interfaceId", "%pI4",
 | 
						|
				(in_addr_t *)&lsdesc->interface_id);
 | 
						|
			json_object_string_addf(
 | 
						|
				json_loop, "neighborInterfaceId", "%pI4",
 | 
						|
				(in_addr_t *)&lsdesc->neighbor_interface_id);
 | 
						|
			json_object_string_addf(json_loop, "neighborRouterId",
 | 
						|
						"%pI4",
 | 
						|
						&lsdesc->neighbor_router_id);
 | 
						|
			json_object_array_add(json_arr, json_loop);
 | 
						|
		} else {
 | 
						|
			vty_out(vty, "    Type: %s Metric: %d\n", name,
 | 
						|
				ntohs(lsdesc->metric));
 | 
						|
			vty_out(vty, "    Interface ID: %s\n",
 | 
						|
				inet_ntop(AF_INET, &lsdesc->interface_id, buf,
 | 
						|
					  sizeof(buf)));
 | 
						|
			vty_out(vty, "    Neighbor Interface ID: %s\n",
 | 
						|
				inet_ntop(AF_INET,
 | 
						|
					  &lsdesc->neighbor_interface_id, buf,
 | 
						|
					  sizeof(buf)));
 | 
						|
			vty_out(vty, "    Neighbor Router ID: %s\n",
 | 
						|
				inet_ntop(AF_INET, &lsdesc->neighbor_router_id,
 | 
						|
					  buf, sizeof(buf)));
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (use_json)
 | 
						|
		json_object_object_add(json_obj, "lsaDescription", json_arr);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_router_lsa_options_set(struct ospf6_area *oa,
 | 
						|
					 struct ospf6_router_lsa *router_lsa)
 | 
						|
{
 | 
						|
	OSPF6_OPT_CLEAR_ALL(router_lsa->options);
 | 
						|
	memcpy(router_lsa->options, oa->options, 3);
 | 
						|
 | 
						|
	if (ospf6_check_and_set_router_abr(oa->ospf6))
 | 
						|
		SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B);
 | 
						|
	else
 | 
						|
		UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B);
 | 
						|
 | 
						|
	if (!IS_AREA_STUB(oa) && ospf6_asbr_is_asbr(oa->ospf6)) {
 | 
						|
		SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_E);
 | 
						|
	} else {
 | 
						|
		UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_E);
 | 
						|
	}
 | 
						|
 | 
						|
	/* If the router is ASBR and the area-type is NSSA set the
 | 
						|
	 * translate bit in router LSA.
 | 
						|
	 */
 | 
						|
	if (IS_AREA_NSSA(oa)
 | 
						|
	    && (ospf6_asbr_is_asbr(oa->ospf6) || IS_OSPF6_ABR(oa->ospf6))) {
 | 
						|
		if (oa->NSSATranslatorRole == OSPF6_NSSA_ROLE_ALWAYS)
 | 
						|
			SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_NT);
 | 
						|
	} else {
 | 
						|
		UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_NT);
 | 
						|
	}
 | 
						|
 | 
						|
	UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_V);
 | 
						|
	UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_W);
 | 
						|
}
 | 
						|
 | 
						|
int ospf6_router_is_stub_router(struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	struct ospf6_router_lsa *rtr_lsa;
 | 
						|
 | 
						|
	if (lsa != NULL && OSPF6_LSA_IS_TYPE(ROUTER, lsa)) {
 | 
						|
		rtr_lsa = (struct ospf6_router_lsa
 | 
						|
				   *)((caddr_t)lsa->header
 | 
						|
				      + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
		if (!OSPF6_OPT_ISSET(rtr_lsa->options, OSPF6_OPT_R)) {
 | 
						|
			return OSPF6_IS_STUB_ROUTER;
 | 
						|
		} else if (!OSPF6_OPT_ISSET(rtr_lsa->options, OSPF6_OPT_V6)) {
 | 
						|
			return OSPF6_IS_STUB_ROUTER_V6;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return OSPF6_NOT_STUB_ROUTER;
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_router_lsa_originate(struct event *thread)
 | 
						|
{
 | 
						|
	struct ospf6_area *oa;
 | 
						|
 | 
						|
	char buffer[OSPF6_MAX_LSASIZE];
 | 
						|
	struct ospf6_lsa_header *lsa_header;
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
 | 
						|
	uint32_t link_state_id = 0;
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct listnode *j;
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
	struct ospf6_neighbor *on, *drouter = NULL;
 | 
						|
	struct ospf6_router_lsa *router_lsa;
 | 
						|
	struct ospf6_router_lsdesc *lsdesc;
 | 
						|
	uint16_t type;
 | 
						|
	uint32_t router;
 | 
						|
	int count;
 | 
						|
 | 
						|
	oa = (struct ospf6_area *)EVENT_ARG(thread);
 | 
						|
 | 
						|
	if (oa->ospf6->gr_info.restart_in_progress) {
 | 
						|
		if (IS_DEBUG_OSPF6_GR)
 | 
						|
			zlog_debug(
 | 
						|
				"Graceful Restart in progress, don't originate LSA");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
 | 
						|
		zlog_debug("Originate Router-LSA for Area %s", oa->name);
 | 
						|
 | 
						|
	memset(buffer, 0, sizeof(buffer));
 | 
						|
	lsa_header = (struct ospf6_lsa_header *)buffer;
 | 
						|
	router_lsa =
 | 
						|
		(struct ospf6_router_lsa *)((caddr_t)lsa_header
 | 
						|
					    + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
	ospf6_router_lsa_options_set(oa, router_lsa);
 | 
						|
 | 
						|
	/* describe links for each interfaces */
 | 
						|
	lsdesc = (struct ospf6_router_lsdesc
 | 
						|
			  *)((caddr_t)router_lsa
 | 
						|
			     + sizeof(struct ospf6_router_lsa));
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
 | 
						|
		/* Interfaces in state Down or Loopback are not described */
 | 
						|
		if (oi->state == OSPF6_INTERFACE_DOWN
 | 
						|
		    || oi->state == OSPF6_INTERFACE_LOOPBACK)
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* Nor are interfaces without any full adjacencies described */
 | 
						|
		count = 0;
 | 
						|
		for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on))
 | 
						|
			if (on->state == OSPF6_NEIGHBOR_FULL)
 | 
						|
				count++;
 | 
						|
 | 
						|
		if (count == 0)
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* Multiple Router-LSA instance according to size limit setting
 | 
						|
		 */
 | 
						|
		if ((oa->router_lsa_size_limit != 0)
 | 
						|
		    && ((size_t)((char *)lsdesc - buffer)
 | 
						|
				+ sizeof(struct ospf6_router_lsdesc)
 | 
						|
			> oa->router_lsa_size_limit)) {
 | 
						|
			if ((caddr_t)lsdesc
 | 
						|
			    == (caddr_t)router_lsa
 | 
						|
				       + sizeof(struct ospf6_router_lsa)) {
 | 
						|
				zlog_warn(
 | 
						|
					"Size limit setting for Router-LSA too short");
 | 
						|
				return;
 | 
						|
			}
 | 
						|
 | 
						|
			/* Fill LSA Header */
 | 
						|
			lsa_header->age = 0;
 | 
						|
			lsa_header->type = htons(OSPF6_LSTYPE_ROUTER);
 | 
						|
			lsa_header->id = htonl(link_state_id);
 | 
						|
			lsa_header->adv_router = oa->ospf6->router_id;
 | 
						|
			lsa_header->seqnum = ospf6_new_ls_seqnum(
 | 
						|
				lsa_header->type, lsa_header->id,
 | 
						|
				lsa_header->adv_router, oa->lsdb);
 | 
						|
			lsa_header->length =
 | 
						|
				htons((caddr_t)lsdesc - (caddr_t)buffer);
 | 
						|
 | 
						|
			/* LSA checksum */
 | 
						|
			ospf6_lsa_checksum(lsa_header);
 | 
						|
 | 
						|
			/* create LSA */
 | 
						|
			lsa = ospf6_lsa_create(lsa_header);
 | 
						|
 | 
						|
			/* Originate */
 | 
						|
			ospf6_lsa_originate_area(lsa, oa);
 | 
						|
 | 
						|
			/* Reset Buffer to fill next Router LSA */
 | 
						|
			memset(buffer, 0, sizeof(buffer));
 | 
						|
			lsa_header = (struct ospf6_lsa_header *)buffer;
 | 
						|
			router_lsa =
 | 
						|
				(struct ospf6_router_lsa
 | 
						|
					 *)((caddr_t)lsa_header
 | 
						|
					    + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
			ospf6_router_lsa_options_set(oa, router_lsa);
 | 
						|
 | 
						|
			/* describe links for each interfaces */
 | 
						|
			lsdesc = (struct ospf6_router_lsdesc
 | 
						|
					  *)((caddr_t)router_lsa
 | 
						|
					     + sizeof(struct ospf6_router_lsa));
 | 
						|
 | 
						|
			link_state_id++;
 | 
						|
		}
 | 
						|
 | 
						|
		/* Point-to-Point interfaces */
 | 
						|
		if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
 | 
						|
			for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on)) {
 | 
						|
				if (on->state != OSPF6_NEIGHBOR_FULL)
 | 
						|
					continue;
 | 
						|
 | 
						|
				lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT;
 | 
						|
				lsdesc->metric = htons(oi->cost);
 | 
						|
				lsdesc->interface_id =
 | 
						|
					htonl(oi->interface->ifindex);
 | 
						|
				lsdesc->neighbor_interface_id =
 | 
						|
					htonl(on->ifindex);
 | 
						|
				lsdesc->neighbor_router_id = on->router_id;
 | 
						|
 | 
						|
				lsdesc++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		/* Broadcast and NBMA interfaces */
 | 
						|
		else if (oi->type == OSPF_IFTYPE_BROADCAST) {
 | 
						|
			/* If this router is not DR,
 | 
						|
			   and If this router not fully adjacent with DR,
 | 
						|
			   this interface is not transit yet: ignore. */
 | 
						|
			if (oi->state != OSPF6_INTERFACE_DR) {
 | 
						|
				drouter =
 | 
						|
					ospf6_neighbor_lookup(oi->drouter, oi);
 | 
						|
				if (drouter == NULL
 | 
						|
				    || drouter->state != OSPF6_NEIGHBOR_FULL)
 | 
						|
					continue;
 | 
						|
			}
 | 
						|
 | 
						|
			lsdesc->type = OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK;
 | 
						|
			lsdesc->metric = htons(oi->cost);
 | 
						|
			lsdesc->interface_id = htonl(oi->interface->ifindex);
 | 
						|
			if (oi->state != OSPF6_INTERFACE_DR) {
 | 
						|
				lsdesc->neighbor_interface_id =
 | 
						|
					htonl(drouter->ifindex);
 | 
						|
				lsdesc->neighbor_router_id = drouter->router_id;
 | 
						|
			} else {
 | 
						|
				lsdesc->neighbor_interface_id =
 | 
						|
					htonl(oi->interface->ifindex);
 | 
						|
				lsdesc->neighbor_router_id =
 | 
						|
					oi->area->ospf6->router_id;
 | 
						|
			}
 | 
						|
 | 
						|
			lsdesc++;
 | 
						|
		} else {
 | 
						|
			assert(0); /* Unknown interface type */
 | 
						|
		}
 | 
						|
 | 
						|
		/* Virtual links */
 | 
						|
		/* xxx */
 | 
						|
		/* Point-to-Multipoint interfaces */
 | 
						|
		/* xxx */
 | 
						|
	}
 | 
						|
 | 
						|
	/* Fill LSA Header */
 | 
						|
	lsa_header->age = 0;
 | 
						|
	lsa_header->type = htons(OSPF6_LSTYPE_ROUTER);
 | 
						|
	lsa_header->id = htonl(link_state_id);
 | 
						|
	lsa_header->adv_router = oa->ospf6->router_id;
 | 
						|
	lsa_header->seqnum =
 | 
						|
		ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
 | 
						|
				    lsa_header->adv_router, oa->lsdb);
 | 
						|
	lsa_header->length = htons((caddr_t)lsdesc - (caddr_t)buffer);
 | 
						|
 | 
						|
	/* LSA checksum */
 | 
						|
	ospf6_lsa_checksum(lsa_header);
 | 
						|
 | 
						|
	/* create LSA */
 | 
						|
	lsa = ospf6_lsa_create(lsa_header);
 | 
						|
 | 
						|
	/* Originate */
 | 
						|
	ospf6_lsa_originate_area(lsa, oa);
 | 
						|
 | 
						|
	link_state_id++;
 | 
						|
 | 
						|
	/* Do premature-aging of rest, undesired Router-LSAs */
 | 
						|
	type = ntohs(OSPF6_LSTYPE_ROUTER);
 | 
						|
	router = oa->ospf6->router_id;
 | 
						|
	count = 0;
 | 
						|
	for (ALL_LSDB_TYPED_ADVRTR(oa->lsdb, type, router, lsa)) {
 | 
						|
		if (ntohl(lsa->header->id) < link_state_id)
 | 
						|
			continue;
 | 
						|
		ospf6_lsa_purge(lsa);
 | 
						|
		count++;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Waiting till the LSA is actually removed from the database to trigger
 | 
						|
	 * SPF delays network convergence. Unlike IPv4, for an ABR, when all
 | 
						|
	 * interfaces associated with an area are gone, triggering an SPF right
 | 
						|
	 * away
 | 
						|
	 * helps convergence with inter-area routes.
 | 
						|
	 */
 | 
						|
	if (count && !link_state_id)
 | 
						|
		ospf6_spf_schedule(oa->ospf6,
 | 
						|
				   OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED);
 | 
						|
}
 | 
						|
 | 
						|
/*******************************/
 | 
						|
/* RFC2740 3.4.3.2 Network-LSA */
 | 
						|
/*******************************/
 | 
						|
 | 
						|
static char *ospf6_network_lsa_get_ar_id(struct ospf6_lsa *lsa, char *buf,
 | 
						|
					 int buflen, int pos)
 | 
						|
{
 | 
						|
	char *start, *end, *current;
 | 
						|
	struct ospf6_network_lsa *network_lsa;
 | 
						|
	struct ospf6_network_lsdesc *lsdesc;
 | 
						|
 | 
						|
	if (lsa) {
 | 
						|
		network_lsa = (struct ospf6_network_lsa
 | 
						|
				       *)((caddr_t)lsa->header
 | 
						|
					  + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
		start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
 | 
						|
		end = (char *)lsa->header + ntohs(lsa->header->length);
 | 
						|
		current = start + pos * (sizeof(struct ospf6_network_lsdesc));
 | 
						|
 | 
						|
		if ((current + sizeof(struct ospf6_network_lsdesc)) <= end) {
 | 
						|
			lsdesc = (struct ospf6_network_lsdesc *)current;
 | 
						|
			if (buf) {
 | 
						|
				inet_ntop(AF_INET, &lsdesc->router_id, buf,
 | 
						|
					  buflen);
 | 
						|
				return buf;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static int ospf6_network_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
 | 
						|
				  json_object *json_obj, bool use_json)
 | 
						|
{
 | 
						|
	char *start, *end, *current;
 | 
						|
	struct ospf6_network_lsa *network_lsa;
 | 
						|
	struct ospf6_network_lsdesc *lsdesc;
 | 
						|
	char buf[128], options[32];
 | 
						|
	json_object *json_arr;
 | 
						|
 | 
						|
	network_lsa =
 | 
						|
		(struct ospf6_network_lsa *)((caddr_t)lsa->header
 | 
						|
					     + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
	ospf6_options_printbuf(network_lsa->options, options, sizeof(options));
 | 
						|
	if (use_json)
 | 
						|
		json_object_string_add(json_obj, "options", options);
 | 
						|
	else
 | 
						|
		vty_out(vty, "     Options: %s\n", options);
 | 
						|
 | 
						|
	start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
 | 
						|
	end = (char *)lsa->header + ntohs(lsa->header->length);
 | 
						|
	if (use_json)
 | 
						|
		json_arr = json_object_new_array();
 | 
						|
 | 
						|
	for (current = start;
 | 
						|
	     current + sizeof(struct ospf6_network_lsdesc) <= end;
 | 
						|
	     current += sizeof(struct ospf6_network_lsdesc)) {
 | 
						|
		lsdesc = (struct ospf6_network_lsdesc *)current;
 | 
						|
		inet_ntop(AF_INET, &lsdesc->router_id, buf, sizeof(buf));
 | 
						|
		if (use_json)
 | 
						|
			json_object_array_add(json_arr,
 | 
						|
					      json_object_new_string(buf));
 | 
						|
		else
 | 
						|
			vty_out(vty, "     Attached Router: %s\n", buf);
 | 
						|
	}
 | 
						|
	if (use_json)
 | 
						|
		json_object_object_add(json_obj, "attachedRouter", json_arr);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_network_lsa_originate(struct event *thread)
 | 
						|
{
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
 | 
						|
	char buffer[OSPF6_MAX_LSASIZE];
 | 
						|
	struct ospf6_lsa_header *lsa_header;
 | 
						|
 | 
						|
	int count;
 | 
						|
	struct ospf6_lsa *old, *lsa;
 | 
						|
	struct ospf6_network_lsa *network_lsa;
 | 
						|
	struct ospf6_network_lsdesc *lsdesc;
 | 
						|
	struct ospf6_neighbor *on;
 | 
						|
	struct ospf6_link_lsa *link_lsa;
 | 
						|
	struct listnode *i;
 | 
						|
	uint16_t type;
 | 
						|
 | 
						|
	oi = (struct ospf6_interface *)EVENT_ARG(thread);
 | 
						|
 | 
						|
	/* The interface must be enabled until here. A Network-LSA of a
 | 
						|
	   disabled interface (but was once enabled) should be flushed
 | 
						|
	   by ospf6_lsa_refresh (), and does not come here. */
 | 
						|
	assert(oi->area);
 | 
						|
 | 
						|
	if (oi->area->ospf6->gr_info.restart_in_progress) {
 | 
						|
		if (IS_DEBUG_OSPF6_GR)
 | 
						|
			zlog_debug(
 | 
						|
				"Graceful Restart in progress, don't originate LSA");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK),
 | 
						|
				htonl(oi->interface->ifindex),
 | 
						|
				oi->area->ospf6->router_id, oi->area->lsdb);
 | 
						|
 | 
						|
	/* Do not originate Network-LSA if not DR */
 | 
						|
	if (oi->state != OSPF6_INTERFACE_DR) {
 | 
						|
		if (old) {
 | 
						|
			ospf6_lsa_purge(old);
 | 
						|
			/*
 | 
						|
			 * Waiting till the LSA is actually removed from the
 | 
						|
			 * database to
 | 
						|
			 * trigger SPF delays network convergence.
 | 
						|
			 */
 | 
						|
			ospf6_spf_schedule(
 | 
						|
				oi->area->ospf6,
 | 
						|
				OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED);
 | 
						|
		}
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ORIGINATE(NETWORK))
 | 
						|
		zlog_debug("Originate Network-LSA for Interface %s",
 | 
						|
			   oi->interface->name);
 | 
						|
 | 
						|
	/* If none of neighbor is adjacent to us */
 | 
						|
	count = 0;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, i, on))
 | 
						|
		if (on->state == OSPF6_NEIGHBOR_FULL)
 | 
						|
			count++;
 | 
						|
 | 
						|
	if (count == 0) {
 | 
						|
		if (IS_OSPF6_DEBUG_ORIGINATE(NETWORK))
 | 
						|
			zlog_debug("Interface stub, ignore");
 | 
						|
		if (old)
 | 
						|
			ospf6_lsa_purge(old);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* prepare buffer */
 | 
						|
	memset(buffer, 0, sizeof(buffer));
 | 
						|
	lsa_header = (struct ospf6_lsa_header *)buffer;
 | 
						|
	network_lsa =
 | 
						|
		(struct ospf6_network_lsa *)((caddr_t)lsa_header
 | 
						|
					     + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
	/* Collect the interface's Link-LSAs to describe
 | 
						|
	   network's optional capabilities */
 | 
						|
	type = htons(OSPF6_LSTYPE_LINK);
 | 
						|
	for (ALL_LSDB_TYPED(oi->lsdb, type, lsa)) {
 | 
						|
		link_lsa = (struct ospf6_link_lsa
 | 
						|
				    *)((caddr_t)lsa->header
 | 
						|
				       + sizeof(struct ospf6_lsa_header));
 | 
						|
		network_lsa->options[0] |= link_lsa->options[0];
 | 
						|
		network_lsa->options[1] |= link_lsa->options[1];
 | 
						|
		network_lsa->options[2] |= link_lsa->options[2];
 | 
						|
	}
 | 
						|
 | 
						|
	lsdesc = (struct ospf6_network_lsdesc
 | 
						|
			  *)((caddr_t)network_lsa
 | 
						|
			     + sizeof(struct ospf6_network_lsa));
 | 
						|
 | 
						|
	/* set Link Description to the router itself */
 | 
						|
	lsdesc->router_id = oi->area->ospf6->router_id;
 | 
						|
	lsdesc++;
 | 
						|
 | 
						|
	/* Walk through the neighbors */
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, i, on)) {
 | 
						|
		if (on->state != OSPF6_NEIGHBOR_FULL)
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* set this neighbor's Router-ID to LSA */
 | 
						|
		lsdesc->router_id = on->router_id;
 | 
						|
		lsdesc++;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Fill LSA Header */
 | 
						|
	lsa_header->age = 0;
 | 
						|
	lsa_header->type = htons(OSPF6_LSTYPE_NETWORK);
 | 
						|
	lsa_header->id = htonl(oi->interface->ifindex);
 | 
						|
	lsa_header->adv_router = oi->area->ospf6->router_id;
 | 
						|
	lsa_header->seqnum =
 | 
						|
		ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
 | 
						|
				    lsa_header->adv_router, oi->area->lsdb);
 | 
						|
	lsa_header->length = htons((caddr_t)lsdesc - (caddr_t)buffer);
 | 
						|
 | 
						|
	/* LSA checksum */
 | 
						|
	ospf6_lsa_checksum(lsa_header);
 | 
						|
 | 
						|
	/* create LSA */
 | 
						|
	lsa = ospf6_lsa_create(lsa_header);
 | 
						|
 | 
						|
	/* Originate */
 | 
						|
	ospf6_lsa_originate_area(lsa, oi->area);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/****************************/
 | 
						|
/* RFC2740 3.4.3.6 Link-LSA */
 | 
						|
/****************************/
 | 
						|
 | 
						|
static char *ospf6_link_lsa_get_prefix_str(struct ospf6_lsa *lsa, char *buf,
 | 
						|
					   int buflen, int pos)
 | 
						|
{
 | 
						|
	char *start, *end, *current;
 | 
						|
	struct ospf6_link_lsa *link_lsa;
 | 
						|
	struct in6_addr in6;
 | 
						|
	struct ospf6_prefix *prefix;
 | 
						|
	int cnt = 0, prefixnum;
 | 
						|
 | 
						|
	if (lsa) {
 | 
						|
		link_lsa = (struct ospf6_link_lsa
 | 
						|
				    *)((caddr_t)lsa->header
 | 
						|
				       + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
		if (pos == 0) {
 | 
						|
			inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf,
 | 
						|
				  buflen);
 | 
						|
			return (buf);
 | 
						|
		}
 | 
						|
 | 
						|
		prefixnum = ntohl(link_lsa->prefix_num);
 | 
						|
		if (pos > prefixnum)
 | 
						|
			return NULL;
 | 
						|
 | 
						|
		start = (char *)link_lsa + sizeof(struct ospf6_link_lsa);
 | 
						|
		end = (char *)lsa->header + ntohs(lsa->header->length);
 | 
						|
		current = start;
 | 
						|
 | 
						|
		while (current + sizeof(struct ospf6_prefix) <= end) {
 | 
						|
			prefix = (struct ospf6_prefix *)current;
 | 
						|
			if (prefix->prefix_length == 0
 | 
						|
			    || current + OSPF6_PREFIX_SIZE(prefix) > end) {
 | 
						|
				return NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			if (cnt < (pos - 1)) {
 | 
						|
				current += OSPF6_PREFIX_SIZE(prefix);
 | 
						|
				cnt++;
 | 
						|
			} else {
 | 
						|
				memset(&in6, 0, sizeof(in6));
 | 
						|
				memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
 | 
						|
				       OSPF6_PREFIX_SPACE(
 | 
						|
					       prefix->prefix_length));
 | 
						|
				inet_ntop(AF_INET6, &in6, buf, buflen);
 | 
						|
				return (buf);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
 | 
						|
			       json_object *json_obj, bool use_json)
 | 
						|
{
 | 
						|
	char *start, *end, *current;
 | 
						|
	struct ospf6_link_lsa *link_lsa;
 | 
						|
	int prefixnum;
 | 
						|
	char buf[128], options[32];
 | 
						|
	struct ospf6_prefix *prefix;
 | 
						|
	struct in6_addr in6;
 | 
						|
	json_object *json_loop;
 | 
						|
	json_object *json_arr = NULL;
 | 
						|
	char prefix_string[133];
 | 
						|
 | 
						|
	link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsa->header
 | 
						|
					     + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
	ospf6_options_printbuf(link_lsa->options, options, sizeof(options));
 | 
						|
	inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf, sizeof(buf));
 | 
						|
	prefixnum = ntohl(link_lsa->prefix_num);
 | 
						|
 | 
						|
	if (use_json) {
 | 
						|
		json_arr = json_object_new_array();
 | 
						|
		json_object_int_add(json_obj, "priority", link_lsa->priority);
 | 
						|
		json_object_string_add(json_obj, "options", options);
 | 
						|
		json_object_string_add(json_obj, "linkLocalAddress", buf);
 | 
						|
		json_object_int_add(json_obj, "numberOfPrefix", prefixnum);
 | 
						|
	} else {
 | 
						|
		vty_out(vty, "     Priority: %d Options: %s\n",
 | 
						|
			link_lsa->priority, options);
 | 
						|
		vty_out(vty, "     LinkLocal Address: %s\n", buf);
 | 
						|
		vty_out(vty, "     Number of Prefix: %d\n", prefixnum);
 | 
						|
	}
 | 
						|
 | 
						|
	start = (char *)link_lsa + sizeof(struct ospf6_link_lsa);
 | 
						|
	end = (char *)lsa->header + ntohs(lsa->header->length);
 | 
						|
	for (current = start; current < end;
 | 
						|
	     current += OSPF6_PREFIX_SIZE(prefix)) {
 | 
						|
		prefix = (struct ospf6_prefix *)current;
 | 
						|
		if (prefix->prefix_length == 0
 | 
						|
		    || current + OSPF6_PREFIX_SIZE(prefix) > end)
 | 
						|
			break;
 | 
						|
 | 
						|
		ospf6_prefix_options_printbuf(prefix->prefix_options, buf,
 | 
						|
					      sizeof(buf));
 | 
						|
		if (use_json) {
 | 
						|
			json_loop = json_object_new_object();
 | 
						|
			json_object_string_add(json_loop, "prefixOption", buf);
 | 
						|
		} else
 | 
						|
			vty_out(vty, "     Prefix Options: %s\n", buf);
 | 
						|
 | 
						|
		memset(&in6, 0, sizeof(in6));
 | 
						|
		memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
 | 
						|
		       OSPF6_PREFIX_SPACE(prefix->prefix_length));
 | 
						|
		inet_ntop(AF_INET6, &in6, buf, sizeof(buf));
 | 
						|
		if (use_json) {
 | 
						|
			snprintf(prefix_string, sizeof(prefix_string), "%s/%d",
 | 
						|
				 buf, prefix->prefix_length);
 | 
						|
			json_object_string_add(json_loop, "prefix",
 | 
						|
					       prefix_string);
 | 
						|
			json_object_array_add(json_arr, json_loop);
 | 
						|
		} else
 | 
						|
			vty_out(vty, "     Prefix: %s/%d\n", buf,
 | 
						|
				prefix->prefix_length);
 | 
						|
	}
 | 
						|
	if (use_json)
 | 
						|
		json_object_object_add(json_obj, "prefix", json_arr);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_link_lsa_originate(struct event *thread)
 | 
						|
{
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
 | 
						|
	char buffer[OSPF6_MAX_LSASIZE];
 | 
						|
	struct ospf6_lsa_header *lsa_header;
 | 
						|
	struct ospf6_lsa *old, *lsa;
 | 
						|
 | 
						|
	struct ospf6_link_lsa *link_lsa;
 | 
						|
	struct ospf6_route *route;
 | 
						|
	struct ospf6_prefix *op;
 | 
						|
 | 
						|
	oi = (struct ospf6_interface *)EVENT_ARG(thread);
 | 
						|
 | 
						|
	assert(oi->area);
 | 
						|
 | 
						|
	if (oi->area->ospf6->gr_info.restart_in_progress) {
 | 
						|
		if (IS_DEBUG_OSPF6_GR)
 | 
						|
			zlog_debug(
 | 
						|
				"Graceful Restart in progress, don't originate LSA");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	/* find previous LSA */
 | 
						|
	old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_LINK),
 | 
						|
				htonl(oi->interface->ifindex),
 | 
						|
				oi->area->ospf6->router_id, oi->lsdb);
 | 
						|
 | 
						|
	if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
 | 
						|
		if (old)
 | 
						|
			ospf6_lsa_purge(old);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
 | 
						|
		zlog_debug("Originate Link-LSA for Interface %s",
 | 
						|
			   oi->interface->name);
 | 
						|
 | 
						|
	/* can't make Link-LSA if linklocal address not set */
 | 
						|
	if (oi->linklocal_addr == NULL) {
 | 
						|
		if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
 | 
						|
			zlog_debug(
 | 
						|
				"No Linklocal address on %s, defer originating",
 | 
						|
				oi->interface->name);
 | 
						|
		if (old)
 | 
						|
			ospf6_lsa_purge(old);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* prepare buffer */
 | 
						|
	memset(buffer, 0, sizeof(buffer));
 | 
						|
	lsa_header = (struct ospf6_lsa_header *)buffer;
 | 
						|
	link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsa_header
 | 
						|
					     + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
	/* Fill Link-LSA */
 | 
						|
	link_lsa->priority = oi->priority;
 | 
						|
	memcpy(link_lsa->options, oi->area->options, 3);
 | 
						|
	memcpy(&link_lsa->linklocal_addr, oi->linklocal_addr,
 | 
						|
	       sizeof(struct in6_addr));
 | 
						|
	link_lsa->prefix_num = htonl(oi->route_connected->count);
 | 
						|
 | 
						|
	op = (struct ospf6_prefix *)((caddr_t)link_lsa
 | 
						|
				     + sizeof(struct ospf6_link_lsa));
 | 
						|
 | 
						|
	/* connected prefix to advertise */
 | 
						|
	for (route = ospf6_route_head(oi->route_connected); route;
 | 
						|
	     route = ospf6_route_next(route)) {
 | 
						|
		op->prefix_length = route->prefix.prefixlen;
 | 
						|
		op->prefix_options = route->prefix_options;
 | 
						|
		op->prefix_metric = htons(0);
 | 
						|
		memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6,
 | 
						|
		       OSPF6_PREFIX_SPACE(op->prefix_length));
 | 
						|
		op = OSPF6_PREFIX_NEXT(op);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Fill LSA Header */
 | 
						|
	lsa_header->age = 0;
 | 
						|
	lsa_header->type = htons(OSPF6_LSTYPE_LINK);
 | 
						|
	lsa_header->id = htonl(oi->interface->ifindex);
 | 
						|
	lsa_header->adv_router = oi->area->ospf6->router_id;
 | 
						|
	lsa_header->seqnum =
 | 
						|
		ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
 | 
						|
				    lsa_header->adv_router, oi->lsdb);
 | 
						|
	lsa_header->length = htons((caddr_t)op - (caddr_t)buffer);
 | 
						|
 | 
						|
	/* LSA checksum */
 | 
						|
	ospf6_lsa_checksum(lsa_header);
 | 
						|
 | 
						|
	/* create LSA */
 | 
						|
	lsa = ospf6_lsa_create(lsa_header);
 | 
						|
 | 
						|
	/* Originate */
 | 
						|
	ospf6_lsa_originate_interface(lsa, oi);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*****************************************/
 | 
						|
/* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */
 | 
						|
/*****************************************/
 | 
						|
static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa,
 | 
						|
						   char *buf, int buflen,
 | 
						|
						   int pos)
 | 
						|
{
 | 
						|
	char *start, *end, *current;
 | 
						|
	struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
 | 
						|
	struct in6_addr in6;
 | 
						|
	int prefixnum, cnt = 0;
 | 
						|
	struct ospf6_prefix *prefix;
 | 
						|
	char tbuf[16];
 | 
						|
 | 
						|
	if (lsa) {
 | 
						|
		intra_prefix_lsa =
 | 
						|
			(struct ospf6_intra_prefix_lsa
 | 
						|
				 *)((caddr_t)lsa->header
 | 
						|
				    + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
		prefixnum = ntohs(intra_prefix_lsa->prefix_num);
 | 
						|
		if ((pos + 1) > prefixnum)
 | 
						|
			return NULL;
 | 
						|
 | 
						|
		start = (char *)intra_prefix_lsa
 | 
						|
			+ sizeof(struct ospf6_intra_prefix_lsa);
 | 
						|
		end = (char *)lsa->header + ntohs(lsa->header->length);
 | 
						|
		current = start;
 | 
						|
 | 
						|
		while (current + sizeof(struct ospf6_prefix) <= end) {
 | 
						|
			prefix = (struct ospf6_prefix *)current;
 | 
						|
			if (prefix->prefix_length == 0
 | 
						|
			    || current + OSPF6_PREFIX_SIZE(prefix) > end) {
 | 
						|
				return NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			if (cnt < pos) {
 | 
						|
				current += OSPF6_PREFIX_SIZE(prefix);
 | 
						|
				cnt++;
 | 
						|
			} else {
 | 
						|
				memset(&in6, 0, sizeof(in6));
 | 
						|
				memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
 | 
						|
				       OSPF6_PREFIX_SPACE(
 | 
						|
					       prefix->prefix_length));
 | 
						|
				inet_ntop(AF_INET6, &in6, buf, buflen);
 | 
						|
				snprintf(tbuf, sizeof(tbuf), "/%d",
 | 
						|
					 prefix->prefix_length);
 | 
						|
				strlcat(buf, tbuf, buflen);
 | 
						|
				return (buf);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
 | 
						|
				       json_object *json_obj, bool use_json)
 | 
						|
{
 | 
						|
	char *start, *end, *current;
 | 
						|
	struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
 | 
						|
	int prefixnum;
 | 
						|
	char buf[128];
 | 
						|
	struct ospf6_prefix *prefix;
 | 
						|
	char id[16], adv_router[16];
 | 
						|
	struct in6_addr in6;
 | 
						|
	json_object *json_loop;
 | 
						|
	json_object *json_arr = NULL;
 | 
						|
	char prefix_string[133];
 | 
						|
 | 
						|
	intra_prefix_lsa = (struct ospf6_intra_prefix_lsa
 | 
						|
				    *)((caddr_t)lsa->header
 | 
						|
				       + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
	prefixnum = ntohs(intra_prefix_lsa->prefix_num);
 | 
						|
 | 
						|
	if (use_json) {
 | 
						|
		json_arr = json_object_new_array();
 | 
						|
		json_object_int_add(json_obj, "numberOfPrefix", prefixnum);
 | 
						|
	} else
 | 
						|
		vty_out(vty, "     Number of Prefix: %d\n", prefixnum);
 | 
						|
 | 
						|
	inet_ntop(AF_INET, &intra_prefix_lsa->ref_id, id, sizeof(id));
 | 
						|
	inet_ntop(AF_INET, &intra_prefix_lsa->ref_adv_router, adv_router,
 | 
						|
		  sizeof(adv_router));
 | 
						|
	if (use_json) {
 | 
						|
		json_object_string_add(
 | 
						|
			json_obj, "reference",
 | 
						|
			ospf6_lstype_name(intra_prefix_lsa->ref_type));
 | 
						|
		json_object_string_add(json_obj, "referenceId", id);
 | 
						|
		json_object_string_add(json_obj, "referenceAdv", adv_router);
 | 
						|
	} else
 | 
						|
		vty_out(vty, "     Reference: %s Id: %s Adv: %s\n",
 | 
						|
			ospf6_lstype_name(intra_prefix_lsa->ref_type), id,
 | 
						|
			adv_router);
 | 
						|
 | 
						|
	start = (char *)intra_prefix_lsa
 | 
						|
		+ sizeof(struct ospf6_intra_prefix_lsa);
 | 
						|
	end = (char *)lsa->header + ntohs(lsa->header->length);
 | 
						|
	for (current = start; current < end;
 | 
						|
	     current += OSPF6_PREFIX_SIZE(prefix)) {
 | 
						|
		prefix = (struct ospf6_prefix *)current;
 | 
						|
		if (prefix->prefix_length == 0
 | 
						|
		    || current + OSPF6_PREFIX_SIZE(prefix) > end)
 | 
						|
			break;
 | 
						|
 | 
						|
		ospf6_prefix_options_printbuf(prefix->prefix_options, buf,
 | 
						|
					      sizeof(buf));
 | 
						|
		if (use_json) {
 | 
						|
			json_loop = json_object_new_object();
 | 
						|
			json_object_string_add(json_loop, "prefixOption", buf);
 | 
						|
		} else
 | 
						|
			vty_out(vty, "     Prefix Options: %s\n", buf);
 | 
						|
 | 
						|
		memset(&in6, 0, sizeof(in6));
 | 
						|
		memcpy(&in6, OSPF6_PREFIX_BODY(prefix),
 | 
						|
		       OSPF6_PREFIX_SPACE(prefix->prefix_length));
 | 
						|
		inet_ntop(AF_INET6, &in6, buf, sizeof(buf));
 | 
						|
		if (use_json) {
 | 
						|
			snprintf(prefix_string, sizeof(prefix_string), "%s/%d",
 | 
						|
				 buf, prefix->prefix_length);
 | 
						|
			json_object_string_add(json_loop, "prefix",
 | 
						|
					       prefix_string);
 | 
						|
			json_object_int_add(json_loop, "metric",
 | 
						|
					    ntohs(prefix->prefix_metric));
 | 
						|
			json_object_array_add(json_arr, json_loop);
 | 
						|
		} else {
 | 
						|
			vty_out(vty, "     Prefix: %s/%d\n", buf,
 | 
						|
				prefix->prefix_length);
 | 
						|
			vty_out(vty, "     Metric: %d\n",
 | 
						|
				ntohs(prefix->prefix_metric));
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (use_json)
 | 
						|
		json_object_object_add(json_obj, "prefix", json_arr);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_intra_prefix_lsa_originate_stub(struct event *thread)
 | 
						|
{
 | 
						|
	struct ospf6_area *oa;
 | 
						|
 | 
						|
	char buffer[OSPF6_MAX_LSASIZE];
 | 
						|
	struct ospf6_lsa_header *lsa_header;
 | 
						|
	struct ospf6_lsa *old, *lsa, *old_next = NULL;
 | 
						|
 | 
						|
	struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
	struct ospf6_neighbor *on;
 | 
						|
	struct ospf6_route *route;
 | 
						|
	struct ospf6_prefix *op;
 | 
						|
	struct listnode *i, *j;
 | 
						|
	int full_count = 0;
 | 
						|
	unsigned short prefix_num = 0;
 | 
						|
	struct ospf6_route_table *route_advertise;
 | 
						|
	int ls_id = 0;
 | 
						|
 | 
						|
	oa = (struct ospf6_area *)EVENT_ARG(thread);
 | 
						|
 | 
						|
	if (oa->ospf6->gr_info.restart_in_progress) {
 | 
						|
		if (IS_DEBUG_OSPF6_GR)
 | 
						|
			zlog_debug(
 | 
						|
				"Graceful Restart in progress, don't originate LSA");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* find previous LSA */
 | 
						|
	old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_INTRA_PREFIX), htonl(0),
 | 
						|
				oa->ospf6->router_id, oa->lsdb);
 | 
						|
 | 
						|
	if (!IS_AREA_ENABLED(oa)) {
 | 
						|
		if (old) {
 | 
						|
			ospf6_lsa_purge(old);
 | 
						|
			/* find previous LSA */
 | 
						|
			old_next = ospf6_lsdb_lookup(
 | 
						|
				htons(OSPF6_LSTYPE_INTRA_PREFIX),
 | 
						|
				htonl(++ls_id), oa->ospf6->router_id, oa->lsdb);
 | 
						|
 | 
						|
			while (old_next) {
 | 
						|
				ospf6_lsa_purge(old_next);
 | 
						|
				old_next = ospf6_lsdb_lookup(
 | 
						|
					htons(OSPF6_LSTYPE_INTRA_PREFIX),
 | 
						|
					htonl(++ls_id), oa->ospf6->router_id,
 | 
						|
					oa->lsdb);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
		zlog_debug(
 | 
						|
			"Originate Intra-Area-Prefix-LSA for area %s's stub prefix",
 | 
						|
			oa->name);
 | 
						|
 | 
						|
	/* prepare buffer */
 | 
						|
	memset(buffer, 0, sizeof(buffer));
 | 
						|
	lsa_header = (struct ospf6_lsa_header *)buffer;
 | 
						|
	intra_prefix_lsa = (struct ospf6_intra_prefix_lsa
 | 
						|
				    *)((caddr_t)lsa_header
 | 
						|
				       + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
	/* Fill Intra-Area-Prefix-LSA */
 | 
						|
	intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_ROUTER);
 | 
						|
	intra_prefix_lsa->ref_id = htonl(0);
 | 
						|
	intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id;
 | 
						|
 | 
						|
	route_advertise = ospf6_route_table_create(0, 0);
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(oa->if_list, i, oi)) {
 | 
						|
		if (oi->state == OSPF6_INTERFACE_DOWN) {
 | 
						|
			if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
				zlog_debug("  Interface %s is down, ignore",
 | 
						|
					   oi->interface->name);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		full_count = 0;
 | 
						|
 | 
						|
		for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on))
 | 
						|
			if (on->state == OSPF6_NEIGHBOR_FULL)
 | 
						|
				full_count++;
 | 
						|
 | 
						|
		if (oi->state != OSPF6_INTERFACE_LOOPBACK
 | 
						|
		    && oi->state != OSPF6_INTERFACE_POINTTOPOINT
 | 
						|
		    && full_count != 0) {
 | 
						|
			if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
				zlog_debug("  Interface %s is not stub, ignore",
 | 
						|
					   oi->interface->name);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
			zlog_debug("  Interface %s:", oi->interface->name);
 | 
						|
 | 
						|
		/* connected prefix to advertise */
 | 
						|
		for (route = ospf6_route_head(oi->route_connected); route;
 | 
						|
		     route = ospf6_route_best_next(route)) {
 | 
						|
			if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
				zlog_debug("    include %pFX", &route->prefix);
 | 
						|
			ospf6_route_add(ospf6_route_copy(route),
 | 
						|
					route_advertise);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (route_advertise->count == 0) {
 | 
						|
		if (old) {
 | 
						|
			ls_id = 0;
 | 
						|
			ospf6_lsa_purge(old);
 | 
						|
			/* find previous LSA */
 | 
						|
			old_next = ospf6_lsdb_lookup(
 | 
						|
				htons(OSPF6_LSTYPE_INTRA_PREFIX),
 | 
						|
				htonl(++ls_id), oa->ospf6->router_id, oa->lsdb);
 | 
						|
 | 
						|
			while (old_next) {
 | 
						|
				ospf6_lsa_purge(old_next);
 | 
						|
				old_next = ospf6_lsdb_lookup(
 | 
						|
					htons(OSPF6_LSTYPE_INTRA_PREFIX),
 | 
						|
					htonl(++ls_id), oa->ospf6->router_id,
 | 
						|
					oa->lsdb);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		ospf6_route_table_delete(route_advertise);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Neighbor change to FULL, if INTRA-AREA-PREFIX LSA
 | 
						|
	 * has not change, Flush old LSA and Re-Originate INP,
 | 
						|
	 * as ospf6_flood() checks if LSA is same as DB,
 | 
						|
	 * it won't be updated to neighbor's DB.
 | 
						|
	 */
 | 
						|
	if (oa->intra_prefix_originate) {
 | 
						|
		if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
			zlog_debug(
 | 
						|
				"%s: Re-originate intra prefix LSA, Current full nbrs %u",
 | 
						|
				__func__, oa->full_nbrs);
 | 
						|
		if (old)
 | 
						|
			ospf6_lsa_purge_multi_ls_id(oa, old);
 | 
						|
		oa->intra_prefix_originate = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* put prefixes to advertise */
 | 
						|
	prefix_num = 0;
 | 
						|
	op = (struct ospf6_prefix *)((caddr_t)intra_prefix_lsa
 | 
						|
				     + sizeof(struct ospf6_intra_prefix_lsa));
 | 
						|
	for (route = ospf6_route_head(route_advertise); route;
 | 
						|
	     route = ospf6_route_best_next(route)) {
 | 
						|
		if (((caddr_t)op - (caddr_t)lsa_header) > MAX_LSA_PAYLOAD) {
 | 
						|
 | 
						|
			intra_prefix_lsa->prefix_num = htons(prefix_num);
 | 
						|
 | 
						|
			/* Fill LSA Header */
 | 
						|
			lsa_header->age = 0;
 | 
						|
			lsa_header->type = htons(OSPF6_LSTYPE_INTRA_PREFIX);
 | 
						|
			lsa_header->id = htonl(ls_id++);
 | 
						|
			lsa_header->adv_router = oa->ospf6->router_id;
 | 
						|
			lsa_header->seqnum = ospf6_new_ls_seqnum(
 | 
						|
				lsa_header->type, lsa_header->id,
 | 
						|
				lsa_header->adv_router, oa->lsdb);
 | 
						|
			lsa_header->length =
 | 
						|
				htons((caddr_t)op - (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, oa);
 | 
						|
 | 
						|
			/* Prepare next buffer */
 | 
						|
			memset(buffer, 0, sizeof(buffer));
 | 
						|
			lsa_header = (struct ospf6_lsa_header *)buffer;
 | 
						|
			intra_prefix_lsa =
 | 
						|
				(struct ospf6_intra_prefix_lsa
 | 
						|
					 *)((caddr_t)lsa_header
 | 
						|
					    + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
			/* Fill Intra-Area-Prefix-LSA */
 | 
						|
			intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_ROUTER);
 | 
						|
			intra_prefix_lsa->ref_id = htonl(0);
 | 
						|
			intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id;
 | 
						|
 | 
						|
			/* Put next set of prefixes to advertise */
 | 
						|
			prefix_num = 0;
 | 
						|
			op = (struct ospf6_prefix
 | 
						|
				      *)((caddr_t)intra_prefix_lsa
 | 
						|
					 + sizeof(struct
 | 
						|
						  ospf6_intra_prefix_lsa));
 | 
						|
		}
 | 
						|
 | 
						|
		op->prefix_length = route->prefix.prefixlen;
 | 
						|
		op->prefix_options = route->prefix_options;
 | 
						|
		op->prefix_metric = htons(route->path.cost);
 | 
						|
		memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6,
 | 
						|
		       OSPF6_PREFIX_SPACE(op->prefix_length));
 | 
						|
		prefix_num++;
 | 
						|
 | 
						|
		op = OSPF6_PREFIX_NEXT(op);
 | 
						|
	}
 | 
						|
 | 
						|
	ospf6_route_table_delete(route_advertise);
 | 
						|
 | 
						|
	if (prefix_num == 0) {
 | 
						|
		if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
			zlog_debug(
 | 
						|
				"Quit to Advertise Intra-Prefix: no route to advertise");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	intra_prefix_lsa->prefix_num = htons(prefix_num);
 | 
						|
 | 
						|
	/* Fill LSA Header */
 | 
						|
	lsa_header->age = 0;
 | 
						|
	lsa_header->type = htons(OSPF6_LSTYPE_INTRA_PREFIX);
 | 
						|
	lsa_header->id = htonl(ls_id++);
 | 
						|
	lsa_header->adv_router = oa->ospf6->router_id;
 | 
						|
	lsa_header->seqnum =
 | 
						|
		ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
 | 
						|
				    lsa_header->adv_router, oa->lsdb);
 | 
						|
	lsa_header->length = htons((caddr_t)op - (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, oa);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void ospf6_intra_prefix_lsa_originate_transit(struct event *thread)
 | 
						|
{
 | 
						|
	struct ospf6_interface *oi;
 | 
						|
 | 
						|
	char buffer[OSPF6_MAX_LSASIZE];
 | 
						|
	struct ospf6_lsa_header *lsa_header;
 | 
						|
	struct ospf6_lsa *old, *lsa;
 | 
						|
 | 
						|
	struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
 | 
						|
	struct ospf6_neighbor *on;
 | 
						|
	struct ospf6_route *route;
 | 
						|
	struct ospf6_prefix *op;
 | 
						|
	struct listnode *i;
 | 
						|
	int full_count = 0;
 | 
						|
	unsigned short prefix_num = 0;
 | 
						|
	struct ospf6_route_table *route_advertise;
 | 
						|
	struct ospf6_link_lsa *link_lsa;
 | 
						|
	char *start, *end, *current;
 | 
						|
	uint16_t type;
 | 
						|
 | 
						|
	oi = (struct ospf6_interface *)EVENT_ARG(thread);
 | 
						|
 | 
						|
	assert(oi->area);
 | 
						|
 | 
						|
	if (oi->area->ospf6->gr_info.restart_in_progress) {
 | 
						|
		if (IS_DEBUG_OSPF6_GR)
 | 
						|
			zlog_debug(
 | 
						|
				"Graceful Restart in progress, don't originate LSA");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* find previous LSA */
 | 
						|
	old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_INTRA_PREFIX),
 | 
						|
				htonl(oi->interface->ifindex),
 | 
						|
				oi->area->ospf6->router_id, oi->area->lsdb);
 | 
						|
 | 
						|
	if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
 | 
						|
		if (old)
 | 
						|
			ospf6_lsa_purge(old);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
		zlog_debug(
 | 
						|
			"Originate Intra-Area-Prefix-LSA for interface %s's prefix",
 | 
						|
			oi->interface->name);
 | 
						|
 | 
						|
	/* prepare buffer */
 | 
						|
	memset(buffer, 0, sizeof(buffer));
 | 
						|
	lsa_header = (struct ospf6_lsa_header *)buffer;
 | 
						|
	intra_prefix_lsa = (struct ospf6_intra_prefix_lsa
 | 
						|
				    *)((caddr_t)lsa_header
 | 
						|
				       + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
	/* Fill Intra-Area-Prefix-LSA */
 | 
						|
	intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_NETWORK);
 | 
						|
	intra_prefix_lsa->ref_id = htonl(oi->interface->ifindex);
 | 
						|
	intra_prefix_lsa->ref_adv_router = oi->area->ospf6->router_id;
 | 
						|
 | 
						|
	if (oi->state != OSPF6_INTERFACE_DR) {
 | 
						|
		if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
			zlog_debug("  Interface is not DR");
 | 
						|
		if (old)
 | 
						|
			ospf6_lsa_purge(old);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	full_count = 0;
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, i, on))
 | 
						|
		if (on->state == OSPF6_NEIGHBOR_FULL)
 | 
						|
			full_count++;
 | 
						|
 | 
						|
	if (full_count == 0) {
 | 
						|
		if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
			zlog_debug("  Interface is stub");
 | 
						|
		if (old)
 | 
						|
			ospf6_lsa_purge(old);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* connected prefix to advertise */
 | 
						|
	route_advertise = ospf6_route_table_create(0, 0);
 | 
						|
 | 
						|
	type = ntohs(OSPF6_LSTYPE_LINK);
 | 
						|
	for (ALL_LSDB_TYPED(oi->lsdb, type, lsa)) {
 | 
						|
		if (OSPF6_LSA_IS_MAXAGE(lsa))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
			zlog_debug("  include prefix from %s", lsa->name);
 | 
						|
 | 
						|
		if (lsa->header->adv_router != oi->area->ospf6->router_id) {
 | 
						|
			on = ospf6_neighbor_lookup(lsa->header->adv_router, oi);
 | 
						|
			if (on == NULL || on->state != OSPF6_NEIGHBOR_FULL) {
 | 
						|
				if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
					zlog_debug(
 | 
						|
						"    Neighbor not found or not Full, ignore");
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		link_lsa = (struct ospf6_link_lsa
 | 
						|
				    *)((caddr_t)lsa->header
 | 
						|
				       + sizeof(struct ospf6_lsa_header));
 | 
						|
 | 
						|
		prefix_num = (unsigned short)ntohl(link_lsa->prefix_num);
 | 
						|
		start = (char *)link_lsa + sizeof(struct ospf6_link_lsa);
 | 
						|
		end = (char *)lsa->header + ntohs(lsa->header->length);
 | 
						|
		for (current = start; current < end && prefix_num;
 | 
						|
		     current += OSPF6_PREFIX_SIZE(op)) {
 | 
						|
			op = (struct ospf6_prefix *)current;
 | 
						|
			if (op->prefix_length == 0
 | 
						|
			    || current + OSPF6_PREFIX_SIZE(op) > end)
 | 
						|
				break;
 | 
						|
 | 
						|
			route = ospf6_route_create(oi->area->ospf6);
 | 
						|
 | 
						|
			route->type = OSPF6_DEST_TYPE_NETWORK;
 | 
						|
			route->prefix.family = AF_INET6;
 | 
						|
			route->prefix.prefixlen = op->prefix_length;
 | 
						|
			memset(&route->prefix.u.prefix6, 0,
 | 
						|
			       sizeof(struct in6_addr));
 | 
						|
			memcpy(&route->prefix.u.prefix6, OSPF6_PREFIX_BODY(op),
 | 
						|
			       OSPF6_PREFIX_SPACE(op->prefix_length));
 | 
						|
			route->prefix_options = op->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.options[0] = link_lsa->options[0];
 | 
						|
			route->path.options[1] = link_lsa->options[1];
 | 
						|
			route->path.options[2] = link_lsa->options[2];
 | 
						|
			route->path.area_id = oi->area->area_id;
 | 
						|
			route->path.type = OSPF6_PATH_TYPE_INTRA;
 | 
						|
 | 
						|
			if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
				zlog_debug("    include %pFX", &route->prefix);
 | 
						|
 | 
						|
			ospf6_route_add(route, route_advertise);
 | 
						|
			prefix_num--;
 | 
						|
		}
 | 
						|
		if (current != end && IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
			zlog_debug("Trailing garbage in %s", lsa->name);
 | 
						|
	}
 | 
						|
 | 
						|
	op = (struct ospf6_prefix *)((caddr_t)intra_prefix_lsa
 | 
						|
				     + sizeof(struct ospf6_intra_prefix_lsa));
 | 
						|
 | 
						|
	prefix_num = 0;
 | 
						|
	for (route = ospf6_route_head(route_advertise); route;
 | 
						|
	     route = ospf6_route_best_next(route)) {
 | 
						|
		op->prefix_length = route->prefix.prefixlen;
 | 
						|
		op->prefix_options = route->prefix_options;
 | 
						|
		op->prefix_metric = htons(0);
 | 
						|
		memcpy(OSPF6_PREFIX_BODY(op), &route->prefix.u.prefix6,
 | 
						|
		       OSPF6_PREFIX_SPACE(op->prefix_length));
 | 
						|
		op = OSPF6_PREFIX_NEXT(op);
 | 
						|
		prefix_num++;
 | 
						|
	}
 | 
						|
 | 
						|
	ospf6_route_table_delete(route_advertise);
 | 
						|
 | 
						|
	if (prefix_num == 0) {
 | 
						|
		if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX))
 | 
						|
			zlog_debug(
 | 
						|
				"Quit to Advertise Intra-Prefix: no route to advertise");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	intra_prefix_lsa->prefix_num = htons(prefix_num);
 | 
						|
 | 
						|
	/* Fill LSA Header */
 | 
						|
	lsa_header->age = 0;
 | 
						|
	lsa_header->type = htons(OSPF6_LSTYPE_INTRA_PREFIX);
 | 
						|
	lsa_header->id = htonl(oi->interface->ifindex);
 | 
						|
	lsa_header->adv_router = oi->area->ospf6->router_id;
 | 
						|
	lsa_header->seqnum =
 | 
						|
		ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
 | 
						|
				    lsa_header->adv_router, oi->area->lsdb);
 | 
						|
	lsa_header->length = htons((caddr_t)op - (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, oi->area);
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_intra_prefix_update_route_origin(struct ospf6_route *oa_route,
 | 
						|
						   struct ospf6 *ospf6)
 | 
						|
{
 | 
						|
	struct ospf6_path *h_path;
 | 
						|
	struct ospf6_route *g_route, *nroute;
 | 
						|
 | 
						|
	/* Update Global ospf6 route path */
 | 
						|
	g_route = ospf6_route_lookup(&oa_route->prefix, ospf6->route_table);
 | 
						|
 | 
						|
	assert(g_route);
 | 
						|
 | 
						|
	for (ospf6_route_lock(g_route); g_route &&
 | 
						|
	     ospf6_route_is_prefix(&oa_route->prefix, g_route);
 | 
						|
	     g_route = nroute) {
 | 
						|
		nroute = ospf6_route_next(g_route);
 | 
						|
		if (g_route->type != oa_route->type)
 | 
						|
			continue;
 | 
						|
		if (g_route->path.area_id != oa_route->path.area_id)
 | 
						|
			continue;
 | 
						|
		if (g_route->path.type != OSPF6_PATH_TYPE_INTRA)
 | 
						|
			continue;
 | 
						|
		if (g_route->path.cost != oa_route->path.cost)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (ospf6_route_is_same_origin(g_route, oa_route)) {
 | 
						|
			h_path = (struct ospf6_path *)listgetdata(
 | 
						|
				listhead(g_route->paths));
 | 
						|
			g_route->path.origin.type = h_path->origin.type;
 | 
						|
			g_route->path.origin.id = h_path->origin.id;
 | 
						|
			g_route->path.origin.adv_router =
 | 
						|
				h_path->origin.adv_router;
 | 
						|
			if (nroute)
 | 
						|
				ospf6_route_unlock(nroute);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	h_path = (struct ospf6_path *)listgetdata(
 | 
						|
				listhead(oa_route->paths));
 | 
						|
	oa_route->path.origin.type = h_path->origin.type;
 | 
						|
	oa_route->path.origin.id = h_path->origin.id;
 | 
						|
	oa_route->path.origin.adv_router = h_path->origin.adv_router;
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
 | 
						|
					struct ospf6_route *old,
 | 
						|
					struct ospf6_route *route)
 | 
						|
{
 | 
						|
	struct ospf6_route *old_route, *ls_entry;
 | 
						|
	struct ospf6_path *ecmp_path, *o_path = NULL;
 | 
						|
	struct listnode *anode, *anext;
 | 
						|
	struct listnode *nnode, *rnode, *rnext;
 | 
						|
	struct ospf6_nexthop *nh, *rnh;
 | 
						|
	bool route_found = false;
 | 
						|
	struct interface *ifp = NULL;
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
	struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
 | 
						|
 | 
						|
	/* check for old entry match with new route origin,
 | 
						|
	 * delete old entry.
 | 
						|
	 */
 | 
						|
	for (old_route = old; old_route; old_route = old_route->next) {
 | 
						|
		bool route_updated = false;
 | 
						|
 | 
						|
		/* 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->path.type != route->path.type)
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* Current and New route has same origin,
 | 
						|
		 * delete old entry.
 | 
						|
		 */
 | 
						|
		for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext,
 | 
						|
						  o_path)) {
 | 
						|
			/* Check old route path and route has same
 | 
						|
			 * origin.
 | 
						|
			 */
 | 
						|
			if (o_path->area_id != route->path.area_id
 | 
						|
			    || !ospf6_ls_origin_same(o_path, &route->path))
 | 
						|
				continue;
 | 
						|
 | 
						|
			/* Cost is not same then delete current path */
 | 
						|
			if (o_path->cost == route->path.cost)
 | 
						|
				continue;
 | 
						|
 | 
						|
			if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
 | 
						|
				zlog_debug(
 | 
						|
					"%s: route %pFX cost old %u new %u is not same, replace route",
 | 
						|
					__func__, &old_route->prefix, o_path->cost,
 | 
						|
					route->path.cost);
 | 
						|
			}
 | 
						|
 | 
						|
			/* Remove selected current path's nh from
 | 
						|
			 * effective nh list.
 | 
						|
			 */
 | 
						|
			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);
 | 
						|
					route_updated = true;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			listnode_delete(old_route->paths, o_path);
 | 
						|
			ospf6_path_free(o_path);
 | 
						|
 | 
						|
			/* Current route's path (adv_router info) is similar
 | 
						|
			 * to route being added.
 | 
						|
			 * Replace current route's path with paths list head.
 | 
						|
			 * Update FIB with effective NHs.
 | 
						|
			 */
 | 
						|
			if (listcount(old_route->paths)) {
 | 
						|
				if (route_updated) {
 | 
						|
					for (ALL_LIST_ELEMENTS(old_route->paths,
 | 
						|
							anode, anext, o_path)) {
 | 
						|
						ospf6_merge_nexthops(
 | 
						|
							old_route->nh_list,
 | 
						|
							o_path->nh_list);
 | 
						|
					}
 | 
						|
					/* Update ospf6 route table and
 | 
						|
					 * RIB/FIB with effective
 | 
						|
					 * nh_list
 | 
						|
					 */
 | 
						|
					if (oa->route_table->hook_add)
 | 
						|
						(*oa->route_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) {
 | 
						|
						ospf6_intra_prefix_update_route_origin(
 | 
						|
							old_route, oa->ospf6);
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
 | 
						|
					zlog_debug(
 | 
						|
						"%s: route %pFX old cost %u new cost %u, delete old entry.",
 | 
						|
						__func__, &old_route->prefix,
 | 
						|
						old_route->path.cost,
 | 
						|
						route->path.cost);
 | 
						|
				}
 | 
						|
				if (oa->route_table->hook_remove)
 | 
						|
					ospf6_route_remove(old_route,
 | 
						|
							   oa->route_table);
 | 
						|
				else
 | 
						|
					SET_FLAG(old_route->flag,
 | 
						|
						 OSPF6_ROUTE_REMOVE);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (route_updated)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	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->path.type != route->path.type)
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* Old Route and New Route have Equal Cost, Merge NHs */
 | 
						|
		if (old_route->path.cost == route->path.cost) {
 | 
						|
			route_found = true;
 | 
						|
 | 
						|
			/* check if this path exists already in
 | 
						|
			 * route->paths list, if so, replace nh_list.
 | 
						|
			 */
 | 
						|
			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;
 | 
						|
			}
 | 
						|
			/* If path is not found in old_route paths's list,
 | 
						|
			 * add a new path to route paths list and merge
 | 
						|
			 * nexthops in route->path->nh_list.
 | 
						|
			 * Otherwise replace existing path's nh_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_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
 | 
						|
					zlog_debug(
 | 
						|
						"%s: route %pFX %p another path added with nh %u, effective paths %u nh %u",
 | 
						|
						__func__, &route->prefix,
 | 
						|
						(void *)old_route,
 | 
						|
						listcount(ecmp_path->nh_list),
 | 
						|
						old_route->paths ? listcount(
 | 
						|
							old_route->paths)
 | 
						|
								 : 0,
 | 
						|
						listcount(old_route->nh_list));
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				list_delete_all_node(o_path->nh_list);
 | 
						|
				ospf6_copy_nexthops(o_path->nh_list,
 | 
						|
					    route->nh_list);
 | 
						|
 | 
						|
			}
 | 
						|
 | 
						|
			list_delete_all_node(old_route->nh_list);
 | 
						|
 | 
						|
			for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
 | 
						|
						  o_path)) {
 | 
						|
				ls_entry = ospf6_route_lookup(
 | 
						|
							&o_path->ls_prefix,
 | 
						|
							oa->spf_table);
 | 
						|
				if (ls_entry == NULL) {
 | 
						|
					if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
 | 
						|
						zlog_debug(
 | 
						|
							"%s: ls_prfix %pFX ls_entry not found.",
 | 
						|
							__func__,
 | 
						|
							&o_path->ls_prefix);
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
				lsa = ospf6_lsdb_lookup(o_path->origin.type,
 | 
						|
						o_path->origin.id,
 | 
						|
						o_path->origin.adv_router,
 | 
						|
						oa->lsdb);
 | 
						|
				if (lsa == NULL) {
 | 
						|
					if (IS_OSPF6_DEBUG_EXAMIN(
 | 
						|
								INTRA_PREFIX)) {
 | 
						|
						struct prefix adv_prefix;
 | 
						|
 | 
						|
						ospf6_linkstate_prefix(
 | 
						|
						o_path->origin.adv_router,
 | 
						|
						o_path->origin.id, &adv_prefix);
 | 
						|
						zlog_debug(
 | 
						|
							"%s: adv_router %pFX lsa not found",
 | 
						|
							__func__, &adv_prefix);
 | 
						|
					}
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
				intra_prefix_lsa =
 | 
						|
					(struct ospf6_intra_prefix_lsa *)
 | 
						|
					OSPF6_LSA_HEADER_END(lsa->header);
 | 
						|
 | 
						|
				if (intra_prefix_lsa->ref_adv_router
 | 
						|
				     == oa->ospf6->router_id) {
 | 
						|
					ifp = if_lookup_prefix(
 | 
						|
						&old_route->prefix,
 | 
						|
						oa->ospf6->vrf_id);
 | 
						|
				}
 | 
						|
 | 
						|
				if (ifp) {
 | 
						|
					/* Nexthop interface found */
 | 
						|
					ospf6_route_add_nexthop(old_route,
 | 
						|
								ifp->ifindex,
 | 
						|
								NULL);
 | 
						|
				} else {
 | 
						|
					/* The connected interfaces between
 | 
						|
					 * routers can be in different networks.
 | 
						|
					 * In this case the matching interface
 | 
						|
					 * is not found. Copy nexthops from the
 | 
						|
					 * link state entry
 | 
						|
					 */
 | 
						|
					ospf6_route_merge_nexthops(old_route,
 | 
						|
								   ls_entry);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
 | 
						|
				zlog_debug(
 | 
						|
					"%s: route %pFX %p with final effective paths %u nh %u",
 | 
						|
					__func__, &route->prefix,
 | 
						|
					(void *)old_route,
 | 
						|
					old_route->paths
 | 
						|
						? listcount(old_route->paths)
 | 
						|
						: 0,
 | 
						|
					listcount(old_route->nh_list));
 | 
						|
 | 
						|
			/* used in intra_route_calculation() to add to
 | 
						|
			 * global ospf6 route table.
 | 
						|
			 */
 | 
						|
			UNSET_FLAG(old_route->flag, OSPF6_ROUTE_REMOVE);
 | 
						|
			SET_FLAG(old_route->flag, OSPF6_ROUTE_ADD);
 | 
						|
			/* Update ospf6 route table and RIB/FIB */
 | 
						|
			if (oa->route_table->hook_add)
 | 
						|
				(*oa->route_table->hook_add)(old_route);
 | 
						|
			/* Delete the new route its info added to existing
 | 
						|
			 * route.
 | 
						|
			 */
 | 
						|
			ospf6_route_delete(route);
 | 
						|
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (!route_found) {
 | 
						|
		/* Add new route to existing node in ospf6 route table. */
 | 
						|
		ospf6_route_add(route, oa->route_table);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
 | 
						|
	struct prefix ls_prefix;
 | 
						|
	struct ospf6_route *route, *ls_entry, *old;
 | 
						|
	int prefix_num;
 | 
						|
	struct ospf6_prefix *op;
 | 
						|
	char *start, *current, *end;
 | 
						|
	char buf[PREFIX2STR_BUFFER];
 | 
						|
	struct interface *ifp = NULL;
 | 
						|
	int direct_connect = 0;
 | 
						|
	struct ospf6_path *path;
 | 
						|
 | 
						|
	if (OSPF6_LSA_IS_MAXAGE(lsa))
 | 
						|
		return;
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
 | 
						|
		zlog_debug("%s: LSA %s found", __func__, lsa->name);
 | 
						|
 | 
						|
	oa = OSPF6_AREA(lsa->lsdb->data);
 | 
						|
 | 
						|
	intra_prefix_lsa =
 | 
						|
		(struct ospf6_intra_prefix_lsa *)OSPF6_LSA_HEADER_END(
 | 
						|
			lsa->header);
 | 
						|
	if (intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_ROUTER) ||
 | 
						|
	    intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_NETWORK))
 | 
						|
		ospf6_linkstate_prefix(intra_prefix_lsa->ref_adv_router,
 | 
						|
				       intra_prefix_lsa->ref_id, &ls_prefix);
 | 
						|
	else {
 | 
						|
		if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
 | 
						|
			zlog_debug("Unknown reference LS-type: %#hx",
 | 
						|
				   ntohs(intra_prefix_lsa->ref_type));
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	ls_entry = ospf6_route_lookup(&ls_prefix, oa->spf_table);
 | 
						|
	if (ls_entry == NULL) {
 | 
						|
		if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
 | 
						|
			ospf6_linkstate_prefix2str(&ls_prefix, buf,
 | 
						|
						   sizeof(buf));
 | 
						|
			zlog_debug("LS entry does not exist: %s", buf);
 | 
						|
		}
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (intra_prefix_lsa->ref_adv_router == oa->ospf6->router_id) {
 | 
						|
		/* the intra-prefix are directly connected */
 | 
						|
		direct_connect = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	prefix_num = ntohs(intra_prefix_lsa->prefix_num);
 | 
						|
	start = (caddr_t)intra_prefix_lsa
 | 
						|
		+ sizeof(struct ospf6_intra_prefix_lsa);
 | 
						|
	end = OSPF6_LSA_END(lsa->header);
 | 
						|
	for (current = start; current < end; current += OSPF6_PREFIX_SIZE(op)) {
 | 
						|
		op = (struct ospf6_prefix *)current;
 | 
						|
		if (prefix_num == 0)
 | 
						|
			break;
 | 
						|
		if (end < current + OSPF6_PREFIX_SIZE(op))
 | 
						|
			break;
 | 
						|
 | 
						|
		/* Appendix A.4.1.1 */
 | 
						|
		if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU)) {
 | 
						|
			if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
 | 
						|
				ospf6_linkstate_prefix2str(
 | 
						|
					(struct prefix *)OSPF6_PREFIX_BODY(op),
 | 
						|
					buf, sizeof(buf));
 | 
						|
				zlog_debug(
 | 
						|
					"%s: Skipping Prefix %s has NU option set",
 | 
						|
					__func__, buf);
 | 
						|
			}
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		route = ospf6_route_create(oa->ospf6);
 | 
						|
 | 
						|
		memset(&route->prefix, 0, sizeof(struct prefix));
 | 
						|
		route->prefix.family = AF_INET6;
 | 
						|
		route->prefix.prefixlen = op->prefix_length;
 | 
						|
		ospf6_prefix_in6_addr(&route->prefix.u.prefix6,
 | 
						|
				      intra_prefix_lsa, op);
 | 
						|
		route->prefix_options = op->prefix_options;
 | 
						|
 | 
						|
		route->type = OSPF6_DEST_TYPE_NETWORK;
 | 
						|
		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.area_id = oa->area_id;
 | 
						|
		route->path.type = OSPF6_PATH_TYPE_INTRA;
 | 
						|
		route->path.metric_type = 1;
 | 
						|
		route->path.cost =
 | 
						|
			ls_entry->path.cost + ntohs(op->prefix_metric);
 | 
						|
		memcpy(&route->path.ls_prefix, &ls_prefix,
 | 
						|
		       sizeof(struct prefix));
 | 
						|
		if (direct_connect) {
 | 
						|
			ifp = if_lookup_prefix(&route->prefix,
 | 
						|
					       oa->ospf6->vrf_id);
 | 
						|
		}
 | 
						|
 | 
						|
		if (ifp) {
 | 
						|
			/* Nexthop interface found */
 | 
						|
			ospf6_route_add_nexthop(route, ifp->ifindex, NULL);
 | 
						|
		} else {
 | 
						|
			/* The connected interfaces between routers can be in
 | 
						|
			 * different networks. In this case the matching
 | 
						|
			 * interface is not found. Copy nexthops from the
 | 
						|
			 * link state entry
 | 
						|
			 */
 | 
						|
			ospf6_route_copy_nexthops(route, ls_entry);
 | 
						|
		}
 | 
						|
 | 
						|
		path = ospf6_path_dup(&route->path);
 | 
						|
		ospf6_copy_nexthops(path->nh_list, route->path.nh_list);
 | 
						|
		listnode_add_sort(route->paths, path);
 | 
						|
 | 
						|
		old = ospf6_route_lookup(&route->prefix, oa->route_table);
 | 
						|
		if (old) {
 | 
						|
			if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
 | 
						|
				prefix2str(&route->prefix, buf, sizeof(buf));
 | 
						|
				zlog_debug(
 | 
						|
					"%s Update route: %s old cost %u new cost %u paths %u nh %u",
 | 
						|
					__func__, buf, old->path.cost,
 | 
						|
					route->path.cost,
 | 
						|
					listcount(route->paths),
 | 
						|
					listcount(route->nh_list));
 | 
						|
			}
 | 
						|
			ospf6_intra_prefix_route_ecmp_path(oa, old, route);
 | 
						|
		} else {
 | 
						|
			if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
 | 
						|
				prefix2str(&route->prefix, buf, sizeof(buf));
 | 
						|
				zlog_debug(
 | 
						|
					"%s route %s add with cost %u paths %u nh %u",
 | 
						|
					__func__, buf, route->path.cost,
 | 
						|
					listcount(route->paths),
 | 
						|
					listcount(route->nh_list));
 | 
						|
			}
 | 
						|
			ospf6_route_add(route, oa->route_table);
 | 
						|
		}
 | 
						|
		prefix_num--;
 | 
						|
	}
 | 
						|
 | 
						|
	if (current != end && IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
 | 
						|
		zlog_debug("Trailing garbage ignored");
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_intra_prefix_lsa_remove_update_route(struct ospf6_lsa *lsa,
 | 
						|
						  struct ospf6_area *oa,
 | 
						|
						  struct ospf6_route *route)
 | 
						|
{
 | 
						|
	struct listnode *anode, *anext;
 | 
						|
	struct listnode *nnode, *rnode, *rnext;
 | 
						|
	struct ospf6_nexthop *nh, *rnh;
 | 
						|
	struct ospf6_path *o_path;
 | 
						|
	bool nh_updated = false;
 | 
						|
	char buf[PREFIX2STR_BUFFER];
 | 
						|
 | 
						|
	/* Iterate all paths of route to find maching
 | 
						|
	 * with LSA remove info.
 | 
						|
	 * If route->path is same, replace
 | 
						|
	 * from paths list.
 | 
						|
	 */
 | 
						|
	for (ALL_LIST_ELEMENTS(route->paths, anode, anext, o_path)) {
 | 
						|
		if ((o_path->origin.type != lsa->header->type) ||
 | 
						|
		    (o_path->origin.adv_router != lsa->header->adv_router) ||
 | 
						|
		    (o_path->origin.id != lsa->header->id))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
 | 
						|
			prefix2str(&route->prefix, buf, sizeof(buf));
 | 
						|
			zlog_debug(
 | 
						|
				"%s: route %s path found with cost %u nh %u to remove.",
 | 
						|
				__func__, buf, o_path->cost,
 | 
						|
				listcount(o_path->nh_list));
 | 
						|
		}
 | 
						|
 | 
						|
		/* Remove found path's nh_list from
 | 
						|
		 * the route's nh_list.
 | 
						|
		 */
 | 
						|
		for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
 | 
						|
			for (ALL_LIST_ELEMENTS(route->nh_list, rnode,
 | 
						|
					       rnext, rnh)) {
 | 
						|
				if (!ospf6_nexthop_is_same(rnh, nh))
 | 
						|
					continue;
 | 
						|
				listnode_delete(route->nh_list, rnh);
 | 
						|
				ospf6_nexthop_delete(rnh);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		/* Delete the path from route's
 | 
						|
		 * path list
 | 
						|
		 */
 | 
						|
		listnode_delete(route->paths, o_path);
 | 
						|
		ospf6_path_free(o_path);
 | 
						|
		nh_updated = true;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (nh_updated) {
 | 
						|
		/* Iterate all paths and merge nexthop,
 | 
						|
		 * unlesss any of the nexthop similar to
 | 
						|
		 * ones deleted as part of path deletion.
 | 
						|
		 */
 | 
						|
		for (ALL_LIST_ELEMENTS(route->paths, anode, anext, o_path))
 | 
						|
			ospf6_merge_nexthops(route->nh_list, o_path->nh_list);
 | 
						|
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
 | 
						|
			prefix2str(&route->prefix, buf, sizeof(buf));
 | 
						|
			zlog_debug(
 | 
						|
				"%s: route %s update paths %u nh %u", __func__,
 | 
						|
				buf, route->paths ? listcount(route->paths) : 0,
 | 
						|
				route->nh_list ? listcount(route->nh_list) : 0);
 | 
						|
		}
 | 
						|
 | 
						|
		/* Update Global Route table and
 | 
						|
		 * RIB/FIB with effective
 | 
						|
		 * nh_list
 | 
						|
		 */
 | 
						|
		if (oa->route_table->hook_add)
 | 
						|
			(*oa->route_table->hook_add)(route);
 | 
						|
 | 
						|
		/* route's primary path is similar
 | 
						|
		 * to LSA, replace route's primary
 | 
						|
		 * path with route's paths list
 | 
						|
		 * head.
 | 
						|
		 */
 | 
						|
		if ((route->path.origin.id == lsa->header->id) &&
 | 
						|
		    (route->path.origin.adv_router ==
 | 
						|
				lsa->header->adv_router)) {
 | 
						|
			ospf6_intra_prefix_update_route_origin(route,
 | 
						|
							       oa->ospf6);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa)
 | 
						|
{
 | 
						|
	struct ospf6_area *oa;
 | 
						|
	struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
 | 
						|
	struct prefix prefix;
 | 
						|
	struct ospf6_route *route, *nroute;
 | 
						|
	int prefix_num;
 | 
						|
	struct ospf6_prefix *op;
 | 
						|
	char *start, *current, *end;
 | 
						|
	char buf[PREFIX2STR_BUFFER];
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
 | 
						|
		zlog_debug("%s: %s disappearing", __func__, lsa->name);
 | 
						|
 | 
						|
	oa = OSPF6_AREA(lsa->lsdb->data);
 | 
						|
 | 
						|
	intra_prefix_lsa =
 | 
						|
		(struct ospf6_intra_prefix_lsa *)OSPF6_LSA_HEADER_END(
 | 
						|
			lsa->header);
 | 
						|
 | 
						|
	prefix_num = ntohs(intra_prefix_lsa->prefix_num);
 | 
						|
	start = (caddr_t)intra_prefix_lsa
 | 
						|
		+ sizeof(struct ospf6_intra_prefix_lsa);
 | 
						|
	end = OSPF6_LSA_END(lsa->header);
 | 
						|
	for (current = start; current < end; current += OSPF6_PREFIX_SIZE(op)) {
 | 
						|
		op = (struct ospf6_prefix *)current;
 | 
						|
		if (prefix_num == 0)
 | 
						|
			break;
 | 
						|
		if (end < current + OSPF6_PREFIX_SIZE(op))
 | 
						|
			break;
 | 
						|
		prefix_num--;
 | 
						|
 | 
						|
		memset(&prefix, 0, sizeof(prefix));
 | 
						|
		prefix.family = AF_INET6;
 | 
						|
		prefix.prefixlen = op->prefix_length;
 | 
						|
		ospf6_prefix_in6_addr(&prefix.u.prefix6, intra_prefix_lsa, op);
 | 
						|
 | 
						|
		route = ospf6_route_lookup(&prefix, oa->route_table);
 | 
						|
		if (route == NULL)
 | 
						|
			continue;
 | 
						|
 | 
						|
		for (ospf6_route_lock(route);
 | 
						|
		     route && ospf6_route_is_prefix(&prefix, route);
 | 
						|
		     route = nroute) {
 | 
						|
			nroute = ospf6_route_next(route);
 | 
						|
			if (route->type != OSPF6_DEST_TYPE_NETWORK)
 | 
						|
				continue;
 | 
						|
			if (route->path.area_id != oa->area_id)
 | 
						|
				continue;
 | 
						|
			if (route->path.type != OSPF6_PATH_TYPE_INTRA)
 | 
						|
				continue;
 | 
						|
			/* Route has multiple ECMP paths, remove matching
 | 
						|
			 * path. Update current route's effective nh list
 | 
						|
			 * after removal of one of the path.
 | 
						|
			 */
 | 
						|
			if (listcount(route->paths) > 1) {
 | 
						|
				ospf6_intra_prefix_lsa_remove_update_route(
 | 
						|
							lsa, oa, route);
 | 
						|
			} else {
 | 
						|
 | 
						|
				if (route->path.origin.type != lsa->header->type
 | 
						|
				    || route->path.origin.id != lsa->header->id
 | 
						|
				    || route->path.origin.adv_router
 | 
						|
				    != lsa->header->adv_router)
 | 
						|
					continue;
 | 
						|
 | 
						|
				if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
 | 
						|
					prefix2str(&route->prefix, buf,
 | 
						|
						   sizeof(buf));
 | 
						|
					zlog_debug(
 | 
						|
						"%s: route remove %s with path type %u cost %u paths %u nh %u",
 | 
						|
						__func__, buf, route->path.type,
 | 
						|
						route->path.cost,
 | 
						|
						listcount(route->paths),
 | 
						|
						listcount(route->nh_list));
 | 
						|
				}
 | 
						|
				ospf6_route_remove(route, oa->route_table);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (route)
 | 
						|
			ospf6_route_unlock(route);
 | 
						|
	}
 | 
						|
 | 
						|
	if (current != end && IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
 | 
						|
		zlog_debug("Trailing garbage ignored");
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_intra_route_calculation(struct ospf6_area *oa)
 | 
						|
{
 | 
						|
	struct ospf6_route *route, *nroute;
 | 
						|
	uint16_t type;
 | 
						|
	struct ospf6_lsa *lsa;
 | 
						|
	void (*hook_add)(struct ospf6_route *) = NULL;
 | 
						|
	void (*hook_remove)(struct ospf6_route *) = NULL;
 | 
						|
	char buf[PREFIX2STR_BUFFER];
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
 | 
						|
		zlog_debug("Re-examin intra-routes for area %s", oa->name);
 | 
						|
 | 
						|
	hook_add = oa->route_table->hook_add;
 | 
						|
	hook_remove = oa->route_table->hook_remove;
 | 
						|
	oa->route_table->hook_add = NULL;
 | 
						|
	oa->route_table->hook_remove = NULL;
 | 
						|
 | 
						|
	for (route = ospf6_route_head(oa->route_table); route;
 | 
						|
	     route = ospf6_route_next(route))
 | 
						|
		route->flag = OSPF6_ROUTE_REMOVE;
 | 
						|
 | 
						|
	type = htons(OSPF6_LSTYPE_INTRA_PREFIX);
 | 
						|
	for (ALL_LSDB_TYPED(oa->lsdb, type, lsa))
 | 
						|
		ospf6_intra_prefix_lsa_add(lsa);
 | 
						|
 | 
						|
	oa->route_table->hook_add = hook_add;
 | 
						|
	oa->route_table->hook_remove = hook_remove;
 | 
						|
 | 
						|
	for (route = ospf6_route_head(oa->route_table); route; route = nroute) {
 | 
						|
		if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
 | 
						|
			prefix2str(&route->prefix, buf, sizeof(buf));
 | 
						|
			zlog_debug("%s: route %s, flag 0x%x", __func__, buf,
 | 
						|
				   route->flag);
 | 
						|
		}
 | 
						|
 | 
						|
		nroute = ospf6_route_next(route);
 | 
						|
		if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)
 | 
						|
		    && CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)) {
 | 
						|
			UNSET_FLAG(route->flag, OSPF6_ROUTE_REMOVE);
 | 
						|
			UNSET_FLAG(route->flag, OSPF6_ROUTE_ADD);
 | 
						|
		}
 | 
						|
 | 
						|
		if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE))
 | 
						|
			ospf6_route_remove(route, oa->route_table);
 | 
						|
		else if (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)
 | 
						|
			 || CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE)) {
 | 
						|
			if (hook_add)
 | 
						|
				(*hook_add)(route);
 | 
						|
			route->flag = 0;
 | 
						|
		} else {
 | 
						|
			/* Redo the summaries as things might have changed */
 | 
						|
			if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
 | 
						|
				zlog_debug("%s: Originate summary for route %s",
 | 
						|
					   __func__, buf);
 | 
						|
			ospf6_abr_originate_summary(route, oa->ospf6);
 | 
						|
			route->flag = 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
 | 
						|
		zlog_debug("Re-examin intra-routes for area %s: Done",
 | 
						|
			   oa->name);
 | 
						|
}
 | 
						|
 | 
						|
static void ospf6_brouter_debug_print(struct ospf6_route *brouter)
 | 
						|
{
 | 
						|
	uint32_t brouter_id;
 | 
						|
	char brouter_name[16];
 | 
						|
	char area_name[16];
 | 
						|
	char destination[64];
 | 
						|
	char installed[64], changed[64];
 | 
						|
	struct timeval now, res;
 | 
						|
	char id[16], adv_router[16];
 | 
						|
	char capa[16], options[32];
 | 
						|
 | 
						|
	brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix);
 | 
						|
	inet_ntop(AF_INET, &brouter_id, brouter_name, sizeof(brouter_name));
 | 
						|
	inet_ntop(AF_INET, &brouter->path.area_id, area_name,
 | 
						|
		  sizeof(area_name));
 | 
						|
	ospf6_linkstate_prefix2str(&brouter->prefix, destination,
 | 
						|
				   sizeof(destination));
 | 
						|
 | 
						|
	monotime(&now);
 | 
						|
	timersub(&now, &brouter->installed, &res);
 | 
						|
	timerstring(&res, installed, sizeof(installed));
 | 
						|
 | 
						|
	monotime(&now);
 | 
						|
	timersub(&now, &brouter->changed, &res);
 | 
						|
	timerstring(&res, changed, sizeof(changed));
 | 
						|
 | 
						|
	inet_ntop(AF_INET, &brouter->path.origin.id, id, sizeof(id));
 | 
						|
	inet_ntop(AF_INET, &brouter->path.origin.adv_router, adv_router,
 | 
						|
		  sizeof(adv_router));
 | 
						|
 | 
						|
	ospf6_options_printbuf(brouter->path.options, options, sizeof(options));
 | 
						|
	ospf6_capability_printbuf(brouter->path.router_bits, capa,
 | 
						|
				  sizeof(capa));
 | 
						|
 | 
						|
	zlog_info("Brouter: %s via area %s", brouter_name, area_name);
 | 
						|
	zlog_info("  memory: prev: %p this: %p next: %p parent rnode: %p",
 | 
						|
		  (void *)brouter->prev, (void *)brouter, (void *)brouter->next,
 | 
						|
		  (void *)brouter->rnode);
 | 
						|
	zlog_info("  type: %d prefix: %s installed: %s changed: %s",
 | 
						|
		  brouter->type, destination, installed, changed);
 | 
						|
	zlog_info("  lock: %d flags: %s%s%s%s", brouter->lock,
 | 
						|
		  (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
 | 
						|
		  (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
 | 
						|
		  (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
 | 
						|
		  (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"));
 | 
						|
	zlog_info("  path type: %s ls-origin %s id: %s adv-router %s",
 | 
						|
		  OSPF6_PATH_TYPE_NAME(brouter->path.type),
 | 
						|
		  ospf6_lstype_name(brouter->path.origin.type), id, adv_router);
 | 
						|
	zlog_info("  options: %s router-bits: %s metric-type: %d metric: %d/%d",
 | 
						|
		  options, capa, brouter->path.metric_type, brouter->path.cost,
 | 
						|
		  brouter->path.u.cost_e2);
 | 
						|
	zlog_info(" paths %u nh %u", listcount(brouter->paths),
 | 
						|
		   listcount(brouter->nh_list));
 | 
						|
}
 | 
						|
 | 
						|
void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
 | 
						|
{
 | 
						|
	struct ospf6_route *brouter, *nbrouter, *copy;
 | 
						|
	void (*hook_add)(struct ospf6_route *) = NULL;
 | 
						|
	void (*hook_remove)(struct ospf6_route *) = NULL;
 | 
						|
	uint32_t brouter_id;
 | 
						|
	char brouter_name[16];
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) ||
 | 
						|
	    IS_OSPF6_DEBUG_ROUTE(MEMORY))
 | 
						|
		zlog_debug("%s: border-router calculation for area %s",
 | 
						|
			   __func__, oa->name);
 | 
						|
 | 
						|
	hook_add = oa->ospf6->brouter_table->hook_add;
 | 
						|
	hook_remove = oa->ospf6->brouter_table->hook_remove;
 | 
						|
	oa->ospf6->brouter_table->hook_add = NULL;
 | 
						|
	oa->ospf6->brouter_table->hook_remove = NULL;
 | 
						|
 | 
						|
	/* withdraw the previous router entries for the area */
 | 
						|
	for (brouter = ospf6_route_head(oa->ospf6->brouter_table); brouter;
 | 
						|
	     brouter = ospf6_route_next(brouter)) {
 | 
						|
		brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix);
 | 
						|
		inet_ntop(AF_INET, &brouter_id, brouter_name,
 | 
						|
			  sizeof(brouter_name));
 | 
						|
 | 
						|
		if (brouter->path.area_id != oa->area_id)
 | 
						|
			continue;
 | 
						|
 | 
						|
		SET_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE);
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(brouter_id)
 | 
						|
		    || IS_OSPF6_DEBUG_ROUTE(MEMORY)) {
 | 
						|
			zlog_debug("%p: mark as removing: area %s brouter %s",
 | 
						|
				   (void *)brouter, oa->name, brouter_name);
 | 
						|
			ospf6_brouter_debug_print(brouter);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for (brouter = ospf6_route_head(oa->spf_table); brouter;
 | 
						|
	     brouter = ospf6_route_next(brouter)) {
 | 
						|
		brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix);
 | 
						|
		inet_ntop(AF_INET, &brouter_id, brouter_name,
 | 
						|
			  sizeof(brouter_name));
 | 
						|
 | 
						|
		if (brouter->type != OSPF6_DEST_TYPE_LINKSTATE)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (ospf6_linkstate_prefix_id(&brouter->prefix) != htonl(0))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (!CHECK_FLAG(brouter->path.router_bits, OSPF6_ROUTER_BIT_E)
 | 
						|
		    && !CHECK_FLAG(brouter->path.router_bits,
 | 
						|
				   OSPF6_ROUTER_BIT_B))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (!OSPF6_OPT_ISSET(brouter->path.options, OSPF6_OPT_V6)
 | 
						|
		    || !OSPF6_OPT_ISSET(brouter->path.options, OSPF6_OPT_R))
 | 
						|
			continue;
 | 
						|
 | 
						|
		copy = ospf6_route_copy(brouter);
 | 
						|
		copy->type = OSPF6_DEST_TYPE_ROUTER;
 | 
						|
		copy->path.area_id = oa->area_id;
 | 
						|
		ospf6_route_add(copy, oa->ospf6->brouter_table);
 | 
						|
 | 
						|
		if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(brouter_id)
 | 
						|
		    || IS_OSPF6_DEBUG_ROUTE(MEMORY)) {
 | 
						|
			zlog_debug("%p: transfer: area %s brouter %s",
 | 
						|
				   (void *)brouter, oa->name, brouter_name);
 | 
						|
			ospf6_brouter_debug_print(brouter);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	oa->ospf6->brouter_table->hook_add = hook_add;
 | 
						|
	oa->ospf6->brouter_table->hook_remove = hook_remove;
 | 
						|
 | 
						|
	for (brouter = ospf6_route_head(oa->ospf6->brouter_table); brouter;
 | 
						|
	     brouter = nbrouter) {
 | 
						|
 | 
						|
		/*
 | 
						|
		 * brouter may have been "deleted" in the last loop iteration.
 | 
						|
		 * If this is the case there is still 1 final refcount lock
 | 
						|
		 * taken by ospf6_route_next, that will be released by the same
 | 
						|
		 * call and result in deletion. To avoid heap UAF we must then
 | 
						|
		 * skip processing the deleted route.
 | 
						|
		 */
 | 
						|
		if (brouter->lock == 1) {
 | 
						|
			if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
 | 
						|
				ospf6_brouter_debug_print(brouter);
 | 
						|
			nbrouter = ospf6_route_next(brouter);
 | 
						|
			continue;
 | 
						|
		} else {
 | 
						|
			nbrouter = ospf6_route_next(brouter);
 | 
						|
		}
 | 
						|
 | 
						|
		brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix);
 | 
						|
		inet_ntop(AF_INET, &brouter_id, brouter_name,
 | 
						|
			  sizeof(brouter_name));
 | 
						|
 | 
						|
		if (brouter->path.area_id != oa->area_id)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_WAS_REMOVED))
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* After iterating spf_table for all routers including
 | 
						|
		 * intra brouter, clear mark for remove flag for
 | 
						|
		 * inter border router if its adv router present in
 | 
						|
		 * SPF table.
 | 
						|
		 */
 | 
						|
		if (brouter->path.type == OSPF6_PATH_TYPE_INTER) {
 | 
						|
			struct prefix adv_prefix;
 | 
						|
 | 
						|
			ospf6_linkstate_prefix(brouter->path.origin.adv_router,
 | 
						|
					       htonl(0), &adv_prefix);
 | 
						|
 | 
						|
			if (ospf6_route_lookup(&adv_prefix, oa->spf_table)) {
 | 
						|
				if (IS_OSPF6_DEBUG_BROUTER) {
 | 
						|
					zlog_debug(
 | 
						|
						"%s: keep inter brouter %s as adv router 0x%x found in spf",
 | 
						|
						__func__, brouter_name,
 | 
						|
						brouter->path.origin
 | 
						|
							.adv_router);
 | 
						|
					ospf6_brouter_debug_print(brouter);
 | 
						|
				}
 | 
						|
				UNSET_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE)
 | 
						|
		    && CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD)) {
 | 
						|
			UNSET_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE);
 | 
						|
			UNSET_FLAG(brouter->flag, OSPF6_ROUTE_ADD);
 | 
						|
		}
 | 
						|
 | 
						|
		if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_REMOVE)) {
 | 
						|
			if (IS_OSPF6_DEBUG_BROUTER
 | 
						|
			    || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(
 | 
						|
				       brouter_id)
 | 
						|
			    || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
 | 
						|
				       oa->area_id))
 | 
						|
				zlog_debug(
 | 
						|
					"%s: brouter %s disappears via area %s",
 | 
						|
					__func__, brouter_name, oa->name);
 | 
						|
			/* This is used to protect nbrouter from removed from
 | 
						|
			 * the table. For an example, ospf6_abr_examin_summary,
 | 
						|
			 * removes brouters which are marked for remove.
 | 
						|
			 */
 | 
						|
			oa->intra_brouter_calc = true;
 | 
						|
			ospf6_route_remove(brouter, oa->ospf6->brouter_table);
 | 
						|
			brouter = NULL;
 | 
						|
		} else if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD)
 | 
						|
			   || CHECK_FLAG(brouter->flag, OSPF6_ROUTE_CHANGE)) {
 | 
						|
			if (IS_OSPF6_DEBUG_BROUTER
 | 
						|
			    || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(
 | 
						|
				       brouter_id)
 | 
						|
			    || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
 | 
						|
				       oa->area_id))
 | 
						|
				zlog_info("%s: brouter %s appears via area %s",
 | 
						|
					  __func__, brouter_name, oa->name);
 | 
						|
 | 
						|
			/* newly added */
 | 
						|
			if (hook_add)
 | 
						|
				(*hook_add)(brouter);
 | 
						|
		} else {
 | 
						|
			if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(
 | 
						|
				    brouter_id)
 | 
						|
			    || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
 | 
						|
				       oa->area_id))
 | 
						|
				zlog_debug(
 | 
						|
					"brouter %s still exists via area %s",
 | 
						|
					brouter_name, oa->name);
 | 
						|
			/* But re-originate summaries */
 | 
						|
			ospf6_abr_originate_summary(brouter, oa->ospf6);
 | 
						|
		}
 | 
						|
 | 
						|
		if (brouter) {
 | 
						|
			UNSET_FLAG(brouter->flag, OSPF6_ROUTE_ADD);
 | 
						|
			UNSET_FLAG(brouter->flag, OSPF6_ROUTE_CHANGE);
 | 
						|
		}
 | 
						|
		/* Reset for nbrouter */
 | 
						|
		oa->intra_brouter_calc = false;
 | 
						|
	}
 | 
						|
 | 
						|
	if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) ||
 | 
						|
	    IS_OSPF6_DEBUG_ROUTE(MEMORY))
 | 
						|
		zlog_debug("%s: border-router calculation for area %s: done",
 | 
						|
			   __func__, oa->name);
 | 
						|
}
 | 
						|
 | 
						|
static struct ospf6_lsa_handler router_handler = {
 | 
						|
	.lh_type = OSPF6_LSTYPE_ROUTER,
 | 
						|
	.lh_name = "Router",
 | 
						|
	.lh_short_name = "Rtr",
 | 
						|
	.lh_show = ospf6_router_lsa_show,
 | 
						|
	.lh_get_prefix_str = ospf6_router_lsa_get_nbr_id,
 | 
						|
	.lh_debug = 0};
 | 
						|
 | 
						|
static struct ospf6_lsa_handler network_handler = {
 | 
						|
	.lh_type = OSPF6_LSTYPE_NETWORK,
 | 
						|
	.lh_name = "Network",
 | 
						|
	.lh_short_name = "Net",
 | 
						|
	.lh_show = ospf6_network_lsa_show,
 | 
						|
	.lh_get_prefix_str = ospf6_network_lsa_get_ar_id,
 | 
						|
	.lh_debug = 0};
 | 
						|
 | 
						|
static struct ospf6_lsa_handler link_handler = {
 | 
						|
	.lh_type = OSPF6_LSTYPE_LINK,
 | 
						|
	.lh_name = "Link",
 | 
						|
	.lh_short_name = "Lnk",
 | 
						|
	.lh_show = ospf6_link_lsa_show,
 | 
						|
	.lh_get_prefix_str = ospf6_link_lsa_get_prefix_str,
 | 
						|
	.lh_debug = 0};
 | 
						|
 | 
						|
static struct ospf6_lsa_handler intra_prefix_handler = {
 | 
						|
	.lh_type = OSPF6_LSTYPE_INTRA_PREFIX,
 | 
						|
	.lh_name = "Intra-Prefix",
 | 
						|
	.lh_short_name = "INP",
 | 
						|
	.lh_show = ospf6_intra_prefix_lsa_show,
 | 
						|
	.lh_get_prefix_str = ospf6_intra_prefix_lsa_get_prefix_str,
 | 
						|
	.lh_debug = 0};
 | 
						|
 | 
						|
void ospf6_intra_init(void)
 | 
						|
{
 | 
						|
	ospf6_install_lsa_handler(&router_handler);
 | 
						|
	ospf6_install_lsa_handler(&network_handler);
 | 
						|
	ospf6_install_lsa_handler(&link_handler);
 | 
						|
	ospf6_install_lsa_handler(&intra_prefix_handler);
 | 
						|
}
 | 
						|
 | 
						|
DEFUN (debug_ospf6_brouter,
 | 
						|
       debug_ospf6_brouter_cmd,
 | 
						|
       "debug ospf6 border-routers",
 | 
						|
       DEBUG_STR
 | 
						|
       OSPF6_STR
 | 
						|
       "Debug border router\n"
 | 
						|
      )
 | 
						|
{
 | 
						|
	OSPF6_DEBUG_BROUTER_ON();
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
DEFUN (no_debug_ospf6_brouter,
 | 
						|
       no_debug_ospf6_brouter_cmd,
 | 
						|
       "no debug ospf6 border-routers",
 | 
						|
       NO_STR
 | 
						|
       DEBUG_STR
 | 
						|
       OSPF6_STR
 | 
						|
       "Debug border router\n"
 | 
						|
      )
 | 
						|
{
 | 
						|
	OSPF6_DEBUG_BROUTER_OFF();
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
DEFUN (debug_ospf6_brouter_router,
 | 
						|
       debug_ospf6_brouter_router_cmd,
 | 
						|
       "debug ospf6 border-routers router-id A.B.C.D",
 | 
						|
       DEBUG_STR
 | 
						|
       OSPF6_STR
 | 
						|
       "Debug border router\n"
 | 
						|
       "Debug specific border router\n"
 | 
						|
       "Specify border-router's router-id\n"
 | 
						|
      )
 | 
						|
{
 | 
						|
	int idx_ipv4 = 4;
 | 
						|
	uint32_t router_id;
 | 
						|
	inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id);
 | 
						|
	OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ON(router_id);
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
DEFUN (no_debug_ospf6_brouter_router,
 | 
						|
       no_debug_ospf6_brouter_router_cmd,
 | 
						|
       "no debug ospf6 border-routers router-id [A.B.C.D]",
 | 
						|
       NO_STR
 | 
						|
       DEBUG_STR
 | 
						|
       OSPF6_STR
 | 
						|
       "Debug border router\n"
 | 
						|
       "Debug specific border router\n"
 | 
						|
       "Specify border-router's router-id\n"
 | 
						|
      )
 | 
						|
{
 | 
						|
	OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF();
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
DEFUN (debug_ospf6_brouter_area,
 | 
						|
       debug_ospf6_brouter_area_cmd,
 | 
						|
       "debug ospf6 border-routers area-id A.B.C.D",
 | 
						|
       DEBUG_STR
 | 
						|
       OSPF6_STR
 | 
						|
       "Debug border router\n"
 | 
						|
       "Debug border routers in specific Area\n"
 | 
						|
       "Specify Area-ID\n"
 | 
						|
      )
 | 
						|
{
 | 
						|
	int idx_ipv4 = 4;
 | 
						|
	uint32_t area_id;
 | 
						|
	inet_pton(AF_INET, argv[idx_ipv4]->arg, &area_id);
 | 
						|
	OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ON(area_id);
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
DEFUN (no_debug_ospf6_brouter_area,
 | 
						|
       no_debug_ospf6_brouter_area_cmd,
 | 
						|
       "no debug ospf6 border-routers area-id [A.B.C.D]",
 | 
						|
       NO_STR
 | 
						|
       DEBUG_STR
 | 
						|
       OSPF6_STR
 | 
						|
       "Debug border router\n"
 | 
						|
       "Debug border routers in specific Area\n"
 | 
						|
       "Specify Area-ID\n"
 | 
						|
      )
 | 
						|
{
 | 
						|
	OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF();
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int config_write_ospf6_debug_brouter(struct vty *vty)
 | 
						|
{
 | 
						|
	char buf[16];
 | 
						|
	if (IS_OSPF6_DEBUG_BROUTER)
 | 
						|
		vty_out(vty, "debug ospf6 border-routers\n");
 | 
						|
	if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER) {
 | 
						|
		inet_ntop(AF_INET, &conf_debug_ospf6_brouter_specific_router_id,
 | 
						|
			  buf, sizeof(buf));
 | 
						|
		vty_out(vty, "debug ospf6 border-routers router-id %s\n", buf);
 | 
						|
	}
 | 
						|
	if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA) {
 | 
						|
		inet_ntop(AF_INET, &conf_debug_ospf6_brouter_specific_area_id,
 | 
						|
			  buf, sizeof(buf));
 | 
						|
		vty_out(vty, "debug ospf6 border-routers area-id %s\n", buf);
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void install_element_ospf6_debug_brouter(void)
 | 
						|
{
 | 
						|
	install_element(ENABLE_NODE, &debug_ospf6_brouter_cmd);
 | 
						|
	install_element(ENABLE_NODE, &debug_ospf6_brouter_router_cmd);
 | 
						|
	install_element(ENABLE_NODE, &debug_ospf6_brouter_area_cmd);
 | 
						|
	install_element(ENABLE_NODE, &no_debug_ospf6_brouter_cmd);
 | 
						|
	install_element(ENABLE_NODE, &no_debug_ospf6_brouter_router_cmd);
 | 
						|
	install_element(ENABLE_NODE, &no_debug_ospf6_brouter_area_cmd);
 | 
						|
	install_element(CONFIG_NODE, &debug_ospf6_brouter_cmd);
 | 
						|
	install_element(CONFIG_NODE, &debug_ospf6_brouter_router_cmd);
 | 
						|
	install_element(CONFIG_NODE, &debug_ospf6_brouter_area_cmd);
 | 
						|
	install_element(CONFIG_NODE, &no_debug_ospf6_brouter_cmd);
 | 
						|
	install_element(CONFIG_NODE, &no_debug_ospf6_brouter_router_cmd);
 | 
						|
	install_element(CONFIG_NODE, &no_debug_ospf6_brouter_area_cmd);
 | 
						|
}
 |