mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-10-31 21:46:33 +00:00 
			
		
		
		
	 ac7424f9de
			
		
	
	
		ac7424f9de
		
	
	
	
	
		
			
			Allow configuration of faster OSPF convergence via the min_ls_interval and min_ls_arrival timer lengths. This patch was originated by Michael, and cross-ported to Cumulus's Quagga. Signed-off-by: Michael Rossberg <michael.rossberg@tu-ilmenau.de> Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
		
			
				
	
	
		
			2488 lines
		
	
	
		
			70 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2488 lines
		
	
	
		
			70 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 GNU Zebra; see the file COPYING.  If not, write to the Free
 | |
|  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 | |
|  * 02111-1307, USA.
 | |
|  */
 | |
| 
 | |
| /***** MTYPE definitions are not reflected to "memory.h" yet. *****/
 | |
| #define MTYPE_OSPF_OPAQUE_FUNCTAB	0
 | |
| #define MTYPE_OPAQUE_INFO_PER_TYPE	0
 | |
| #define MTYPE_OPAQUE_INFO_PER_ID	0
 | |
| 
 | |
| #include <zebra.h>
 | |
| #ifdef HAVE_OPAQUE_LSA
 | |
| 
 | |
| #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"
 | |
| 
 | |
| /*------------------------------------------------------------------------*
 | |
|  * Followings are initialize/terminate functions for Opaque-LSAs handling.
 | |
|  *------------------------------------------------------------------------*/
 | |
| 
 | |
| #ifdef HAVE_OSPF_TE
 | |
| #include "ospfd/ospf_te.h"
 | |
| #endif /* HAVE_OSPF_TE */
 | |
| 
 | |
| #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 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 ();
 | |
| 
 | |
| #ifdef HAVE_OSPF_TE
 | |
|   if (ospf_mpls_te_init () != 0)
 | |
|     exit (1);
 | |
| #endif /* HAVE_OSPF_TE */
 | |
| 
 | |
| #ifdef SUPPORT_OSPF_API
 | |
|   if ((ospf_apiserver_enable) && (ospf_apiserver_init () != 0))
 | |
|     exit (1);
 | |
| #endif /* SUPPORT_OSPF_API */
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| void
 | |
| ospf_opaque_term (void)
 | |
| {
 | |
| #ifdef HAVE_OSPF_TE
 | |
|   ospf_mpls_te_term ();
 | |
| #endif /* HAVE_OSPF_TE */
 | |
| 
 | |
| #ifdef SUPPORT_OSPF_API
 | |
|   ospf_apiserver_term ();
 | |
| #endif /* SUPPORT_OSPF_API */
 | |
| 
 | |
|   ospf_opaque_funclist_term ();
 | |
|   return;
 | |
| }
 | |
| 
 | |
| 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);
 | |
|   area->opaque_lsa_self = NULL;
 | |
|   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);
 | |
|   top->opaque_lsa_self = NULL;
 | |
|   return;
 | |
| }
 | |
| 
 | |
| static const char *
 | |
