mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-10-31 10:56:49 +00:00 
			
		
		
		
	 ae82bb756b
			
		
	
	
		ae82bb756b
		
	
	
	
	
		
			
			The opaque lsa that we are storing is stored on various lists depending on it's type. This removal from the list was being done *after* the pointer was freed. This is not a good idea. Since the use after free was just removal from a linked list and the freeing function does not do anything other than free data, than just switching the function order should be sufficient. Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
		
			
				
	
	
		
			2190 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2190 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * This is an implementation of rfc2370.
 | |
|  * Copyright (C) 2001 KDD R&D Laboratories, Inc.
 | |
|  * http://www.kddlabs.co.jp/
 | |
|  *
 | |
|  * This file is part of GNU Zebra.
 | |
|  *
 | |
|  * GNU Zebra is free software; you can redistribute it and/or modify it
 | |
|  * under the terms of the GNU General Public License as published by the
 | |
|  * Free Software Foundation; either version 2, or (at your option) any
 | |
|  * later version.
 | |
|  *
 | |
|  * GNU Zebra is distributed in the hope that it will be useful, but
 | |
|  * WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License along
 | |
|  * with this program; see the file COPYING; if not, write to the Free Software
 | |
|  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 | |
|  */
 | |
| 
 | |
| #include <zebra.h>
 | |
| 
 | |
| #include "linklist.h"
 | |
| #include "prefix.h"
 | |
| #include "if.h"
 | |
| #include "table.h"
 | |
| #include "memory.h"
 | |
| #include "command.h"
 | |
| #include "vty.h"
 | |
| #include "stream.h"
 | |
| #include "log.h"
 | |
| #include "thread.h"
 | |
| #include "hash.h"
 | |
| #include "sockunion.h" /* for inet_aton() */
 | |
| 
 | |
| #include "ospfd/ospfd.h"
 | |
| #include "ospfd/ospf_interface.h"
 | |
| #include "ospfd/ospf_ism.h"
 | |
| #include "ospfd/ospf_asbr.h"
 | |
| #include "ospfd/ospf_lsa.h"
 | |
| #include "ospfd/ospf_lsdb.h"
 | |
| #include "ospfd/ospf_neighbor.h"
 | |
| #include "ospfd/ospf_nsm.h"
 | |
| #include "ospfd/ospf_flood.h"
 | |
| #include "ospfd/ospf_packet.h"
 | |
| #include "ospfd/ospf_spf.h"
 | |
| #include "ospfd/ospf_dump.h"
 | |
| #include "ospfd/ospf_route.h"
 | |
| #include "ospfd/ospf_ase.h"
 | |
| #include "ospfd/ospf_zebra.h"
 | |
| #include "ospfd/ospf_te.h"
 | |
| #include "ospfd/ospf_sr.h"
 | |
| #include "ospfd/ospf_ri.h"
 | |
| #include "ospfd/ospf_ext.h"
 | |
| #include "ospfd/ospf_errors.h"
 | |
| 
 | |
| DEFINE_MTYPE_STATIC(OSPFD, OSPF_OPAQUE_FUNCTAB, "OSPF opaque function table")
 | |
| DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_TYPE, "OSPF opaque per-type info")
 | |
| DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_ID, "OSPF opaque per-ID info")
 | |
| 
 | |
| /*------------------------------------------------------------------------*
 | |
|  * Followings are initialize/terminate functions for Opaque-LSAs handling.
 | |
|  *------------------------------------------------------------------------*/
 | |
| 
 | |
| #ifdef SUPPORT_OSPF_API
 | |
| int ospf_apiserver_init(void);
 | |
| void ospf_apiserver_term(void);
 | |
| /* Init apiserver? It's disabled by default. */
 | |
| int ospf_apiserver_enable;
 | |
| #endif /* SUPPORT_OSPF_API */
 | |
| 
 | |
| static void ospf_opaque_register_vty(void);
 | |
| static void ospf_opaque_funclist_init(void);
 | |
| static void ospf_opaque_funclist_term(void);
 | |
| static void free_opaque_info_per_type(void *val);
 | |
| static void free_opaque_info_per_id(void *val);
 | |
| static void free_opaque_info_owner(void *val);
 | |
| static int ospf_opaque_lsa_install_hook(struct ospf_lsa *lsa);
 | |
| static int ospf_opaque_lsa_delete_hook(struct ospf_lsa *lsa);
 | |
| 
 | |
| void ospf_opaque_init(void)
 | |
| {
 | |
| 	ospf_opaque_register_vty();
 | |
| 	ospf_opaque_funclist_init();
 | |
| 
 | |
| 	if (ospf_mpls_te_init() != 0)
 | |
| 		exit(1);
 | |
| 
 | |
| 	/* Segment Routing init */
 | |
| 	if (ospf_sr_init() != 0)
 | |
| 		exit(1);
 | |
| 
 | |
| 	if (ospf_router_info_init() != 0)
 | |
| 		exit(1);
 | |
| 
 | |
| 	if (ospf_ext_init() != 0)
 | |
| 		exit(1);
 | |
| 
 | |
| #ifdef SUPPORT_OSPF_API
 | |
| 	if ((ospf_apiserver_enable) && (ospf_apiserver_init() != 0))
 | |
| 		exit(1);
 | |
| #endif /* SUPPORT_OSPF_API */
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_term(void)
 | |
| {
 | |
| 	ospf_mpls_te_term();
 | |
| 
 | |
| 	ospf_router_info_term();
 | |
| 
 | |
| 	ospf_ext_term();
 | |
| 
 | |
| 	ospf_sr_term();
 | |
| 
 | |
| #ifdef SUPPORT_OSPF_API
 | |
| 	ospf_apiserver_term();
 | |
| #endif /* SUPPORT_OSPF_API */
 | |
| 
 | |
| 	ospf_opaque_funclist_term();
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_finish(void)
 | |
| {
 | |
| 	ospf_router_info_finish();
 | |
| 
 | |
| 	ospf_ext_finish();
 | |
| 
 | |
| 	ospf_sr_finish();
 | |
| }
 | |
| 
 | |
| int ospf_opaque_type9_lsa_init(struct ospf_interface *oi)
 | |
| {
 | |
| 	if (oi->opaque_lsa_self != NULL)
 | |
| 		list_delete(&oi->opaque_lsa_self);
 | |
| 
 | |
| 	oi->opaque_lsa_self = list_new();
 | |
| 	oi->opaque_lsa_self->del = free_opaque_info_per_type;
 | |
| 	oi->t_opaque_lsa_self = NULL;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_type9_lsa_term(struct ospf_interface *oi)
 | |
| {
 | |
| 	OSPF_TIMER_OFF(oi->t_opaque_lsa_self);
 | |
| 	if (oi->opaque_lsa_self != NULL)
 | |
| 		list_delete(&oi->opaque_lsa_self);
 | |
| 	oi->opaque_lsa_self = NULL;
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| int ospf_opaque_type10_lsa_init(struct ospf_area *area)
 | |
| {
 | |
| 	if (area->opaque_lsa_self != NULL)
 | |
| 		list_delete(&area->opaque_lsa_self);
 | |
| 
 | |
| 	area->opaque_lsa_self = list_new();
 | |
| 	area->opaque_lsa_self->del = free_opaque_info_per_type;
 | |
| 	area->t_opaque_lsa_self = NULL;
 | |
| 
 | |
| #ifdef MONITOR_LSDB_CHANGE
 | |
| 	area->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook;
 | |
| 	area->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook;
 | |
| #endif /* MONITOR_LSDB_CHANGE */
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_type10_lsa_term(struct ospf_area *area)
 | |
| {
 | |
| #ifdef MONITOR_LSDB_CHANGE
 | |
| 	area->lsdb->new_lsa_hook = area->lsdb->del_lsa_hook = NULL;
 | |
| #endif /* MONITOR_LSDB_CHANGE */
 | |
| 
 | |
| 	OSPF_TIMER_OFF(area->t_opaque_lsa_self);
 | |
| 	if (area->opaque_lsa_self != NULL)
 | |
| 		list_delete(&area->opaque_lsa_self);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| int ospf_opaque_type11_lsa_init(struct ospf *top)
 | |
| {
 | |
| 	if (top->opaque_lsa_self != NULL)
 | |
| 		list_delete(&top->opaque_lsa_self);
 | |
| 
 | |
| 	top->opaque_lsa_self = list_new();
 | |
| 	top->opaque_lsa_self->del = free_opaque_info_per_type;
 | |
| 	top->t_opaque_lsa_self = NULL;
 | |
| 
 | |
| #ifdef MONITOR_LSDB_CHANGE
 | |
| 	top->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook;
 | |
| 	top->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook;
 | |
| #endif /* MONITOR_LSDB_CHANGE */
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_type11_lsa_term(struct ospf *top)
 | |
| {
 | |
| #ifdef MONITOR_LSDB_CHANGE
 | |
| 	top->lsdb->new_lsa_hook = top->lsdb->del_lsa_hook = NULL;
 | |
| #endif /* MONITOR_LSDB_CHANGE */
 | |
| 
 | |
| 	OSPF_TIMER_OFF(top->t_opaque_lsa_self);
 | |
| 	if (top->opaque_lsa_self != NULL)
 | |
| 		list_delete(&top->opaque_lsa_self);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static const char *ospf_opaque_type_name(uint8_t opaque_type)
 | |
| {
 | |
| 	const char *name = "Unknown";
 | |
| 
 | |
| 	switch (opaque_type) {
 | |
| 	case OPAQUE_TYPE_WILDCARD: /* This is a special assignment! */
 | |
| 		name = "Wildcard";
 | |
| 		break;
 | |
| 	case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA:
 | |
| 		name = "Traffic Engineering LSA";
 | |
| 		break;
 | |
| 	case OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC:
 | |
| 		name = "Sycamore optical topology description";
 | |
| 		break;
 | |
| 	case OPAQUE_TYPE_GRACE_LSA:
 | |
| 		name = "Grace-LSA";
 | |
| 		break;
 | |
| 	case OPAQUE_TYPE_INTER_AS_LSA:
 | |
| 		name = "Inter-AS TE-v2 LSA";
 | |
| 		break;
 | |
| 	case OPAQUE_TYPE_ROUTER_INFORMATION_LSA:
 | |
| 		name = "Router Information LSA";
 | |
| 		break;
 | |
| 	case OPAQUE_TYPE_EXTENDED_PREFIX_LSA:
 | |
| 		name = "Extended Prefix Opaque LSA";
 | |
| 		break;
 | |
| 	case OPAQUE_TYPE_EXTENDED_LINK_LSA:
 | |
| 		name = "Extended Link Opaque LSA";
 | |
| 		break;
 | |
| 	default:
 | |
| 		if (OPAQUE_TYPE_RANGE_UNASSIGNED(opaque_type))
 | |
| 			name = "Unassigned";
 | |
| 		else {
 | |
| 			uint32_t bigger_range = opaque_type;
 | |
| 			/*
 | |
| 			 * Get around type-limits warning: comparison is always
 | |
| 			 * true due to limited range of data type
 | |
| 			 */
 | |
| 			if (OPAQUE_TYPE_RANGE_RESERVED(bigger_range))
 | |
| 				name = "Private/Experimental";
 | |
| 		}
 | |
| 		break;
 | |
| 	}
 | |
| 	return name;
 | |
| }
 | |
| 
 | |
| /*------------------------------------------------------------------------*
 | |
|  * Followings are management functions to store user specified callbacks.
 | |
|  *------------------------------------------------------------------------*/
 | |
| 
 | |
| struct opaque_info_per_type; /* Forward declaration. */
 | |
| 
 | |
| struct ospf_opaque_functab {
 | |
| 	uint8_t opaque_type;
 | |
| 	struct opaque_info_per_type *oipt;
 | |
| 
 | |
| 	int (*new_if_hook)(struct interface *ifp);
 | |
| 	int (*del_if_hook)(struct interface *ifp);
 | |
| 	void (*ism_change_hook)(struct ospf_interface *oi, int old_status);
 | |
| 	void (*nsm_change_hook)(struct ospf_neighbor *nbr, int old_status);
 | |
| 	void (*config_write_router)(struct vty *vty);
 | |
| 	void (*config_write_if)(struct vty *vty, struct interface *ifp);
 | |
| 	void (*config_write_debug)(struct vty *vty);
 | |
| 	void (*show_opaque_info)(struct vty *vty, struct ospf_lsa *lsa);
 | |
| 	int (*lsa_originator)(void *arg);
 | |
| 	struct ospf_lsa *(*lsa_refresher)(struct ospf_lsa *lsa);
 | |
| 	int (*new_lsa_hook)(struct ospf_lsa *lsa);
 | |
| 	int (*del_lsa_hook)(struct ospf_lsa *lsa);
 | |
| };
 | |
| 
 | |
| /* Handle LSA-9/10/11 altogether. */
 | |
| static struct list *ospf_opaque_wildcard_funclist;
 | |
| static struct list *ospf_opaque_type9_funclist;
 | |
| static struct list *ospf_opaque_type10_funclist;
 | |
| static struct list *ospf_opaque_type11_funclist;
 | |
| 
 | |
| static void ospf_opaque_del_functab(void *val)
 | |
| {
 | |
| 	XFREE(MTYPE_OSPF_OPAQUE_FUNCTAB, val);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static void ospf_opaque_funclist_init(void)
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 
 | |
| 	funclist = ospf_opaque_wildcard_funclist = list_new();
 | |
| 	funclist->del = ospf_opaque_del_functab;
 | |
| 
 | |
| 	funclist = ospf_opaque_type9_funclist = list_new();
 | |
| 	funclist->del = ospf_opaque_del_functab;
 | |
| 
 | |
| 	funclist = ospf_opaque_type10_funclist = list_new();
 | |
| 	funclist->del = ospf_opaque_del_functab;
 | |
| 
 | |
| 	funclist = ospf_opaque_type11_funclist = list_new();
 | |
| 	funclist->del = ospf_opaque_del_functab;
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static void ospf_opaque_funclist_term(void)
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 
 | |
| 	funclist = ospf_opaque_wildcard_funclist;
 | |
| 	list_delete(&funclist);
 | |
| 
 | |
| 	funclist = ospf_opaque_type9_funclist;
 | |
| 	list_delete(&funclist);
 | |
| 
 | |
| 	funclist = ospf_opaque_type10_funclist;
 | |
| 	list_delete(&funclist);
 | |
| 
 | |
| 	funclist = ospf_opaque_type11_funclist;
 | |
| 	list_delete(&funclist);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static struct list *ospf_get_opaque_funclist(uint8_t lsa_type)
 | |
| {
 | |
| 	struct list *funclist = NULL;
 | |
| 
 | |
| 	switch (lsa_type) {
 | |
| 	case OPAQUE_TYPE_WILDCARD:
 | |
| 		/* XXX
 | |
| 		 * This is an ugly trick to handle type-9/10/11 LSA altogether.
 | |
| 		 * Yes, "OPAQUE_TYPE_WILDCARD (value 0)" is not an LSA-type, nor
 | |
| 		 * an officially assigned opaque-type.
 | |
| 		 * Though it is possible that the value might be officially used
 | |
| 		 * in the future, we use it internally as a special label, for
 | |
| 		 * now.
 | |
| 		 */
 | |
| 		funclist = ospf_opaque_wildcard_funclist;
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_LINK_LSA:
 | |
| 		funclist = ospf_opaque_type9_funclist;
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AREA_LSA:
 | |
| 		funclist = ospf_opaque_type10_funclist;
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AS_LSA:
 | |
| 		funclist = ospf_opaque_type11_funclist;
 | |
| 		break;
 | |
| 	default:
 | |
| 		flog_warn(EC_OSPF_LSA_UNEXPECTED,
 | |
| 			  "ospf_get_opaque_funclist: Unexpected LSA-type(%u)",
 | |
| 			  lsa_type);
 | |
| 		break;
 | |
| 	}
 | |
| 	return funclist;
 | |
| }
 | |
| 
 | |
| /* XXX: such a huge argument list can /not/ be healthy... */
 | |
| int ospf_register_opaque_functab(
 | |
| 	uint8_t lsa_type, uint8_t opaque_type,
 | |
| 	int (*new_if_hook)(struct interface *ifp),
 | |
| 	int (*del_if_hook)(struct interface *ifp),
 | |
| 	void (*ism_change_hook)(struct ospf_interface *oi, int old_status),
 | |
| 	void (*nsm_change_hook)(struct ospf_neighbor *nbr, int old_status),
 | |
| 	void (*config_write_router)(struct vty *vty),
 | |
| 	void (*config_write_if)(struct vty *vty, struct interface *ifp),
 | |
| 	void (*config_write_debug)(struct vty *vty),
 | |
| 	void (*show_opaque_info)(struct vty *vty, struct ospf_lsa *lsa),
 | |
| 	int (*lsa_originator)(void *arg),
 | |
| 	struct ospf_lsa *(*lsa_refresher)(struct ospf_lsa *lsa),
 | |
| 	int (*new_lsa_hook)(struct ospf_lsa *lsa),
 | |
| 	int (*del_lsa_hook)(struct ospf_lsa *lsa))
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 	struct ospf_opaque_functab *new;
 | |
| 
 | |
| 	if ((funclist = ospf_get_opaque_funclist(lsa_type)) == NULL)
 | |
| 		return -1;
 | |
| 
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
 | |
| 		if (functab->opaque_type == opaque_type) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"ospf_register_opaque_functab: Duplicated entry?: lsa_type(%u), opaque_type(%u)",
 | |
| 				lsa_type, opaque_type);
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 	new = XCALLOC(MTYPE_OSPF_OPAQUE_FUNCTAB,
 | |
| 		      sizeof(struct ospf_opaque_functab));
 | |
| 
 | |
| 	new->opaque_type = opaque_type;
 | |
| 	new->oipt = NULL;
 | |
| 	new->new_if_hook = new_if_hook;
 | |
| 	new->del_if_hook = del_if_hook;
 | |
| 	new->ism_change_hook = ism_change_hook;
 | |
| 	new->nsm_change_hook = nsm_change_hook;
 | |
| 	new->config_write_router = config_write_router;
 | |
| 	new->config_write_if = config_write_if;
 | |
| 	new->config_write_debug = config_write_debug;
 | |
| 	new->show_opaque_info = show_opaque_info;
 | |
| 	new->lsa_originator = lsa_originator;
 | |
| 	new->lsa_refresher = lsa_refresher;
 | |
| 	new->new_lsa_hook = new_lsa_hook;
 | |
| 	new->del_lsa_hook = del_lsa_hook;
 | |
| 
 | |
| 	listnode_add(funclist, new);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void ospf_delete_opaque_functab(uint8_t lsa_type, uint8_t opaque_type)
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 
 | |
| 	if ((funclist = ospf_get_opaque_funclist(lsa_type)) != NULL)
 | |
| 		for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab)) {
 | |
| 			if (functab->opaque_type == opaque_type) {
 | |
| 				/* Cleanup internal control information, if it
 | |
| 				 * still remains. */
 | |
| 				if (functab->oipt != NULL) {
 | |
| 					free_opaque_info_owner(functab->oipt);
 | |
| 					free_opaque_info_per_type(
 | |
| 						functab->oipt);
 | |
| 				}
 | |
| 
 | |
| 				/* Dequeue listnode entry from the list. */
 | |
| 				listnode_delete(funclist, functab);
 | |
| 
 | |
| 				XFREE(MTYPE_OSPF_OPAQUE_FUNCTAB, functab);
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static struct ospf_opaque_functab *
 | |
| ospf_opaque_functab_lookup(struct ospf_lsa *lsa)
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 	struct listnode *node;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 	uint8_t key = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr));
 | |
| 
 | |
| 	if ((funclist = ospf_get_opaque_funclist(lsa->data->type)) != NULL)
 | |
| 		for (ALL_LIST_ELEMENTS_RO(funclist, node, functab))
 | |
| 			if (functab->opaque_type == key)
 | |
| 				return functab;
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| /*------------------------------------------------------------------------*
 | |
|  * Followings are management functions for self-originated LSA entries.
 | |
|  *------------------------------------------------------------------------*/
 | |
| 
 | |
| /*
 | |
|  * Opaque-LSA control information per opaque-type.
 | |
|  * Single Opaque-Type may have multiple instances; each of them will be
 | |
|  * identified by their opaque-id.
 | |
|  */
 | |
| struct opaque_info_per_type {
 | |
| 	uint8_t lsa_type;
 | |
| 	uint8_t opaque_type;
 | |
| 
 | |
| 	enum { PROC_NORMAL, PROC_SUSPEND } status;
 | |
| 
 | |
| 	/*
 | |
| 	 * Thread for (re-)origination scheduling for this opaque-type.
 | |
| 	 *
 | |
| 	 * Initial origination of Opaque-LSAs is controlled by generic
 | |
| 	 * Opaque-LSA handling module so that same opaque-type entries are
 | |
| 	 * called all at once when certain conditions are met.
 | |
| 	 * However, there might be cases that some Opaque-LSA clients need
 | |
| 	 * to (re-)originate their own Opaque-LSAs out-of-sync with others.
 | |
| 	 * This thread is prepared for that specific purpose.
 | |
| 	 */
 | |
| 	struct thread *t_opaque_lsa_self;
 | |
| 
 | |
| 	/*
 | |
| 	 * Backpointer to an "owner" which is LSA-type dependent.
 | |
| 	 *   type-9:  struct ospf_interface
 | |
| 	 *   type-10: struct ospf_area
 | |
| 	 *   type-11: struct ospf
 | |
| 	 */
 | |
| 	void *owner;
 | |
| 
 | |
| 	/* Collection of callback functions for this opaque-type. */
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 
 | |
| 	/* List of Opaque-LSA control information per opaque-id. */
 | |
| 	struct list *id_list;
 | |
| };
 | |
| 
 | |
| /* Opaque-LSA control information per opaque-id. */
 | |
| struct opaque_info_per_id {
 | |
| 	uint32_t opaque_id;
 | |
| 
 | |
| 	/* Thread for refresh/flush scheduling for this opaque-type/id. */
 | |
| 	struct thread *t_opaque_lsa_self;
 | |
| 
 | |
| 	/* Backpointer to Opaque-LSA control information per opaque-type. */
 | |
| 	struct opaque_info_per_type *opqctl_type;
 | |
| 
 | |
| 	/* Here comes an actual Opaque-LSA entry for this opaque-type/id. */
 | |
| 	struct ospf_lsa *lsa;
 | |
| };
 | |
| 
 | |
| static struct opaque_info_per_type *
 | |
| register_opaque_info_per_type(struct ospf_opaque_functab *functab,
 | |
| 			      struct ospf_lsa *new);
 | |
| static struct opaque_info_per_type *
 | |
| lookup_opaque_info_by_type(struct ospf_lsa *lsa);
 | |
| static struct opaque_info_per_id *
 | |
| register_opaque_info_per_id(struct opaque_info_per_type *oipt,
 | |
| 			    struct ospf_lsa *new);
 | |
| static struct opaque_info_per_id *
 | |
| lookup_opaque_info_by_id(struct opaque_info_per_type *oipt,
 | |
| 			 struct ospf_lsa *lsa);
 | |
| static struct opaque_info_per_id *register_opaque_lsa(struct ospf_lsa *new);
 | |
| 
 | |
| 
 | |
| static struct opaque_info_per_type *
 | |
| register_opaque_info_per_type(struct ospf_opaque_functab *functab,
 | |
| 			      struct ospf_lsa *new)
 | |
| {
 | |
| 	struct ospf *top;
 | |
| 	struct opaque_info_per_type *oipt;
 | |
| 
 | |
| 	oipt = XCALLOC(MTYPE_OPAQUE_INFO_PER_TYPE,
 | |
| 		       sizeof(struct opaque_info_per_type));
 | |
| 
 | |
| 	switch (new->data->type) {
 | |
| 	case OSPF_OPAQUE_LINK_LSA:
 | |
| 		oipt->owner = new->oi;
 | |
| 		listnode_add(new->oi->opaque_lsa_self, oipt);
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AREA_LSA:
 | |
| 		oipt->owner = new->area;
 | |
| 		listnode_add(new->area->opaque_lsa_self, oipt);
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AS_LSA:
 | |
| 		top = ospf_lookup_by_vrf_id(new->vrf_id);
 | |
| 		if (new->area != NULL && (top = new->area->ospf) == NULL) {
 | |
| 			free_opaque_info_owner(oipt);
 | |
| 			free_opaque_info_per_type(oipt);
 | |
| 			oipt = NULL;
 | |
| 			goto out; /* This case may not exist. */
 | |
| 		}
 | |
| 		oipt->owner = top;
 | |
| 		listnode_add(top->opaque_lsa_self, oipt);
 | |
| 		break;
 | |
| 	default:
 | |
| 		flog_warn(
 | |
| 			EC_OSPF_LSA_UNEXPECTED,
 | |
| 			"register_opaque_info_per_type: Unexpected LSA-type(%u)",
 | |
| 			new->data->type);
 | |
| 		free_opaque_info_owner(oipt);
 | |
| 		free_opaque_info_per_type(oipt);
 | |
| 		oipt = NULL;
 | |
| 		goto out; /* This case may not exist. */
 | |
| 	}
 | |
| 
 | |
| 	oipt->lsa_type = new->data->type;
 | |
| 	oipt->opaque_type = GET_OPAQUE_TYPE(ntohl(new->data->id.s_addr));
 | |
| 	oipt->status = PROC_NORMAL;
 | |
| 	oipt->t_opaque_lsa_self = NULL;
 | |
| 	oipt->functab = functab;
 | |
| 	functab->oipt = oipt;
 | |
| 	oipt->id_list = list_new();
 | |
| 	oipt->id_list->del = free_opaque_info_per_id;
 | |
| 
 | |
| out:
 | |
| 	return oipt;
 | |
| }
 | |
| 
 | |
| /* Remove "oipt" from its owner's self-originated LSA list. */
 | |
| static void free_opaque_info_owner(void *val)
 | |
| {
 | |
| 	struct opaque_info_per_type *oipt = (struct opaque_info_per_type *)val;
 | |
| 
 | |
| 	switch (oipt->lsa_type) {
 | |
| 	case OSPF_OPAQUE_LINK_LSA: {
 | |
| 		struct ospf_interface *oi =
 | |
| 			(struct ospf_interface *)(oipt->owner);
 | |
| 		listnode_delete(oi->opaque_lsa_self, oipt);
 | |
| 		break;
 | |
| 	}
 | |
| 	case OSPF_OPAQUE_AREA_LSA: {
 | |
| 		struct ospf_area *area = (struct ospf_area *)(oipt->owner);
 | |
| 		listnode_delete(area->opaque_lsa_self, oipt);
 | |
| 		break;
 | |
| 	}
 | |
| 	case OSPF_OPAQUE_AS_LSA: {
 | |
| 		struct ospf *top = (struct ospf *)(oipt->owner);
 | |
| 		listnode_delete(top->opaque_lsa_self, oipt);
 | |
| 		break;
 | |
| 	}
 | |
| 	default:
 | |
| 		flog_warn(EC_OSPF_LSA_UNEXPECTED,
 | |
| 			  "free_opaque_info_owner: Unexpected LSA-type(%u)",
 | |
| 			  oipt->lsa_type);
 | |
| 		break; /* This case may not exist. */
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void free_opaque_info_per_type(void *val)
 | |
| {
 | |
| 	struct opaque_info_per_type *oipt = (struct opaque_info_per_type *)val;
 | |
| 	struct opaque_info_per_id *oipi;
 | |
| 	struct ospf_lsa *lsa;
 | |
| 	struct listnode *node, *nnode;
 | |
| 
 | |
| 	/* Control information per opaque-id may still exist. */
 | |
| 	for (ALL_LIST_ELEMENTS(oipt->id_list, node, nnode, oipi)) {
 | |
| 		if ((lsa = oipi->lsa) == NULL)
 | |
| 			continue;
 | |
| 		if (IS_LSA_MAXAGE(lsa))
 | |
| 			continue;
 | |
| 		ospf_opaque_lsa_flush_schedule(lsa);
 | |
| 	}
 | |
| 
 | |
| 	OSPF_TIMER_OFF(oipt->t_opaque_lsa_self);
 | |
| 	list_delete(&oipt->id_list);
 | |
| 	XFREE(MTYPE_OPAQUE_INFO_PER_TYPE, oipt);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static struct opaque_info_per_type *
 | |
| lookup_opaque_info_by_type(struct ospf_lsa *lsa)
 | |
| {
 | |
| 	struct ospf *top;
 | |
| 	struct ospf_area *area;
 | |
| 	struct ospf_interface *oi;
 | |
| 	struct list *listtop = NULL;
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct opaque_info_per_type *oipt = NULL;
 | |
| 	uint8_t key = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr));
 | |
| 
 | |
| 	switch (lsa->data->type) {
 | |
| 	case OSPF_OPAQUE_LINK_LSA:
 | |
| 		if ((oi = lsa->oi) != NULL)
 | |
| 			listtop = oi->opaque_lsa_self;
 | |
| 		else
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"Type-9 Opaque-LSA: Reference to OI is missing?");
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AREA_LSA:
 | |
| 		if ((area = lsa->area) != NULL)
 | |
| 			listtop = area->opaque_lsa_self;
 | |
| 		else
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"Type-10 Opaque-LSA: Reference to AREA is missing?");
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AS_LSA:
 | |
| 		top = ospf_lookup_by_vrf_id(lsa->vrf_id);
 | |
| 		if ((area = lsa->area) != NULL && (top = area->ospf) == NULL) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"Type-11 Opaque-LSA: Reference to OSPF is missing?");
 | |
| 			break; /* Unlikely to happen. */
 | |
| 		}
 | |
| 		listtop = top->opaque_lsa_self;
 | |
| 		break;
 | |
| 	default:
 | |
| 		flog_warn(EC_OSPF_LSA_UNEXPECTED,
 | |
| 			  "lookup_opaque_info_by_type: Unexpected LSA-type(%u)",
 | |
| 			  lsa->data->type);
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	if (listtop != NULL)
 | |
| 		for (ALL_LIST_ELEMENTS(listtop, node, nnode, oipt))
 | |
| 			if (oipt->opaque_type == key)
 | |
| 				return oipt;
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| static struct opaque_info_per_id *
 | |
| register_opaque_info_per_id(struct opaque_info_per_type *oipt,
 | |
| 			    struct ospf_lsa *new)
 | |
| {
 | |
| 	struct opaque_info_per_id *oipi;
 | |
| 
 | |
| 	oipi = XCALLOC(MTYPE_OPAQUE_INFO_PER_ID,
 | |
| 		       sizeof(struct opaque_info_per_id));
 | |
| 
 | |
| 	oipi->opaque_id = GET_OPAQUE_ID(ntohl(new->data->id.s_addr));
 | |
| 	oipi->t_opaque_lsa_self = NULL;
 | |
| 	oipi->opqctl_type = oipt;
 | |
| 	oipi->lsa = ospf_lsa_lock(new);
 | |
| 
 | |
| 	listnode_add(oipt->id_list, oipi);
 | |
| 
 | |
| 	return oipi;
 | |
| }
 | |
| 
 | |
| static void free_opaque_info_per_id(void *val)
 | |
| {
 | |
| 	struct opaque_info_per_id *oipi = (struct opaque_info_per_id *)val;
 | |
| 
 | |
| 	OSPF_TIMER_OFF(oipi->t_opaque_lsa_self);
 | |
| 	if (oipi->lsa != NULL)
 | |
| 		ospf_lsa_unlock(&oipi->lsa);
 | |
| 	XFREE(MTYPE_OPAQUE_INFO_PER_ID, oipi);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static struct opaque_info_per_id *
 | |
| lookup_opaque_info_by_id(struct opaque_info_per_type *oipt,
 | |
| 			 struct ospf_lsa *lsa)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct opaque_info_per_id *oipi;
 | |
| 	uint32_t key = GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr));
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(oipt->id_list, node, nnode, oipi))
 | |
| 		if (oipi->opaque_id == key)
 | |
| 			return oipi;
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| static struct opaque_info_per_id *register_opaque_lsa(struct ospf_lsa *new)
 | |
| {
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 	struct opaque_info_per_type *oipt;
 | |
| 	struct opaque_info_per_id *oipi = NULL;
 | |
| 
 | |
| 	if ((functab = ospf_opaque_functab_lookup(new)) == NULL)
 | |
| 		goto out;
 | |
| 
 | |
| 	if ((oipt = lookup_opaque_info_by_type(new)) == NULL
 | |
| 	    && (oipt = register_opaque_info_per_type(functab, new)) == NULL)
 | |
| 		goto out;
 | |
| 
 | |
| 	if ((oipi = register_opaque_info_per_id(oipt, new)) == NULL)
 | |
| 		goto out;
 | |
| 
 | |
| out:
 | |
| 	return oipi;
 | |
| }
 | |
| 
 | |
| /*------------------------------------------------------------------------*
 | |
|  * Followings are (vty) configuration functions for Opaque-LSAs handling.
 | |
|  *------------------------------------------------------------------------*/
 | |
| 
 | |
| DEFUN (capability_opaque,
 | |
|        capability_opaque_cmd,
 | |
|        "capability opaque",
 | |
|        "Enable specific OSPF feature\n"
 | |
|        "Opaque LSA\n")
 | |
| {
 | |
| 	VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 | |
| 
 | |
| 	/* Turn on the "master switch" of opaque-lsa capability. */
 | |
| 	if (!CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE)) {
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug("Opaque capability: OFF -> ON");
 | |
| 
 | |
| 		SET_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE);
 | |
| 		ospf_renegotiate_optional_capabilities(ospf);
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (ospf_opaque,
 | |
|        ospf_opaque_cmd,
 | |
|        "ospf opaque-lsa",
 | |
|        "OSPF specific commands\n"
 | |
|        "Enable the Opaque-LSA capability (rfc2370)\n")
 | |
| {
 | |
| 	return capability_opaque(self, vty, argc, argv);
 | |
| }
 | |
| 
 | |
| DEFUN (no_capability_opaque,
 | |
|        no_capability_opaque_cmd,
 | |
|        "no capability opaque",
 | |
|        NO_STR
 | |
|        "Enable specific OSPF feature\n"
 | |
|        "Opaque LSA\n")
 | |
| {
 | |
| 	VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
 | |
| 
 | |
| 	/* Turn off the "master switch" of opaque-lsa capability. */
 | |
| 	if (CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE)) {
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug("Opaque capability: ON -> OFF");
 | |
| 
 | |
| 		UNSET_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE);
 | |
| 		ospf_renegotiate_optional_capabilities(ospf);
 | |
| 	}
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_ospf_opaque,
 | |
|        no_ospf_opaque_cmd,
 | |
|        "no ospf opaque-lsa",
 | |
|        NO_STR
 | |
|        "OSPF specific commands\n"
 | |
|        "Enable the Opaque-LSA capability (rfc2370)\n")
 | |
| {
 | |
| 	return no_capability_opaque(self, vty, argc, argv);
 | |
| }
 | |
| 
 | |
| static void ospf_opaque_register_vty(void)
 | |
| {
 | |
| 	install_element(OSPF_NODE, &capability_opaque_cmd);
 | |
| 	install_element(OSPF_NODE, &no_capability_opaque_cmd);
 | |
| 	install_element(OSPF_NODE, &ospf_opaque_cmd);
 | |
| 	install_element(OSPF_NODE, &no_ospf_opaque_cmd);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| /*------------------------------------------------------------------------*
 | |
|  * Followings are collection of user-registered function callers.
 | |
|  *------------------------------------------------------------------------*/
 | |
| 
 | |
| static int opaque_lsa_new_if_callback(struct list *funclist,
 | |
| 				      struct interface *ifp)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 	int rc = -1;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
 | |
| 		if (functab->new_if_hook != NULL)
 | |
| 			if ((*functab->new_if_hook)(ifp) != 0)
 | |
| 				goto out;
 | |
| 	rc = 0;
 | |
| out:
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static int opaque_lsa_del_if_callback(struct list *funclist,
 | |
| 				      struct interface *ifp)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 	int rc = -1;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
 | |
| 		if (functab->del_if_hook != NULL)
 | |
| 			if ((*functab->del_if_hook)(ifp) != 0)
 | |
| 				goto out;
 | |
| 	rc = 0;
 | |
| out:
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static void opaque_lsa_ism_change_callback(struct list *funclist,
 | |
| 					   struct ospf_interface *oi,
 | |
| 					   int old_status)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
 | |
| 		if (functab->ism_change_hook != NULL)
 | |
| 			(*functab->ism_change_hook)(oi, old_status);
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static void opaque_lsa_nsm_change_callback(struct list *funclist,
 | |
| 					   struct ospf_neighbor *nbr,
 | |
| 					   int old_status)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
 | |
| 		if (functab->nsm_change_hook != NULL)
 | |
| 			(*functab->nsm_change_hook)(nbr, old_status);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static void opaque_lsa_config_write_router_callback(struct list *funclist,
 | |
| 						    struct vty *vty)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
 | |
| 		if (functab->config_write_router != NULL)
 | |
| 			(*functab->config_write_router)(vty);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static void opaque_lsa_config_write_if_callback(struct list *funclist,
 | |
| 						struct vty *vty,
 | |
| 						struct interface *ifp)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
 | |
| 		if (functab->config_write_if != NULL)
 | |
| 			(*functab->config_write_if)(vty, ifp);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static void opaque_lsa_config_write_debug_callback(struct list *funclist,
 | |
| 						   struct vty *vty)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
 | |
| 		if (functab->config_write_debug != NULL)
 | |
| 			(*functab->config_write_debug)(vty);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static int opaque_lsa_originate_callback(struct list *funclist,
 | |
| 					 void *lsa_type_dependent)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 	int rc = -1;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
 | |
| 		if (functab->lsa_originator != NULL)
 | |
| 			if ((*functab->lsa_originator)(lsa_type_dependent) != 0)
 | |
| 				goto out;
 | |
| 	rc = 0;
 | |
| out:
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static int new_lsa_callback(struct list *funclist, struct ospf_lsa *lsa)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 	int rc = -1;
 | |
| 
 | |
| 	/* This function handles ALL types of LSAs, not only opaque ones. */
 | |
| 	for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
 | |
| 		if (functab->new_lsa_hook != NULL)
 | |
| 			if ((*functab->new_lsa_hook)(lsa) != 0)
 | |
| 				goto out;
 | |
| 	rc = 0;
 | |
| out:
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static int del_lsa_callback(struct list *funclist, struct ospf_lsa *lsa)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 	int rc = -1;
 | |
| 
 | |
| 	/* This function handles ALL types of LSAs, not only opaque ones. */
 | |
| 	for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
 | |
| 		if (functab->del_lsa_hook != NULL)
 | |
| 			if ((*functab->del_lsa_hook)(lsa) != 0)
 | |
| 				goto out;
 | |
| 	rc = 0;
 | |
| out:
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| /*------------------------------------------------------------------------*
 | |
|  * Followings are glue functions to call Opaque-LSA specific processing.
 | |
|  *------------------------------------------------------------------------*/
 | |
| 
 | |
| int ospf_opaque_new_if(struct interface *ifp)
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 	int rc = -1;
 | |
| 
 | |
| 	funclist = ospf_opaque_wildcard_funclist;
 | |
| 	if (opaque_lsa_new_if_callback(funclist, ifp) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	funclist = ospf_opaque_type9_funclist;
 | |
| 	if (opaque_lsa_new_if_callback(funclist, ifp) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	funclist = ospf_opaque_type10_funclist;
 | |
| 	if (opaque_lsa_new_if_callback(funclist, ifp) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	funclist = ospf_opaque_type11_funclist;
 | |
| 	if (opaque_lsa_new_if_callback(funclist, ifp) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	rc = 0;
 | |
| out:
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| int ospf_opaque_del_if(struct interface *ifp)
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 	int rc = -1;
 | |
| 
 | |
| 	funclist = ospf_opaque_wildcard_funclist;
 | |
| 	if (opaque_lsa_del_if_callback(funclist, ifp) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	funclist = ospf_opaque_type9_funclist;
 | |
| 	if (opaque_lsa_del_if_callback(funclist, ifp) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	funclist = ospf_opaque_type10_funclist;
 | |
| 	if (opaque_lsa_del_if_callback(funclist, ifp) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	funclist = ospf_opaque_type11_funclist;
 | |
| 	if (opaque_lsa_del_if_callback(funclist, ifp) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	rc = 0;
 | |
| out:
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_ism_change(struct ospf_interface *oi, int old_status)
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 
 | |
| 	funclist = ospf_opaque_wildcard_funclist;
 | |
| 	opaque_lsa_ism_change_callback(funclist, oi, old_status);
 | |
| 
 | |
| 	funclist = ospf_opaque_type9_funclist;
 | |
| 	opaque_lsa_ism_change_callback(funclist, oi, old_status);
 | |
| 
 | |
| 	funclist = ospf_opaque_type10_funclist;
 | |
| 	opaque_lsa_ism_change_callback(funclist, oi, old_status);
 | |
| 
 | |
| 	funclist = ospf_opaque_type11_funclist;
 | |
| 	opaque_lsa_ism_change_callback(funclist, oi, old_status);
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_nsm_change(struct ospf_neighbor *nbr, int old_state)
 | |
| {
 | |
| 	struct ospf *top;
 | |
| 	struct list *funclist;
 | |
| 
 | |
| 	if ((top = oi_to_top(nbr->oi)) == NULL)
 | |
| 		goto out;
 | |
| 
 | |
| 	if (old_state != NSM_Full && nbr->state == NSM_Full) {
 | |
| 		if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)) {
 | |
| 			if (!CHECK_FLAG(top->opaque,
 | |
| 					OPAQUE_OPERATION_READY_BIT)) {
 | |
| 				if (IS_DEBUG_OSPF_EVENT)
 | |
| 					zlog_debug(
 | |
| 						"Opaque-LSA: Now get operational!");
 | |
| 
 | |
| 				SET_FLAG(top->opaque,
 | |
| 					 OPAQUE_OPERATION_READY_BIT);
 | |
| 			}
 | |
| 
 | |
| 			ospf_opaque_lsa_originate_schedule(nbr->oi, NULL);
 | |
| 		}
 | |
| 	} else if (old_state == NSM_Full && nbr->state != NSM_Full) {
 | |
| #ifdef NOTYET
 | |
| /*
 | |
|  * If no more opaque-capable full-state neighbor remains in the
 | |
|  * flooding scope which corresponds to Opaque-LSA type, periodic
 | |
|  * LS flooding should be stopped.
 | |
|  */
 | |
| #endif /* NOTYET */
 | |
| 		;
 | |
| 	}
 | |
| 
 | |
| 	funclist = ospf_opaque_wildcard_funclist;
 | |
| 	opaque_lsa_nsm_change_callback(funclist, nbr, old_state);
 | |
| 
 | |
| 	funclist = ospf_opaque_type9_funclist;
 | |
| 	opaque_lsa_nsm_change_callback(funclist, nbr, old_state);
 | |
| 
 | |
| 	funclist = ospf_opaque_type10_funclist;
 | |
| 	opaque_lsa_nsm_change_callback(funclist, nbr, old_state);
 | |
| 
 | |
| 	funclist = ospf_opaque_type11_funclist;
 | |
| 	opaque_lsa_nsm_change_callback(funclist, nbr, old_state);
 | |
| 
 | |
| out:
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_config_write_router(struct vty *vty, struct ospf *ospf)
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 
 | |
| 	if (CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE))
 | |
| 		vty_out(vty, " capability opaque\n");
 | |
| 
 | |
| 	funclist = ospf_opaque_wildcard_funclist;
 | |
| 	opaque_lsa_config_write_router_callback(funclist, vty);
 | |
| 
 | |
| 	funclist = ospf_opaque_type9_funclist;
 | |
| 	opaque_lsa_config_write_router_callback(funclist, vty);
 | |
| 
 | |
| 	funclist = ospf_opaque_type10_funclist;
 | |
| 	opaque_lsa_config_write_router_callback(funclist, vty);
 | |
| 
 | |
| 	funclist = ospf_opaque_type11_funclist;
 | |
| 	opaque_lsa_config_write_router_callback(funclist, vty);
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_config_write_if(struct vty *vty, struct interface *ifp)
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 
 | |
| 	funclist = ospf_opaque_wildcard_funclist;
 | |
| 	opaque_lsa_config_write_if_callback(funclist, vty, ifp);
 | |
| 
 | |
| 	funclist = ospf_opaque_type9_funclist;
 | |
| 	opaque_lsa_config_write_if_callback(funclist, vty, ifp);
 | |
| 
 | |
| 	funclist = ospf_opaque_type10_funclist;
 | |
| 	opaque_lsa_config_write_if_callback(funclist, vty, ifp);
 | |
| 
 | |
| 	funclist = ospf_opaque_type11_funclist;
 | |
| 	opaque_lsa_config_write_if_callback(funclist, vty, ifp);
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_config_write_debug(struct vty *vty)
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 
 | |
| 	funclist = ospf_opaque_wildcard_funclist;
 | |
| 	opaque_lsa_config_write_debug_callback(funclist, vty);
 | |
| 
 | |
| 	funclist = ospf_opaque_type9_funclist;
 | |
| 	opaque_lsa_config_write_debug_callback(funclist, vty);
 | |
| 
 | |
| 	funclist = ospf_opaque_type10_funclist;
 | |
| 	opaque_lsa_config_write_debug_callback(funclist, vty);
 | |
| 
 | |
| 	funclist = ospf_opaque_type11_funclist;
 | |
| 	opaque_lsa_config_write_debug_callback(funclist, vty);
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa)
 | |
| {
 | |
| 	struct lsa_header *lsah = (struct lsa_header *)lsa->data;
 | |
| 	uint32_t lsid = ntohl(lsah->id.s_addr);
 | |
| 	uint8_t opaque_type = GET_OPAQUE_TYPE(lsid);
 | |
| 	uint32_t opaque_id = GET_OPAQUE_ID(lsid);
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 
 | |
| 	/* Switch output functionality by vty address. */
 | |
| 	if (vty != NULL) {
 | |
| 		vty_out(vty, "  Opaque-Type %u (%s)\n", opaque_type,
 | |
| 			ospf_opaque_type_name(opaque_type));
 | |
| 		vty_out(vty, "  Opaque-ID   0x%x\n", opaque_id);
 | |
| 
 | |
| 		vty_out(vty, "  Opaque-Info: %u octets of data%s\n",
 | |
| 			ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE,
 | |
| 			VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)");
 | |
| 	} else {
 | |
| 		zlog_debug("    Opaque-Type %u (%s)", opaque_type,
 | |
| 			   ospf_opaque_type_name(opaque_type));
 | |
| 		zlog_debug("    Opaque-ID   0x%x", opaque_id);
 | |
| 
 | |
| 		zlog_debug("    Opaque-Info: %u octets of data%s",
 | |
| 			   ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE,
 | |
| 			   VALID_OPAQUE_INFO_LEN(lsah) ? ""
 | |
| 						       : "(Invalid length?)");
 | |
| 	}
 | |
| 
 | |
| 	/* Call individual output functions. */
 | |
| 	if ((functab = ospf_opaque_functab_lookup(lsa)) != NULL)
 | |
| 		if (functab->show_opaque_info != NULL)
 | |
| 			(*functab->show_opaque_info)(vty, lsa);
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_lsa_dump(struct stream *s, uint16_t length)
 | |
| {
 | |
| 	struct ospf_lsa lsa;
 | |
| 
 | |
| 	lsa.data = (struct lsa_header *)stream_pnt(s);
 | |
| 	show_opaque_info_detail(NULL, &lsa);
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static int ospf_opaque_lsa_install_hook(struct ospf_lsa *lsa)
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 	int rc = -1;
 | |
| 
 | |
| 	/*
 | |
| 	 * Some Opaque-LSA user may want to monitor every LSA installation
 | |
| 	 * into the LSDB, regardless with target LSA type.
 | |
| 	 */
 | |
| 	funclist = ospf_opaque_wildcard_funclist;
 | |
| 	if (new_lsa_callback(funclist, lsa) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	funclist = ospf_opaque_type9_funclist;
 | |
| 	if (new_lsa_callback(funclist, lsa) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	funclist = ospf_opaque_type10_funclist;
 | |
| 	if (new_lsa_callback(funclist, lsa) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	funclist = ospf_opaque_type11_funclist;
 | |
| 	if (new_lsa_callback(funclist, lsa) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	rc = 0;
 | |
| out:
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static int ospf_opaque_lsa_delete_hook(struct ospf_lsa *lsa)
 | |
| {
 | |
| 	struct list *funclist;
 | |
| 	int rc = -1;
 | |
| 
 | |
| 	/*
 | |
| 	 * Some Opaque-LSA user may want to monitor every LSA deletion
 | |
| 	 * from the LSDB, regardless with target LSA type.
 | |
| 	 */
 | |
| 	funclist = ospf_opaque_wildcard_funclist;
 | |
| 	if (del_lsa_callback(funclist, lsa) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	funclist = ospf_opaque_type9_funclist;
 | |
| 	if (del_lsa_callback(funclist, lsa) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	funclist = ospf_opaque_type10_funclist;
 | |
| 	if (del_lsa_callback(funclist, lsa) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	funclist = ospf_opaque_type11_funclist;
 | |
| 	if (del_lsa_callback(funclist, lsa) != 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	rc = 0;
 | |
| out:
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| /*------------------------------------------------------------------------*
 | |
|  * Followings are Opaque-LSA origination/refresh management functions.
 | |
|  *------------------------------------------------------------------------*/
 | |
| 
 | |
| static int ospf_opaque_type9_lsa_originate(struct thread *t);
 | |
| static int ospf_opaque_type10_lsa_originate(struct thread *t);
 | |
| static int ospf_opaque_type11_lsa_originate(struct thread *t);
 | |
| static void ospf_opaque_lsa_reoriginate_resume(struct list *listtop, void *arg);
 | |
| 
 | |
| void ospf_opaque_lsa_originate_schedule(struct ospf_interface *oi, int *delay0)
 | |
| {
 | |
| 	struct ospf *top;
 | |
| 	struct ospf_area *area;
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct opaque_info_per_type *oipt;
 | |
| 	int delay = 0;
 | |
| 
 | |
| 	if ((top = oi_to_top(oi)) == NULL || (area = oi->area) == NULL) {
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug(
 | |
| 				"ospf_opaque_lsa_originate_schedule: Invalid argument?");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* It may not a right time to schedule origination now. */
 | |
| 	if (!CHECK_FLAG(top->opaque, OPAQUE_OPERATION_READY_BIT)) {
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug(
 | |
| 				"ospf_opaque_lsa_originate_schedule: Not operational.");
 | |
| 		return; /* This is not an error. */
 | |
| 	}
 | |
| 
 | |
| 	if (delay0 != NULL)
 | |
| 		delay = *delay0;
 | |
| 
 | |
| 	/*
 | |
| 	 * There might be some entries that have been waiting for triggering
 | |
| 	 * of per opaque-type re-origination get resumed.
 | |
| 	 */
 | |
| 	ospf_opaque_lsa_reoriginate_resume(oi->opaque_lsa_self, (void *)oi);
 | |
| 	ospf_opaque_lsa_reoriginate_resume(area->opaque_lsa_self, (void *)area);
 | |
| 	ospf_opaque_lsa_reoriginate_resume(top->opaque_lsa_self, (void *)top);
 | |
| 
 | |
| 	/*
 | |
| 	 * Now, schedule origination of all Opaque-LSAs per opaque-type.
 | |
| 	 */
 | |
| 	if (!list_isempty(ospf_opaque_type9_funclist)
 | |
| 	    && list_isempty(oi->opaque_lsa_self)
 | |
| 	    && oi->t_opaque_lsa_self == NULL) {
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug(
 | |
| 				"Schedule Type-9 Opaque-LSA origination in %d ms later.",
 | |
| 				delay);
 | |
| 		oi->t_opaque_lsa_self = NULL;
 | |
| 		thread_add_timer_msec(master, ospf_opaque_type9_lsa_originate,
 | |
| 				      oi, delay, &oi->t_opaque_lsa_self);
 | |
| 		delay += top->min_ls_interval;
 | |
| 	}
 | |
| 
 | |
| 	if (!list_isempty(ospf_opaque_type10_funclist)
 | |
| 	    && list_isempty(area->opaque_lsa_self)
 | |
| 	    && area->t_opaque_lsa_self == NULL) {
 | |
| 		/*
 | |
| 		 * One AREA may contain multiple OIs, but above 2nd and 3rd
 | |
| 		 * conditions prevent from scheduling the originate function
 | |
| 		 * again and again.
 | |
| 		 */
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug(
 | |
| 				"Schedule Type-10 Opaque-LSA origination in %d ms later.",
 | |
| 				delay);
 | |
| 		area->t_opaque_lsa_self = NULL;
 | |
| 		thread_add_timer_msec(master, ospf_opaque_type10_lsa_originate,
 | |
| 				      area, delay, &area->t_opaque_lsa_self);
 | |
| 		delay += top->min_ls_interval;
 | |
| 	}
 | |
| 
 | |
| 	if (!list_isempty(ospf_opaque_type11_funclist)
 | |
| 	    && list_isempty(top->opaque_lsa_self)
 | |
| 	    && top->t_opaque_lsa_self == NULL) {
 | |
| 		/*
 | |
| 		 * One OSPF may contain multiple AREAs, but above 2nd and 3rd
 | |
| 		 * conditions prevent from scheduling the originate function
 | |
| 		 * again and again.
 | |
| 		 */
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug(
 | |
| 				"Schedule Type-11 Opaque-LSA origination in %d ms later.",
 | |
| 				delay);
 | |
| 		top->t_opaque_lsa_self = NULL;
 | |
| 		thread_add_timer_msec(master, ospf_opaque_type11_lsa_originate,
 | |
| 				      top, delay, &top->t_opaque_lsa_self);
 | |
| 		delay += top->min_ls_interval;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Following section treats a special situation that this node's
 | |
| 	 * opaque capability has changed as "ON -> OFF -> ON".
 | |
| 	 */
 | |
| 	if (!list_isempty(ospf_opaque_type9_funclist)
 | |
| 	    && !list_isempty(oi->opaque_lsa_self)) {
 | |
| 		for (ALL_LIST_ELEMENTS(oi->opaque_lsa_self, node, nnode,
 | |
| 				       oipt)) {
 | |
| 			/*
 | |
| 			 * removed the test for
 | |
| 			 *   (! list_isempty (oipt->id_list))   * Handler is
 | |
| 			 * already active. *
 | |
| 			 * because opaque cababilities ON -> OFF -> ON result in
 | |
| 			 * list_isempty (oipt->id_list)
 | |
| 			 * not being empty.
 | |
| 			 */
 | |
| 			if (oipt->t_opaque_lsa_self
 | |
| 				    != NULL /* Waiting for a thread call. */
 | |
| 			    || oipt->status == PROC_SUSPEND) /* Cannot
 | |
| 								originate
 | |
| 								now. */
 | |
| 				continue;
 | |
| 
 | |
| 			ospf_opaque_lsa_reoriginate_schedule(
 | |
| 				(void *)oi, OSPF_OPAQUE_LINK_LSA,
 | |
| 				oipt->opaque_type);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (!list_isempty(ospf_opaque_type10_funclist)
 | |
| 	    && !list_isempty(area->opaque_lsa_self)) {
 | |
| 		for (ALL_LIST_ELEMENTS(area->opaque_lsa_self, node, nnode,
 | |
| 				       oipt)) {
 | |
| 			/*
 | |
| 			 * removed the test for
 | |
| 			 *   (! list_isempty (oipt->id_list))   * Handler is
 | |
| 			 * already active. *
 | |
| 			 * because opaque cababilities ON -> OFF -> ON result in
 | |
| 			 * list_isempty (oipt->id_list)
 | |
| 			 * not being empty.
 | |
| 			 */
 | |
| 			if (oipt->t_opaque_lsa_self
 | |
| 				    != NULL /* Waiting for a thread call. */
 | |
| 			    || oipt->status == PROC_SUSPEND) /* Cannot
 | |
| 								originate
 | |
| 								now. */
 | |
| 				continue;
 | |
| 
 | |
| 			ospf_opaque_lsa_reoriginate_schedule(
 | |
| 				(void *)area, OSPF_OPAQUE_AREA_LSA,
 | |
| 				oipt->opaque_type);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (!list_isempty(ospf_opaque_type11_funclist)
 | |
| 	    && !list_isempty(top->opaque_lsa_self)) {
 | |
| 		for (ALL_LIST_ELEMENTS(top->opaque_lsa_self, node, nnode,
 | |
| 				       oipt)) {
 | |
| 			/*
 | |
| 			 * removed the test for
 | |
| 			 *   (! list_isempty (oipt->id_list))   * Handler is
 | |
| 			 * already active. *
 | |
| 			 * because opaque cababilities ON -> OFF -> ON result in
 | |
| 			 * list_isempty (oipt->id_list)
 | |
| 			 * not being empty.
 | |
| 			 */
 | |
| 			if (oipt->t_opaque_lsa_self
 | |
| 				    != NULL /* Waiting for a thread call. */
 | |
| 			    || oipt->status == PROC_SUSPEND) /* Cannot
 | |
| 								originate
 | |
| 								now. */
 | |
| 				continue;
 | |
| 
 | |
| 			ospf_opaque_lsa_reoriginate_schedule((void *)top,
 | |
| 							     OSPF_OPAQUE_AS_LSA,
 | |
| 							     oipt->opaque_type);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (delay0 != NULL)
 | |
| 		*delay0 = delay;
 | |
| }
 | |
| 
 | |
| static int ospf_opaque_type9_lsa_originate(struct thread *t)
 | |
| {
 | |
| 	struct ospf_interface *oi;
 | |
| 	int rc;
 | |
| 
 | |
| 	oi = THREAD_ARG(t);
 | |
| 	oi->t_opaque_lsa_self = NULL;
 | |
| 
 | |
| 	if (IS_DEBUG_OSPF_EVENT)
 | |
| 		zlog_debug("Timer[Type9-LSA]: Originate Opaque-LSAs for OI %s",
 | |
| 			   IF_NAME(oi));
 | |
| 
 | |
| 	rc = opaque_lsa_originate_callback(ospf_opaque_type9_funclist, oi);
 | |
| 
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static int ospf_opaque_type10_lsa_originate(struct thread *t)
 | |
| {
 | |
| 	struct ospf_area *area;
 | |
| 	int rc;
 | |
| 
 | |
| 	area = THREAD_ARG(t);
 | |
| 	area->t_opaque_lsa_self = NULL;
 | |
| 
 | |
| 	if (IS_DEBUG_OSPF_EVENT)
 | |
| 		zlog_debug(
 | |
| 			"Timer[Type10-LSA]: Originate Opaque-LSAs for Area %s",
 | |
| 			inet_ntoa(area->area_id));
 | |
| 
 | |
| 	rc = opaque_lsa_originate_callback(ospf_opaque_type10_funclist, area);
 | |
| 
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static int ospf_opaque_type11_lsa_originate(struct thread *t)
 | |
| {
 | |
| 	struct ospf *top;
 | |
| 	int rc;
 | |
| 
 | |
| 	top = THREAD_ARG(t);
 | |
| 	top->t_opaque_lsa_self = NULL;
 | |
| 
 | |
| 	if (IS_DEBUG_OSPF_EVENT)
 | |
| 		zlog_debug(
 | |
| 			"Timer[Type11-LSA]: Originate AS-External Opaque-LSAs");
 | |
| 
 | |
| 	rc = opaque_lsa_originate_callback(ospf_opaque_type11_funclist, top);
 | |
| 
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static void ospf_opaque_lsa_reoriginate_resume(struct list *listtop, void *arg)
 | |
| {
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct opaque_info_per_type *oipt;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 
 | |
| 	if (listtop == NULL)
 | |
| 		goto out;
 | |
| 
 | |
| 	/*
 | |
| 	 * Pickup oipt entries those which in SUSPEND status, and give
 | |
| 	 * them a chance to start re-origination now.
 | |
| 	 */
 | |
| 	for (ALL_LIST_ELEMENTS(listtop, node, nnode, oipt)) {
 | |
| 		if (oipt->status != PROC_SUSPEND)
 | |
| 			continue;
 | |
| 
 | |
| 		oipt->status = PROC_NORMAL;
 | |
| 
 | |
| 		if ((functab = oipt->functab) == NULL
 | |
| 		    || functab->lsa_originator == NULL)
 | |
| 			continue;
 | |
| 
 | |
| 		if ((*functab->lsa_originator)(arg) != 0) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"ospf_opaque_lsa_reoriginate_resume: Failed (opaque-type=%u)",
 | |
| 				oipt->opaque_type);
 | |
| 			continue;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| out:
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| struct ospf_lsa *ospf_opaque_lsa_install(struct ospf_lsa *lsa, int rt_recalc)
 | |
| {
 | |
| 	struct ospf_lsa *new = NULL;
 | |
| 	struct opaque_info_per_type *oipt;
 | |
| 	struct opaque_info_per_id *oipi;
 | |
| 	struct ospf *top;
 | |
| 
 | |
| 	/* Don't take "rt_recalc" into consideration for now. */ /* XXX */
 | |
| 
 | |
| 	if (!IS_LSA_SELF(lsa)) {
 | |
| 		new = lsa; /* Don't touch this LSA. */
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	if (IS_DEBUG_OSPF(lsa, LSA_INSTALL))
 | |
| 		zlog_debug(
 | |
| 			"Install Type-%u Opaque-LSA: [opaque-type=%u, opaque-id=%x]",
 | |
| 			lsa->data->type,
 | |
| 			GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)),
 | |
| 			GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)));
 | |
| 
 | |
| 	/* Replace the existing lsa with the new one. */
 | |
| 	if ((oipt = lookup_opaque_info_by_type(lsa)) != NULL
 | |
| 	    && (oipi = lookup_opaque_info_by_id(oipt, lsa)) != NULL) {
 | |
| 		ospf_lsa_unlock(&oipi->lsa);
 | |
| 		oipi->lsa = ospf_lsa_lock(lsa);
 | |
| 	}
 | |
| 	/* Register the new lsa entry and get its control info. */
 | |
| 	else if ((oipi = register_opaque_lsa(lsa)) == NULL) {
 | |
| 		flog_warn(EC_OSPF_LSA,
 | |
| 			  "ospf_opaque_lsa_install: register_opaque_lsa() ?");
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Make use of a common mechanism (ospf_lsa_refresh_walker)
 | |
| 	 * for periodic refresh of self-originated Opaque-LSAs.
 | |
| 	 */
 | |
| 	switch (lsa->data->type) {
 | |
| 	case OSPF_OPAQUE_LINK_LSA:
 | |
| 		if ((top = oi_to_top(lsa->oi)) == NULL) {
 | |
| 			/* Above conditions must have passed. */
 | |
| 			flog_warn(EC_OSPF_LSA,
 | |
| 				  "ospf_opaque_lsa_install: Something wrong?");
 | |
| 			goto out;
 | |
| 		}
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AREA_LSA:
 | |
| 		if (lsa->area == NULL || (top = lsa->area->ospf) == NULL) {
 | |
| 			/* Above conditions must have passed. */
 | |
| 			flog_warn(EC_OSPF_LSA,
 | |
| 				  "ospf_opaque_lsa_install: Something wrong?");
 | |
| 			goto out;
 | |
| 		}
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AS_LSA:
 | |
| 		top = ospf_lookup_by_vrf_id(lsa->vrf_id);
 | |
| 		if (lsa->area != NULL && (top = lsa->area->ospf) == NULL) {
 | |
| 			/* Above conditions must have passed. */
 | |
| 			flog_warn(EC_OSPF_LSA,
 | |
| 				  "ospf_opaque_lsa_install: Something wrong?");
 | |
| 			goto out;
 | |
| 		}
 | |
| 		break;
 | |
| 	default:
 | |
| 		flog_warn(EC_OSPF_LSA_UNEXPECTED,
 | |
| 			  "ospf_opaque_lsa_install: Unexpected LSA-type(%u)",
 | |
| 			  lsa->data->type);
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	ospf_refresher_register_lsa(top, lsa);
 | |
| 	new = lsa;
 | |
| 
 | |
| out:
 | |
| 	return new;
 | |
| }
 | |
| 
 | |
| struct ospf_lsa *ospf_opaque_lsa_refresh(struct ospf_lsa *lsa)
 | |
| {
 | |
| 	struct ospf *ospf;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 	struct ospf_lsa *new = NULL;
 | |
| 
 | |
| 	ospf = ospf_lookup_by_vrf_id(lsa->vrf_id);
 | |
| 
 | |
| 	if ((functab = ospf_opaque_functab_lookup(lsa)) == NULL
 | |
| 	    || functab->lsa_refresher == NULL) {
 | |
| 		/*
 | |
| 		 * Though this LSA seems to have originated on this node, the
 | |
| 		 * handling module for this "lsa-type and opaque-type" was
 | |
| 		 * already deleted sometime ago.
 | |
| 		 * Anyway, this node still has a responsibility to flush this
 | |
| 		 * LSA from the routing domain.
 | |
| 		 */
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug("LSA[Type%d:%s]: Flush stray Opaque-LSA",
 | |
| 				   lsa->data->type, inet_ntoa(lsa->data->id));
 | |
| 
 | |
| 		lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
 | |
| 		ospf_lsa_flush(ospf, lsa);
 | |
| 	} else
 | |
| 		new = (*functab->lsa_refresher)(lsa);
 | |
| 
 | |
| 	return new;
 | |
| }
 | |
| 
 | |
| /*------------------------------------------------------------------------*
 | |
|  * Followings are re-origination/refresh/flush operations of Opaque-LSAs,
 | |
|  * triggered by external interventions (vty session, signaling, etc).
 | |
|  *------------------------------------------------------------------------*/
 | |
| 
 | |
| #define OSPF_OPAQUE_TIMER_ON(T,F,L,V) thread_add_timer_msec (master, (F), (L), (V), &(T))
 | |
| 
 | |
| static struct ospf_lsa *pseudo_lsa(struct ospf_interface *oi,
 | |
| 				   struct ospf_area *area, uint8_t lsa_type,
 | |
| 				   uint8_t opaque_type);
 | |
| static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t);
 | |
| static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t);
 | |
| static int ospf_opaque_type11_lsa_reoriginate_timer(struct thread *t);
 | |
| static int ospf_opaque_lsa_refresh_timer(struct thread *t);
 | |
| 
 | |
| void ospf_opaque_lsa_reoriginate_schedule(void *lsa_type_dependent,
 | |
| 					  uint8_t lsa_type, uint8_t opaque_type)
 | |
| {
 | |
| 	struct ospf *top = NULL;
 | |
| 	struct ospf_area dummy, *area = NULL;
 | |
| 	struct ospf_interface *oi = NULL;
 | |
| 
 | |
| 	struct ospf_lsa *lsa;
 | |
| 	struct opaque_info_per_type *oipt;
 | |
| 	int (*func)(struct thread * t) = NULL;
 | |
| 	int delay;
 | |
| 
 | |
| 	switch (lsa_type) {
 | |
| 	case OSPF_OPAQUE_LINK_LSA:
 | |
| 		if ((oi = (struct ospf_interface *)lsa_type_dependent)
 | |
| 		    == NULL) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"ospf_opaque_lsa_reoriginate_schedule: Type-9 Opaque-LSA: Invalid parameter?");
 | |
| 			goto out;
 | |
| 		}
 | |
| 		if ((top = oi_to_top(oi)) == NULL) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"ospf_opaque_lsa_reoriginate_schedule: OI(%s) -> TOP?",
 | |
| 				IF_NAME(oi));
 | |
| 			goto out;
 | |
| 		}
 | |
| 		if (!list_isempty(ospf_opaque_type9_funclist)
 | |
| 		    && list_isempty(oi->opaque_lsa_self)
 | |
| 		    && oi->t_opaque_lsa_self != NULL) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"Type-9 Opaque-LSA (opaque_type=%u): Common origination for OI(%s) has already started",
 | |
| 				opaque_type, IF_NAME(oi));
 | |
| 			goto out;
 | |
| 		}
 | |
| 		func = ospf_opaque_type9_lsa_reoriginate_timer;
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AREA_LSA:
 | |
| 		if ((area = (struct ospf_area *)lsa_type_dependent) == NULL) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"ospf_opaque_lsa_reoriginate_schedule: Type-10 Opaque-LSA: Invalid parameter?");
 | |
| 			goto out;
 | |
| 		}
 | |
| 		if ((top = area->ospf) == NULL) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"ospf_opaque_lsa_reoriginate_schedule: AREA(%s) -> TOP?",
 | |
| 				inet_ntoa(area->area_id));
 | |
| 			goto out;
 | |
| 		}
 | |
| 		if (!list_isempty(ospf_opaque_type10_funclist)
 | |
| 		    && list_isempty(area->opaque_lsa_self)
 | |
| 		    && area->t_opaque_lsa_self != NULL) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"Type-10 Opaque-LSA (opaque_type=%u): Common origination for AREA(%s) has already started",
 | |
| 				opaque_type, inet_ntoa(area->area_id));
 | |
| 			goto out;
 | |
| 		}
 | |
| 		func = ospf_opaque_type10_lsa_reoriginate_timer;
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AS_LSA:
 | |
| 		if ((top = (struct ospf *)lsa_type_dependent) == NULL) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"ospf_opaque_lsa_reoriginate_schedule: Type-11 Opaque-LSA: Invalid parameter?");
 | |
| 			goto out;
 | |
| 		}
 | |
| 		if (!list_isempty(ospf_opaque_type11_funclist)
 | |
| 		    && list_isempty(top->opaque_lsa_self)
 | |
| 		    && top->t_opaque_lsa_self != NULL) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"Type-11 Opaque-LSA (opaque_type=%u): Common origination has already started",
 | |
| 				opaque_type);
 | |
| 			goto out;
 | |
| 		}
 | |
| 
 | |
| 		/* Fake "area" to pass "ospf" to a lookup function later. */
 | |
| 		dummy.ospf = top;
 | |
| 		area = &dummy;
 | |
| 
 | |
| 		func = ospf_opaque_type11_lsa_reoriginate_timer;
 | |
| 		break;
 | |
| 	default:
 | |
| 		flog_warn(
 | |
| 			EC_OSPF_LSA_UNEXPECTED,
 | |
| 			"ospf_opaque_lsa_reoriginate_schedule: Unexpected LSA-type(%u)",
 | |
| 			lsa_type);
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* It may not a right time to schedule reorigination now. */
 | |
| 	if (!CHECK_FLAG(top->opaque, OPAQUE_OPERATION_READY_BIT)) {
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug(
 | |
| 				"ospf_opaque_lsa_reoriginate_schedule: Not operational.");
 | |
| 		goto out; /* This is not an error. */
 | |
| 	}
 | |
| 
 | |
| 	/* Generate a dummy lsa to be passed for a lookup function. */
 | |
| 	lsa = pseudo_lsa(oi, area, lsa_type, opaque_type);
 | |
| 	lsa->vrf_id = top->vrf_id;
 | |
| 
 | |
| 	if ((oipt = lookup_opaque_info_by_type(lsa)) == NULL) {
 | |
| 		struct ospf_opaque_functab *functab;
 | |
| 		if ((functab = ospf_opaque_functab_lookup(lsa)) == NULL) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"ospf_opaque_lsa_reoriginate_schedule: No associated function?: lsa_type(%u), opaque_type(%u)",
 | |
| 				lsa_type, opaque_type);
 | |
| 			goto out;
 | |
| 		}
 | |
| 		if ((oipt = register_opaque_info_per_type(functab, lsa))
 | |
| 		    == NULL) {
 | |
| 			flog_warn(
 | |
| 				EC_OSPF_LSA,
 | |
| 				"ospf_opaque_lsa_reoriginate_schedule: Cannot get a control info?: lsa_type(%u), opaque_type(%u)",
 | |
| 				lsa_type, opaque_type);
 | |
| 			goto out;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (oipt->t_opaque_lsa_self != NULL) {
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug(
 | |
| 				"Type-%u Opaque-LSA has already scheduled to"
 | |
| 				" RE-ORIGINATE: [opaque-type=%u]",
 | |
| 				lsa_type,
 | |
| 				GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)));
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Different from initial origination time, in which various conditions
 | |
| 	 * (opaque capability, neighbor status etc) are assured by caller of
 | |
| 	 * the originating function "ospf_opaque_lsa_originate_schedule ()",
 | |
| 	 * it is highly possible that these conditions might not be satisfied
 | |
| 	 * at the time of re-origination function is to be called.
 | |
| 	 */
 | |
| 	delay = top->min_ls_interval; /* XXX */
 | |
| 
 | |
| 	if (IS_DEBUG_OSPF_EVENT)
 | |
| 		zlog_debug(
 | |
| 			"Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d"
 | |
| 			" ms later: [opaque-type=%u]",
 | |
| 			lsa_type, delay,
 | |
| 			GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)));
 | |
| 
 | |
| 	OSPF_OPAQUE_TIMER_ON(oipt->t_opaque_lsa_self, func, oipt, delay);
 | |
| 
 | |
| out:
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static struct ospf_lsa *pseudo_lsa(struct ospf_interface *oi,
 | |
| 				   struct ospf_area *area, uint8_t lsa_type,
 | |
| 				   uint8_t opaque_type)
 | |
| {
 | |
| 	static struct ospf_lsa lsa = {0};
 | |
| 	static struct lsa_header lsah = {0};
 | |
| 	uint32_t tmp;
 | |
| 
 | |
| 	lsa.oi = oi;
 | |
| 	lsa.area = area;
 | |
| 	lsa.data = &lsah;
 | |
| 	lsa.vrf_id = VRF_DEFAULT;
 | |
| 
 | |
| 	lsah.type = lsa_type;
 | |
| 	tmp = SET_OPAQUE_LSID(opaque_type, 0); /* Opaque-ID is unused here. */
 | |
| 	lsah.id.s_addr = htonl(tmp);
 | |
| 
 | |
| 	return &lsa;
 | |
| }
 | |
| 
 | |
| static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t)
 | |
| {
 | |
| 	struct opaque_info_per_type *oipt;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 	struct ospf *top;
 | |
| 	struct ospf_interface *oi;
 | |
| 	int rc = -1;
 | |
| 
 | |
| 	oipt = THREAD_ARG(t);
 | |
| 	oipt->t_opaque_lsa_self = NULL;
 | |
| 
 | |
| 	if ((functab = oipt->functab) == NULL
 | |
| 	    || functab->lsa_originator == NULL) {
 | |
| 		flog_warn(
 | |
| 			EC_OSPF_LSA,
 | |
| 			"ospf_opaque_type9_lsa_reoriginate_timer: No associated function?");
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	oi = (struct ospf_interface *)oipt->owner;
 | |
| 	if ((top = oi_to_top(oi)) == NULL) {
 | |
| 		flog_warn(
 | |
| 			EC_OSPF_LSA,
 | |
| 			"ospf_opaque_type9_lsa_reoriginate_timer: Something wrong?");
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	if (!CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE)
 | |
| 	    || !ospf_if_is_enable(oi)
 | |
| 	    || ospf_nbr_count_opaque_capable(oi) == 0) {
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug(
 | |
| 				"Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...",
 | |
| 				oipt->opaque_type);
 | |
| 
 | |
| 		oipt->status = PROC_SUSPEND;
 | |
| 		rc = 0;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	if (IS_DEBUG_OSPF_EVENT)
 | |
| 		zlog_debug(
 | |
| 			"Timer[Type9-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for OI (%s)",
 | |
| 			oipt->opaque_type, IF_NAME(oi));
 | |
| 
 | |
| 	rc = (*functab->lsa_originator)(oi);
 | |
| out:
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t)
 | |
| {
 | |
| 	struct opaque_info_per_type *oipt;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 	struct listnode *node, *nnode;
 | |
| 	struct ospf *top;
 | |
| 	struct ospf_area *area;
 | |
| 	struct ospf_interface *oi;
 | |
| 	int n, rc = -1;
 | |
| 
 | |
| 	oipt = THREAD_ARG(t);
 | |
| 	oipt->t_opaque_lsa_self = NULL;
 | |
| 
 | |
| 	if ((functab = oipt->functab) == NULL
 | |
| 	    || functab->lsa_originator == NULL) {
 | |
| 		flog_warn(
 | |
| 			EC_OSPF_LSA,
 | |
| 			"ospf_opaque_type10_lsa_reoriginate_timer: No associated function?");
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	area = (struct ospf_area *)oipt->owner;
 | |
| 	if (area == NULL || (top = area->ospf) == NULL) {
 | |
| 		flog_warn(
 | |
| 			EC_OSPF_LSA,
 | |
| 			"ospf_opaque_type10_lsa_reoriginate_timer: Something wrong?");
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* There must be at least one "opaque-capable, full-state" neighbor. */
 | |
| 	n = 0;
 | |
| 	for (ALL_LIST_ELEMENTS(area->oiflist, node, nnode, oi)) {
 | |
| 		if ((n = ospf_nbr_count_opaque_capable(oi)) > 0)
 | |
| 			break;
 | |
| 	}
 | |
| 
 | |
| 	if (n == 0 || !CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE)) {
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug(
 | |
| 				"Suspend re-origination of Type-10 Opaque-LSAs"
 | |
| 				" (opaque-type=%u) for a while...",
 | |
| 				oipt->opaque_type);
 | |
| 
 | |
| 		oipt->status = PROC_SUSPEND;
 | |
| 		rc = 0;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	if (IS_DEBUG_OSPF_EVENT)
 | |
| 		zlog_debug(
 | |
| 			"Timer[Type10-LSA]: Re-originate Opaque-LSAs"
 | |
| 			" (opaque-type=%u) for Area %s",
 | |
| 			oipt->opaque_type, inet_ntoa(area->area_id));
 | |
| 
 | |
| 	rc = (*functab->lsa_originator)(area);
 | |
| out:
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static int ospf_opaque_type11_lsa_reoriginate_timer(struct thread *t)
 | |
| {
 | |
| 	struct opaque_info_per_type *oipt;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 	struct ospf *top;
 | |
| 	int rc = -1;
 | |
| 
 | |
| 	oipt = THREAD_ARG(t);
 | |
| 	oipt->t_opaque_lsa_self = NULL;
 | |
| 
 | |
| 	if ((functab = oipt->functab) == NULL
 | |
| 	    || functab->lsa_originator == NULL) {
 | |
| 		flog_warn(
 | |
| 			EC_OSPF_LSA,
 | |
| 			"ospf_opaque_type11_lsa_reoriginate_timer: No associated function?");
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	if ((top = (struct ospf *)oipt->owner) == NULL) {
 | |
| 		flog_warn(
 | |
| 			EC_OSPF_LSA,
 | |
| 			"ospf_opaque_type11_lsa_reoriginate_timer: Something wrong?");
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	if (!CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE)) {
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug(
 | |
| 				"Suspend re-origination of Type-11 Opaque-LSAs (opaque-type=%u) for a while...",
 | |
| 				oipt->opaque_type);
 | |
| 
 | |
| 		oipt->status = PROC_SUSPEND;
 | |
| 		rc = 0;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	if (IS_DEBUG_OSPF_EVENT)
 | |
| 		zlog_debug(
 | |
| 			"Timer[Type11-LSA]: Re-originate Opaque-LSAs (opaque-type=%u).",
 | |
| 			oipt->opaque_type);
 | |
| 
 | |
| 	rc = (*functab->lsa_originator)(top);
 | |
| out:
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_lsa_refresh_schedule(struct ospf_lsa *lsa0)
 | |
| {
 | |
| 	struct opaque_info_per_type *oipt;
 | |
| 	struct opaque_info_per_id *oipi;
 | |
| 	struct ospf_lsa *lsa;
 | |
| 	struct ospf *top;
 | |
| 	int delay;
 | |
| 
 | |
| 	if ((oipt = lookup_opaque_info_by_type(lsa0)) == NULL
 | |
| 	    || (oipi = lookup_opaque_info_by_id(oipt, lsa0)) == NULL) {
 | |
| 		flog_warn(
 | |
| 			EC_OSPF_LSA,
 | |
| 			"ospf_opaque_lsa_refresh_schedule: Invalid parameter?");
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
 | |
| 	if ((lsa = oipi->lsa) == NULL) {
 | |
| 		flog_warn(EC_OSPF_LSA,
 | |
| 			  "ospf_opaque_lsa_refresh_schedule: Something wrong?");
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	if (oipi->t_opaque_lsa_self != NULL) {
 | |
| 		if (IS_DEBUG_OSPF_EVENT)
 | |
| 			zlog_debug(
 | |
| 				"Type-%u Opaque-LSA has already scheduled to REFRESH: [opaque-type=%u, opaque-id=%x]",
 | |
| 				lsa->data->type,
 | |
| 				GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)),
 | |
| 				GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)));
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* Delete this lsa from neighbor retransmit-list. */
 | |
| 	switch (lsa->data->type) {
 | |
| 	case OSPF_OPAQUE_LINK_LSA:
 | |
| 	case OSPF_OPAQUE_AREA_LSA:
 | |
| 		ospf_ls_retransmit_delete_nbr_area(lsa->area, lsa);
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AS_LSA:
 | |
| 		top = ospf_lookup_by_vrf_id(lsa0->vrf_id);
 | |
| 		if ((lsa0->area != NULL) && (lsa0->area->ospf != NULL))
 | |
| 			top = lsa0->area->ospf;
 | |
| 		ospf_ls_retransmit_delete_nbr_as(top, lsa);
 | |
| 		break;
 | |
| 	default:
 | |
| 		flog_warn(
 | |
| 			EC_OSPF_LSA_UNEXPECTED,
 | |
| 			"ospf_opaque_lsa_refresh_schedule: Unexpected LSA-type(%u)",
 | |
| 			lsa->data->type);
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	delay = ospf_lsa_refresh_delay(lsa);
 | |
| 
 | |
| 	if (IS_DEBUG_OSPF_EVENT)
 | |
| 		zlog_debug(
 | |
| 			"Schedule Type-%u Opaque-LSA to REFRESH in %d sec later: [opaque-type=%u, opaque-id=%x]",
 | |
| 			lsa->data->type, delay,
 | |
| 			GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)),
 | |
| 			GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)));
 | |
| 
 | |
| 	OSPF_OPAQUE_TIMER_ON(oipi->t_opaque_lsa_self,
 | |
| 			     ospf_opaque_lsa_refresh_timer, oipi, delay * 1000);
 | |
| out:
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static int ospf_opaque_lsa_refresh_timer(struct thread *t)
 | |
| {
 | |
| 	struct opaque_info_per_id *oipi;
 | |
| 	struct ospf_opaque_functab *functab;
 | |
| 	struct ospf_lsa *lsa;
 | |
| 
 | |
| 	if (IS_DEBUG_OSPF_EVENT)
 | |
| 		zlog_debug("Timer[Opaque-LSA]: (Opaque-LSA Refresh expire)");
 | |
| 
 | |
| 	oipi = THREAD_ARG(t);
 | |
| 	oipi->t_opaque_lsa_self = NULL;
 | |
| 
 | |
| 	if ((lsa = oipi->lsa) != NULL)
 | |
| 		if ((functab = oipi->opqctl_type->functab) != NULL)
 | |
| 			if (functab->lsa_refresher != NULL)
 | |
| 				(*functab->lsa_refresher)(lsa);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_lsa_flush_schedule(struct ospf_lsa *lsa0)
 | |
| {
 | |
| 	struct opaque_info_per_type *oipt;
 | |
| 	struct opaque_info_per_id *oipi;
 | |
| 	struct ospf_lsa *lsa;
 | |
| 	struct ospf *top;
 | |
| 
 | |
| 	top = ospf_lookup_by_vrf_id(lsa0->vrf_id);
 | |
| 
 | |
| 	if ((oipt = lookup_opaque_info_by_type(lsa0)) == NULL
 | |
| 	    || (oipi = lookup_opaque_info_by_id(oipt, lsa0)) == NULL) {
 | |
| 		flog_warn(EC_OSPF_LSA,
 | |
| 			  "ospf_opaque_lsa_flush_schedule: Invalid parameter?");
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
 | |
| 	if ((lsa = oipi->lsa) == NULL) {
 | |
| 		flog_warn(EC_OSPF_LSA,
 | |
| 			  "ospf_opaque_lsa_flush_schedule: Something wrong?");
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* Delete this lsa from neighbor retransmit-list. */
 | |
| 	switch (lsa->data->type) {
 | |
| 	case OSPF_OPAQUE_LINK_LSA:
 | |
| 	case OSPF_OPAQUE_AREA_LSA:
 | |
| 		ospf_ls_retransmit_delete_nbr_area(lsa->area, lsa);
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AS_LSA:
 | |
| 		if ((lsa0->area != NULL) && (lsa0->area->ospf != NULL))
 | |
| 			top = lsa0->area->ospf;
 | |
| 		ospf_ls_retransmit_delete_nbr_as(top, lsa);
 | |
| 		break;
 | |
| 	default:
 | |
| 		flog_warn(
 | |
| 			EC_OSPF_LSA_UNEXPECTED,
 | |
| 			"ospf_opaque_lsa_flush_schedule: Unexpected LSA-type(%u)",
 | |
| 			lsa->data->type);
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* Dequeue listnode entry from the list. */
 | |
| 	listnode_delete(oipt->id_list, oipi);
 | |
| 
 | |
| 	/* Disassociate internal control information with the given lsa. */
 | |
| 	free_opaque_info_per_id((void *)oipi);
 | |
| 
 | |
| 	/* Force given lsa's age to MaxAge. */
 | |
| 	lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
 | |
| 
 | |
| 	if (IS_DEBUG_OSPF_EVENT)
 | |
| 		zlog_debug(
 | |
| 			"Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]",
 | |
| 			lsa->data->type,
 | |
| 			GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)),
 | |
| 			GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)));
 | |
| 
 | |
| 	/* This lsa will be flushed and removed eventually. */
 | |
| 	ospf_lsa_flush(top, lsa);
 | |
| 
 | |
| out:
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| void ospf_opaque_self_originated_lsa_received(struct ospf_neighbor *nbr,
 | |
| 					      struct ospf_lsa *lsa)
 | |
| {
 | |
| 	struct ospf *top;
 | |
| 
 | |
| 	if ((top = oi_to_top(nbr->oi)) == NULL)
 | |
| 		return;
 | |
| 
 | |
| 	/*
 | |
| 	 * Since these LSA entries are not yet installed into corresponding
 | |
| 	 * LSDB, just flush them without calling ospf_ls_maxage() afterward.
 | |
| 	 */
 | |
| 	lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
 | |
| 	switch (lsa->data->type) {
 | |
| 	case OSPF_OPAQUE_LINK_LSA:
 | |
| 		ospf_flood_through_area(nbr->oi->area, NULL /*inbr*/, lsa);
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AREA_LSA:
 | |
| 		ospf_flood_through_area(nbr->oi->area, NULL /*inbr*/, lsa);
 | |
| 		break;
 | |
| 	case OSPF_OPAQUE_AS_LSA:
 | |
| 		ospf_flood_through_as(top, NULL /*inbr*/, lsa);
 | |
| 		break;
 | |
| 	default:
 | |
| 		flog_warn(
 | |
| 			EC_OSPF_LSA_UNEXPECTED,
 | |
| 			"ospf_opaque_self_originated_lsa_received: Unexpected LSA-type(%u)",
 | |
| 			lsa->data->type);
 | |
| 		return;
 | |
| 	}
 | |
| 	ospf_lsa_discard(lsa); /* List "lsas" will be deleted by caller. */
 | |
| }
 | |
| 
 | |
| /*------------------------------------------------------------------------*
 | |
|  * Followings are util functions; probably be used by Opaque-LSAs only...
 | |
|  *------------------------------------------------------------------------*/
 | |
| 
 | |
| struct ospf *oi_to_top(struct ospf_interface *oi)
 | |
| {
 | |
| 	struct ospf *top = NULL;
 | |
| 	struct ospf_area *area;
 | |
| 
 | |
| 	if (oi == NULL || (area = oi->area) == NULL
 | |
| 	    || (top = area->ospf) == NULL)
 | |
| 		flog_warn(EC_OSPF_LSA,
 | |
| 			  "Broken relationship for \"OI -> AREA -> OSPF\"?");
 | |
| 
 | |
| 	return top;
 | |
| }
 |