| ospf_opaque_type_name (u_char 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;
 | |
|     default:
 | |
|       if (OPAQUE_TYPE_RANGE_UNASSIGNED (opaque_type))
 | |
|         name = "Unassigned";
 | |
|       else
 | |
|         {
 | |
|           u_int32_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
 | |
| {
 | |
|   u_char 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 (u_char 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:
 | |
|       zlog_warn ("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 (
 | |
|   u_char lsa_type,
 | |
|   u_char 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;
 | |
|   int rc = -1;
 | |
| 
 | |
|   if ((funclist = ospf_get_opaque_funclist (lsa_type)) == NULL)
 | |
|     {
 | |
|       zlog_warn ("ospf_register_opaque_functab: Cannot get funclist"
 | |
|                  " for Type-%u LSAs?",
 | |
|                  lsa_type);
 | |
|       goto out;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       struct listnode *node, *nnode;
 | |
|       struct ospf_opaque_functab *functab;
 | |
|       
 | |
|       for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab))
 | |
|         if (functab->opaque_type == opaque_type)
 | |
|           {
 | |
|             zlog_warn ("ospf_register_opaque_functab: Duplicated entry?:"
 | |
|                        " lsa_type(%u), opaque_type(%u)", 
 | |
|                        lsa_type, opaque_type);
 | |
|             goto out;
 | |
|           }
 | |
|     }
 | |
| 
 | |
|   if ((new = XCALLOC (MTYPE_OSPF_OPAQUE_FUNCTAB,
 | |
| 		      sizeof (struct ospf_opaque_functab))) == NULL)
 | |
|     {
 | |
|       zlog_warn ("ospf_register_opaque_functab: XMALLOC: %s",
 | |
|                  safe_strerror (errno));
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   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);
 | |
|   rc = 0;
 | |
| 
 | |
| out:
 | |
|   return rc;
 | |
| }
 | |
| 
 | |
| void
 | |
| ospf_delete_opaque_functab (u_char lsa_type, u_char 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_per_type (functab->oipt);
 | |
| 
 | |
|             /* Dequeue listnode entry from the list. */
 | |
|             listnode_delete (funclist, functab);
 | |
| 
 | |
|             /* Avoid misjudgement in the next lookup. */
 | |
|             if (listcount (funclist) == 0)
 | |
|               funclist->head = funclist->tail = NULL;
 | |
| 
 | |
|             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;
 | |
|   u_char 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
 | |
| {
 | |
|   u_char lsa_type;
 | |
|   u_char 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 informations per opaque-id. */
 | |
|   struct list *id_list;
 | |
| };
 | |
| 
 | |
| /* Opaque-LSA control information per opaque-id. */
 | |
| struct opaque_info_per_id
 | |
| {
 | |
|   u_int32_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;
 | |
| 
 | |
|   if ((oipt = XCALLOC (MTYPE_OPAQUE_INFO_PER_TYPE,
 | |
| 		       sizeof (struct opaque_info_per_type))) == NULL)
 | |
|     {
 | |
|       zlog_warn ("register_opaque_info_per_type: XMALLOC: %s", safe_strerror (errno));
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   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 ();
 | |
|       if (new->area != NULL && (top = new->area->ospf) == NULL)
 | |
|         {
 | |
|           free_opaque_info_per_type ((void *) oipt);
 | |
|           oipt = NULL;
 | |
|           goto out; /* This case may not exist. */
 | |
|         }
 | |
|       oipt->owner = top;
 | |
|       listnode_add (top->opaque_lsa_self, oipt);
 | |
|       break;
 | |
|     default:
 | |
|       zlog_warn ("register_opaque_info_per_type: Unexpected LSA-type(%u)", new->data->type);
 | |
|       free_opaque_info_per_type ((void *) 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;
 | |
| }
 | |
| 
 | |
| 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);
 | |
|     }
 | |
| 
 | |
|   /* Remove "oipt" from its owner's self-originated LSA list. */
 | |
|   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:
 | |
|       zlog_warn ("free_opaque_info_per_type: Unexpected LSA-type(%u)", oipt->lsa_type);
 | |
|       break; /* This case may not exist. */
 | |
|     }
 | |
| 
 | |
|   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;
 | |
|   u_char 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
 | |
|         zlog_warn ("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
 | |
|         zlog_warn ("Type-10 Opaque-LSA: Reference to AREA is missing?");
 | |
|       break;
 | |
|     case OSPF_OPAQUE_AS_LSA:
 | |
|       top = ospf_lookup ();
 | |
|       if ((area = lsa->area) != NULL && (top = area->ospf) == NULL)
 | |
|         {
 | |
|           zlog_warn ("Type-11 Opaque-LSA: Reference to OSPF is missing?");
 | |
|           break; /* Unlikely to happen. */
 | |
|         }
 | |
|       listtop = top->opaque_lsa_self;
 | |
|       break;
 | |
|     default:
 | |
|       zlog_warn ("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;
 | |
| 
 | |
|   if ((oipi = XCALLOC (MTYPE_OPAQUE_INFO_PER_ID,
 | |
| 		       sizeof (struct opaque_info_per_id))) == NULL)
 | |
|     {
 | |
|       zlog_warn ("register_opaque_info_per_id: XMALLOC: %s", safe_strerror (errno));
 | |
|       goto out;
 | |
|     }
 | |
|   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);
 | |
| 
 | |
| out:
 | |
|   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;
 | |
|   u_int32_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")
 | |
| {
 | |
|   struct ospf *ospf = (struct ospf *) vty->index;
 | |
| 
 | |
|   if (!ospf)
 | |
|     return CMD_SUCCESS;
 | |
| 
 | |
|   /* 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;
 | |
| }
 | |
| 
 | |
| ALIAS (capability_opaque,
 | |
|        ospf_opaque_capable_cmd,
 | |
|        "ospf opaque-lsa",
 | |
|        "OSPF specific commands\n"
 | |
|        "Enable the Opaque-LSA capability (rfc2370)\n")
 | |
| 
 | |
| DEFUN (no_capability_opaque,
 | |
|        no_capability_opaque_cmd,
 | |
|        "no capability opaque",
 | |
|        NO_STR
 | |
|        "Enable specific OSPF feature\n"
 | |
|        "Opaque LSA\n")
 | |
| {
 | |
|   struct ospf *ospf = (struct ospf *) vty->index;
 | |
| 
 | |
|   if (!ospf)
 | |
|     return CMD_SUCCESS;
 | |
| 
 | |
|   /* 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;
 | |
| }
 | |
| 
 | |
| ALIAS (no_capability_opaque,
 | |
|        no_ospf_opaque_capable_cmd,
 | |
|        "no ospf opaque-lsa",
 | |
|        NO_STR
 | |
|        "OSPF specific commands\n"
 | |
|        "Disable the Opaque-LSA capability (rfc2370)\n")
 | |
| 
 | |
| 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_capable_cmd);
 | |
|   install_element (OSPF_NODE, &no_ospf_opaque_capable_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%s", VTY_NEWLINE);
 | |
| 
 | |
|   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;
 | |
|   u_int32_t lsid = ntohl (lsah->id.s_addr);
 | |
|   u_char    opaque_type = GET_OPAQUE_TYPE (lsid);
 | |
|   u_int32_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)%s", opaque_type,
 | |
| 	       ospf_opaque_type_name (opaque_type), VTY_NEWLINE);
 | |
|       vty_out (vty, "  Opaque-ID   0x%x%s", opaque_id, VTY_NEWLINE);
 | |
| 
 | |
|       vty_out (vty, "  Opaque-Info: %u octets of data%s%s",
 | |
|                ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE,
 | |
|                VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)",
 | |
|                VTY_NEWLINE);
 | |
|     }
 | |
|   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, u_int16_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)
 | |
|     {
 | |
|       zlog_warn ("ospf_opaque_lsa_originate_schedule: Invalid argument?");
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   /* 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.");
 | |
|       goto out; /* This is not an error. */
 | |
|     }
 | |
|   if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
 | |
|     {
 | |
|       if (IS_DEBUG_OSPF_EVENT)
 | |
|         zlog_debug ("ospf_opaque_lsa_originate_schedule: Under blockade.");
 | |
|       goto out; /* This is not an error, too. */
 | |
|     }
 | |
| 
 | |
|   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 =
 | |
| 	thread_add_timer_msec (master, ospf_opaque_type9_lsa_originate, oi, delay);
 | |
|       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 =
 | |
|         thread_add_timer_msec (master, ospf_opaque_type10_lsa_originate,
 | |
| 			       area, delay);
 | |
|       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 =
 | |
|         thread_add_timer_msec (master, ospf_opaque_type11_lsa_originate,
 | |
| 			       top, delay);
 | |
|       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;
 | |
| 
 | |
| out:
 | |
|   return;
 | |
| }
 | |
| 
 | |
| 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)
 | |
|         {
 | |
|           zlog_warn ("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)
 | |
|     {
 | |
|       zlog_warn ("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. */
 | |
|           zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?");
 | |
|           goto out;
 | |
|         }
 | |
|       break;
 | |
|     case OSPF_OPAQUE_AREA_LSA:
 | |
|       if (lsa->area == NULL || (top = lsa->area->ospf) == NULL)
 | |
|         {
 | |
|           /* Above conditions must have passed. */
 | |
|           zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?");
 | |
|           goto out;
 | |
|         }
 | |
|       break;
 | |
|     case OSPF_OPAQUE_AS_LSA:
 | |
|       top = ospf_lookup ();
 | |
|       if (lsa->area != NULL && (top = lsa->area->ospf) == NULL)
 | |
|         {
 | |
|           /* Above conditions must have passed. */
 | |
|           zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?");
 | |
|           goto out;
 | |
|         }
 | |
|       break;
 | |
|     default:
 | |
|       zlog_warn ("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 ();
 | |
| 
 | |
|   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) \
 | |
|       if (!(T)) \
 | |
|         (T) = thread_add_timer_msec (master, (F), (L), (V))
 | |
| 
 | |
| static struct ospf_lsa *pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, u_char lsa_type, u_char 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,
 | |
|                                       u_char lsa_type, u_char opaque_type)
 | |
| {
 | |
|   struct ospf *top;
 | |
|   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)
 | |
|         {
 | |
|           zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:"
 | |
|                      " Type-9 Opaque-LSA: Invalid parameter?");
 | |
|           goto out;
 | |
|         }
 | |
|       if ((top = oi_to_top (oi)) == NULL)
 | |
|         {
 | |
|           zlog_warn ("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)
 | |
|         {
 | |
|           zlog_warn ("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)
 | |
|         {
 | |
|           zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:"
 | |
|                      " Type-10 Opaque-LSA: Invalid parameter?");
 | |
|           goto out;
 | |
|         }
 | |
|       if ((top = area->ospf) == NULL)
 | |
|         {
 | |
|           zlog_warn ("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)
 | |
|         {
 | |
|           zlog_warn ("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)
 | |
|         {
 | |
|           zlog_warn ("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)
 | |
|         {
 | |
|           zlog_warn ("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:
 | |
|       zlog_warn ("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. */
 | |
|     }
 | |
|   if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
 | |
|     {
 | |
|       if (IS_DEBUG_OSPF_EVENT)
 | |
|         zlog_debug ("ospf_opaque_lsa_reoriginate_schedule: Under blockade.");
 | |
|       goto out;                 /* This is not an error, too. */
 | |
|     }
 | |
| 
 | |
|   /* Generate a dummy lsa to be passed for a lookup function. */
 | |
|   lsa = pseudo_lsa (oi, area, lsa_type, opaque_type);
 | |
| 
 | |
|   if ((oipt = lookup_opaque_info_by_type (lsa)) == NULL)
 | |
|     {
 | |
|       struct ospf_opaque_functab *functab;
 | |
|       if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL)
 | |
|         {
 | |
|           zlog_warn ("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)
 | |
|         {
 | |
|           zlog_warn ("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 * 1000);
 | |
| 
 | |
| out:
 | |
|   return;
 | |
| }
 | |
| 
 | |
| static struct ospf_lsa *
 | |
| pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area,
 | |
|             u_char lsa_type, u_char opaque_type)
 | |
| {
 | |
|   static struct ospf_lsa lsa = { 0 };
 | |
|   static struct lsa_header lsah = { 0 };
 | |
|   u_int32_t tmp;
 | |
| 
 | |
|   lsa.oi   = oi;
 | |
|   lsa.area = area;
 | |
|   lsa.data = &lsah;
 | |
| 
 | |
|   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)
 | |
|     {
 | |
|       zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: No associated function?");
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   oi = (struct ospf_interface *) oipt->owner;
 | |
|   if ((top = oi_to_top (oi)) == NULL)
 | |
|     {
 | |
|       zlog_warn ("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)
 | |
|     {
 | |
|       zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: No associated function?");
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   area = (struct ospf_area *) oipt->owner;
 | |
|   if (area == NULL || (top = area->ospf) == NULL)
 | |
|     {
 | |
|       zlog_warn ("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)
 | |
|     {
 | |
|       zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer:"
 | |
|                  " No associated function?");
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   if ((top = (struct ospf *) oipt->owner) == NULL)
 | |
|     {
 | |
|       zlog_warn ("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;
 | |
|   int delay;
 | |
| 
 | |
|   if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL
 | |
|   ||  (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL)
 | |
|     {
 | |
|       zlog_warn ("ospf_opaque_lsa_refresh_schedule: Invalid parameter?");
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
 | |
|   if ((lsa = oipi->lsa) == NULL)
 | |
|     {
 | |
|       zlog_warn ("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:
 | |
|       ospf_ls_retransmit_delete_nbr_as (lsa0->area->ospf, lsa);
 | |
|       break;
 | |
|     default:
 | |
|       zlog_warn ("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;
 | |
| 
 | |
|   if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL
 | |
|   ||  (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL)
 | |
|     {
 | |
|       zlog_warn ("ospf_opaque_lsa_flush_schedule: Invalid parameter?");
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|   /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
 | |
|   if ((lsa = oipi->lsa) == NULL)
 | |
|     {
 | |
|       zlog_warn ("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:
 | |
|       ospf_ls_retransmit_delete_nbr_as (lsa0->area->ospf, lsa);
 | |
|       break;
 | |
|     default:
 | |
|       zlog_warn ("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);
 | |
| 
 | |
|   /* Avoid misjudgement in the next lookup. */
 | |
|   if (listcount (oipt->id_list) == 0)
 | |
|     oipt->id_list->head = oipt->id_list->tail = NULL;
 | |
| 
 | |
|   /* 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 (lsa0->area->ospf, lsa);
 | |
| 
 | |
| out:
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /*------------------------------------------------------------------------*
 | |
|  * Followings are control functions to block origination after restart.
 | |
|  *------------------------------------------------------------------------*/
 | |
| 
 | |
| static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa);
 | |
| static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi);
 | |
| static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area);
 | |
| static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top);
 | |
| static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type);
 | |
| 
 | |
| void
 | |
| ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, struct list *lsas)
 | |
| {
 | |
|   struct ospf *top;
 | |
|   struct ospf_area *area;
 | |
|   struct ospf_interface *oi;
 | |
|   struct listnode *node1, *nnode1;
 | |
|   struct listnode *node2, *nnode2;
 | |
|   struct ospf_lsa *lsa;
 | |
| 
 | |
|   if ((top = oi_to_top (nbr->oi)) == NULL)
 | |
|     goto out;
 | |
| 
 | |
|   /*
 | |
|    * If an instance of self-originated Opaque-LSA is found in the given
 | |
|    * LSA list, and it is not installed to LSDB yet, exclude it from the
 | |
|    * list "nbr->ls_req". In this way, it is assured that an LSReq message,
 | |
|    * which might be sent in the process of flooding, will not request for
 | |
|    * the LSA to be flushed immediately; otherwise, depending on timing,
 | |
|    * an LSUpd message will carry instances of target LSAs with MaxAge,
 | |
|    * while other LSUpd message might carry old LSA instances (non-MaxAge).
 | |
|    * Obviously, the latter would trigger miserable situations that repeat
 | |
|    * installation and removal of unwanted LSAs indefinitely.
 | |
|    */
 | |
|   for (ALL_LIST_ELEMENTS (lsas, node1, nnode1, lsa))
 | |
|     {
 | |
|       /* Filter out unwanted LSAs. */
 | |
|       if (! IS_OPAQUE_LSA (lsa->data->type))
 | |
|         continue;
 | |
|       if (! IPV4_ADDR_SAME (&lsa->data->adv_router, &top->router_id))
 | |
|         continue;
 | |
| 
 | |
|       /*
 | |
|        * Don't touch an LSA which has MaxAge; two possible cases.
 | |
|        *
 | |
|        *   1) This LSA has originally flushed by myself (received LSUpd
 | |
|        *      message's router-id is equal to my router-id), and flooded
 | |
|        *      back by an opaque-capable router.
 | |
|        *
 | |
|        *   2) This LSA has expired in an opaque-capable router and thus
 | |
|        *      flushed by the router.
 | |
|        */
 | |
|       if (IS_LSA_MAXAGE (lsa))
 | |
|         continue;
 | |
| 
 | |
|       /* If the LSA has installed in the LSDB, nothing to do here. */
 | |
|       if (ospf_lsa_lookup_by_header (nbr->oi->area, lsa->data) != NULL)
 | |
|         continue;
 | |
| 
 | |
|       /* Ok, here we go. */
 | |
|       switch (lsa->data->type)
 | |
|         {
 | |
|         case OSPF_OPAQUE_LINK_LSA:
 | |
|           oi = nbr->oi;
 | |
|           ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa);
 | |
|           break;
 | |
|         case OSPF_OPAQUE_AREA_LSA:
 | |
|           area = nbr->oi->area;
 | |
|           for (ALL_LIST_ELEMENTS (area->oiflist, node2, nnode2, oi))
 | |
|             ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa);
 | |
|           break;
 | |
|         case OSPF_OPAQUE_AS_LSA:
 | |
|           for (ALL_LIST_ELEMENTS (top->oiflist, node2, nnode2, oi))
 | |
|             ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa);
 | |
|           break;
 | |
|         default:
 | |
|           break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| out:
 | |
|   return;
 | |
| }
 | |
| 
 | |
| static void
 | |
| ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs,
 | |
|                                     struct ospf_neighbor *inbr,
 | |
|                                     struct ospf_lsa *lsa)
 | |
| {
 | |
|   struct route_node *rn;
 | |
|   struct ospf_neighbor *onbr;
 | |
|   struct ospf_lsa *ls_req;
 | |
| 
 | |
|   for (rn = route_top (nbrs); rn; rn = route_next (rn))
 | |
|     {
 | |
|       if ((onbr = rn->info) == NULL)
 | |
|         continue;
 | |
|       if (onbr == inbr)
 | |
|         continue;
 | |
|       if ((ls_req = ospf_ls_request_lookup (onbr, lsa)) == NULL)
 | |
|         continue;
 | |
| 
 | |
|       if (IS_DEBUG_OSPF_EVENT)
 | |
|         zlog_debug ("LSA[%s]: Exclude this entry from LSReq to send.", dump_lsa_key (lsa));
 | |
| 
 | |
|       ospf_ls_request_delete (onbr, ls_req);
 | |
| /*    ospf_check_nbr_loading (onbr);*//* XXX */
 | |
|     }
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| void
 | |
| ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, 
 | |
|                                           struct ospf_lsa *lsa)
 | |
| {
 | |
|   struct ospf *top;
 | |
|   u_char before;
 | |
| 
 | |
|   if ((top = oi_to_top (nbr->oi)) == NULL)
 | |
|     return;
 | |
| 
 | |
|   before = IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque);
 | |
| 
 | |
|   /*
 | |
|    * 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:
 | |
|       SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT);
 | |
|       ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa);
 | |
|       break;
 | |
|     case OSPF_OPAQUE_AREA_LSA:
 | |
|       SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT);
 | |
|       ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa);
 | |
|       break;
 | |
|     case OSPF_OPAQUE_AS_LSA:
 | |
|       SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT);
 | |
|       ospf_flood_through_as (top, NULL/*inbr*/, lsa);
 | |
|       break;
 | |
|     default:
 | |
|       zlog_warn ("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. */
 | |
| 
 | |
|   if (before == 0 && IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
 | |
|     {
 | |
|       if (IS_DEBUG_OSPF_EVENT)
 | |
|         zlog_debug ("Block Opaque-LSA origination: OFF -> ON");
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
 | |
| {
 | |
|   struct ospf *top;
 | |
|   int delay;
 | |
|   struct ospf_interface *oi;
 | |
|   struct listnode *node, *nnode;
 | |
| 
 | |
|   if ((top = oi_to_top (nbr->oi)) == NULL)
 | |
|     return;
 | |
|   
 | |
|   if (!IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
 | |
|     return;
 | |
|   
 | |
|   switch (lsa->data->type)
 | |
|     {
 | |
|     case OSPF_OPAQUE_LINK_LSA:
 | |
|       if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT))
 | |
|         ospf_opaque_type9_lsa_rxmt_nbr_check (nbr->oi);
 | |
|       /* Callback function... */
 | |
|       break;
 | |
|     case OSPF_OPAQUE_AREA_LSA:
 | |
|       if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT))
 | |
|         ospf_opaque_type10_lsa_rxmt_nbr_check (nbr->oi->area);
 | |
|       /* Callback function... */
 | |
|       break;
 | |
|     case OSPF_OPAQUE_AS_LSA:
 | |
|       if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT))
 | |
|         ospf_opaque_type11_lsa_rxmt_nbr_check (top);
 | |
|       /* Callback function... */
 | |
|       break;
 | |
|     default:
 | |
|       zlog_warn ("ospf_opaque_ls_ack_received: Unexpected LSA-type(%u)", lsa->data->type);
 | |
|       return;
 | |
|     }
 | |
|   
 | |
|   if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque))
 | |
|     {
 | |
|       if (IS_DEBUG_OSPF_EVENT)
 | |
|         zlog_debug ("Block Opaque-LSA origination: ON -> OFF");
 | |
|       return; /* Blocking still in progress. */
 | |
|     }
 | |
|   
 | |
|   if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE))
 | |
|     return; /* Opaque capability condition must have changed. */
 | |
| 
 | |
|   /* Ok, let's start origination of Opaque-LSAs. */
 | |
|   delay = OSPF_MIN_LS_INTERVAL;
 | |
| 
 | |
|   for (ALL_LIST_ELEMENTS (top->oiflist, node, nnode, oi))
 | |
|     {
 | |
|       if (! ospf_if_is_enable (oi)
 | |
|           || ospf_nbr_count_opaque_capable (oi) == 0)
 | |
|         continue;
 | |
| 
 | |
|       ospf_opaque_lsa_originate_schedule (oi, &delay);
 | |
|     }
 | |
|     
 | |
|   return;
 | |
| }
 | |
| 
 | |
| static void
 | |
| ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi)
 | |
| {
 | |
|   unsigned long n;
 | |
| 
 | |
|   n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_LINK_LSA);
 | |
|   if (n == 0)
 | |
|     {
 | |
|       if (IS_DEBUG_OSPF_EVENT)
 | |
|         zlog_debug ("Self-originated type-9 Opaque-LSAs: OI(%s): Flush completed", IF_NAME (oi));
 | |
| 
 | |
|       UNSET_FLAG (oi->area->ospf->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT);
 | |
|     }
 | |
|   return;
 | |
| }
 | |
| 
 | |
| static void
 | |
| ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area)
 | |
| {
 | |
|   struct listnode *node;
 | |
|   struct ospf_interface *oi;
 | |
|   unsigned long n = 0;
 | |
| 
 | |
|   for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi))
 | |
|     {
 | |
|       if (area->area_id.s_addr != OSPF_AREA_BACKBONE
 | |
|           && oi->type == OSPF_IFTYPE_VIRTUALLINK) 
 | |
|         continue;
 | |
| 
 | |
|       n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AREA_LSA);
 | |
|       if (n > 0)
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|   if (n == 0)
 | |
|     {
 | |
|       if (IS_DEBUG_OSPF_EVENT)
 | |
|         zlog_debug ("Self-originated type-10 Opaque-LSAs: AREA(%s): Flush completed", inet_ntoa (area->area_id));
 | |
| 
 | |
|       UNSET_FLAG (area->ospf->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT);
 | |
|     }
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| static void
 | |
| ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top)
 | |
| {
 | |
|   struct listnode *node;
 | |
|   struct ospf_interface *oi;
 | |
|   unsigned long n = 0;
 | |
| 
 | |
|   for (ALL_LIST_ELEMENTS_RO (top->oiflist, node, oi))
 | |
|     {
 | |
|       switch (oi->type)
 | |
|         {
 | |
|         case OSPF_IFTYPE_VIRTUALLINK:
 | |
|           continue;
 | |
|         default:
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|       n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AS_LSA);
 | |
|       if (n > 0)
 | |
|         goto out;
 | |
|     }
 | |
| 
 | |
|   if (n == 0)
 | |
|     {
 | |
|       if (IS_DEBUG_OSPF_EVENT)
 | |
|         zlog_debug ("Self-originated type-11 Opaque-LSAs: Flush completed");
 | |
| 
 | |
|       UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT);
 | |
|     }
 | |
| 
 | |
| out:
 | |
|   return;
 | |
| }
 | |
| 
 | |
| static unsigned long
 | |
| ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type)
 | |
| {
 | |
|   struct route_node *rn;
 | |
|   struct ospf_neighbor *nbr;
 | |
|   struct ospf *top;
 | |
|   unsigned long n = 0;
 | |
| 
 | |
|   for (rn = route_top (nbrs); rn; rn = route_next (rn))
 | |
|     {
 | |
|       if ((nbr = rn->info) == NULL)
 | |
|         continue;
 | |
|       if ((top = oi_to_top (nbr->oi)) == NULL)
 | |
|         continue;
 | |
|       if (IPV4_ADDR_SAME (&nbr->router_id, &top->router_id))
 | |
|         continue;
 | |
|       n += ospf_ls_retransmit_count_self (nbr, lsa_type);
 | |
|     }
 | |
| 
 | |
|   return n;
 | |
| }
 | |
| 
 | |
| /*------------------------------------------------------------------------*
 | |
|  * Followings are util functions; probably be used by Opaque-LSAs only...
 | |
|  *------------------------------------------------------------------------*/
 | |
| 
 | |
| void
 | |
| htonf (float *src, float *dst)
 | |
| {
 | |
|   u_int32_t lu1, lu2;
 | |
| 
 | |
|   memcpy (&lu1, src, sizeof (u_int32_t));
 | |
|   lu2 = htonl (lu1);
 | |
|   memcpy (dst, &lu2, sizeof (u_int32_t));
 | |
|   return;
 | |
| }
 | |
| 
 | |
| void
 | |
| ntohf (float *src, float *dst)
 | |
| {
 | |
|   u_int32_t lu1, lu2;
 | |
| 
 | |
|   memcpy (&lu1, src, sizeof (u_int32_t));
 | |
|   lu2 = ntohl (lu1);
 | |
|   memcpy (dst, &lu2, sizeof (u_int32_t));
 | |
|   return;
 | |
| }
 | |
| 
 | |
| 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)
 | |
|     zlog_warn ("Broken relationship for \"OI -> AREA -> OSPF\"?");
 | |
| 
 | |
|   return top;
 | |
| }
 | |
| 
 | |
| #endif /* HAVE_OPAQUE_LSA */
 |