back to topotato report
topotato coverage report
Current view: top level - ospfd - ospf_opaque.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 227 1046 21.7 %
Date: 2023-02-24 14:41:08 Functions: 29 74 39.2 %

          Line data    Source code
       1             : /*
       2             :  * This is an implementation of rfc2370.
       3             :  * Copyright (C) 2001 KDD R&D Laboratories, Inc.
       4             :  * http://www.kddlabs.co.jp/
       5             :  *
       6             :  * This file is part of GNU Zebra.
       7             :  *
       8             :  * GNU Zebra is free software; you can redistribute it and/or modify it
       9             :  * under the terms of the GNU General Public License as published by the
      10             :  * Free Software Foundation; either version 2, or (at your option) any
      11             :  * later version.
      12             :  *
      13             :  * GNU Zebra is distributed in the hope that it will be useful, but
      14             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU General Public License along
      19             :  * with this program; see the file COPYING; if not, write to the Free Software
      20             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      21             :  */
      22             : 
      23             : #include <zebra.h>
      24             : 
      25             : #include "linklist.h"
      26             : #include "prefix.h"
      27             : #include "if.h"
      28             : #include "table.h"
      29             : #include "memory.h"
      30             : #include "command.h"
      31             : #include "vty.h"
      32             : #include "stream.h"
      33             : #include "log.h"
      34             : #include "thread.h"
      35             : #include "hash.h"
      36             : #include "sockunion.h" /* for inet_aton() */
      37             : 
      38             : #include "ospfd/ospfd.h"
      39             : #include "ospfd/ospf_interface.h"
      40             : #include "ospfd/ospf_ism.h"
      41             : #include "ospfd/ospf_asbr.h"
      42             : #include "ospfd/ospf_lsa.h"
      43             : #include "ospfd/ospf_lsdb.h"
      44             : #include "ospfd/ospf_neighbor.h"
      45             : #include "ospfd/ospf_nsm.h"
      46             : #include "ospfd/ospf_flood.h"
      47             : #include "ospfd/ospf_packet.h"
      48             : #include "ospfd/ospf_spf.h"
      49             : #include "ospfd/ospf_dump.h"
      50             : #include "ospfd/ospf_route.h"
      51             : #include "ospfd/ospf_ase.h"
      52             : #include "ospfd/ospf_zebra.h"
      53             : #include "ospfd/ospf_te.h"
      54             : #include "ospfd/ospf_sr.h"
      55             : #include "ospfd/ospf_ri.h"
      56             : #include "ospfd/ospf_ext.h"
      57             : #include "ospfd/ospf_errors.h"
      58             : 
      59          12 : DEFINE_MTYPE_STATIC(OSPFD, OSPF_OPAQUE_FUNCTAB, "OSPF opaque function table");
      60          12 : DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_TYPE, "OSPF opaque per-type info");
      61          12 : DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_ID, "OSPF opaque per-ID info");
      62             : 
      63             : /*------------------------------------------------------------------------*
      64             :  * Following are initialize/terminate functions for Opaque-LSAs handling.
      65             :  *------------------------------------------------------------------------*/
      66             : 
      67             : #ifdef SUPPORT_OSPF_API
      68             : int ospf_apiserver_init(void);
      69             : void ospf_apiserver_term(void);
      70             : /* Init apiserver? It's disabled by default. */
      71             : int ospf_apiserver_enable;
      72             : #endif /* SUPPORT_OSPF_API */
      73             : 
      74             : static void ospf_opaque_register_vty(void);
      75             : static void ospf_opaque_funclist_init(void);
      76             : static void ospf_opaque_funclist_term(void);
      77             : static void free_opaque_info_per_type_del(void *val);
      78             : static void free_opaque_info_per_id(void *val);
      79             : static int ospf_opaque_lsa_install_hook(struct ospf_lsa *lsa);
      80             : static int ospf_opaque_lsa_delete_hook(struct ospf_lsa *lsa);
      81             : 
      82           4 : void ospf_opaque_init(void)
      83             : {
      84           4 :         ospf_opaque_register_vty();
      85           4 :         ospf_opaque_funclist_init();
      86             : 
      87           4 :         if (ospf_mpls_te_init() != 0)
      88           0 :                 exit(1);
      89             : 
      90             :         /* Segment Routing init */
      91           4 :         if (ospf_sr_init() != 0)
      92           0 :                 exit(1);
      93             : 
      94           4 :         if (ospf_router_info_init() != 0)
      95           0 :                 exit(1);
      96             : 
      97           4 :         if (ospf_ext_init() != 0)
      98           0 :                 exit(1);
      99             : 
     100             : #ifdef SUPPORT_OSPF_API
     101           4 :         if ((ospf_apiserver_enable) && (ospf_apiserver_init() != 0))
     102           0 :                 exit(1);
     103             : #endif /* SUPPORT_OSPF_API */
     104             : 
     105           4 :         return;
     106             : }
     107             : 
     108           0 : void ospf_opaque_term(void)
     109             : {
     110           0 :         ospf_mpls_te_term();
     111             : 
     112           0 :         ospf_router_info_term();
     113             : 
     114           0 :         ospf_ext_term();
     115             : 
     116           0 :         ospf_sr_term();
     117             : 
     118             : #ifdef SUPPORT_OSPF_API
     119           0 :         ospf_apiserver_term();
     120             : #endif /* SUPPORT_OSPF_API */
     121             : 
     122           0 :         ospf_opaque_funclist_term();
     123           0 :         return;
     124             : }
     125             : 
     126           4 : void ospf_opaque_finish(void)
     127             : {
     128           4 :         ospf_mpls_te_finish();
     129             : 
     130           4 :         ospf_router_info_finish();
     131             : 
     132           4 :         ospf_ext_finish();
     133             : 
     134           4 :         ospf_sr_finish();
     135           4 : }
     136             : 
     137          17 : int ospf_opaque_type9_lsa_init(struct ospf_interface *oi)
     138             : {
     139          17 :         if (oi->opaque_lsa_self != NULL)
     140           0 :                 list_delete(&oi->opaque_lsa_self);
     141             : 
     142          17 :         oi->opaque_lsa_self = list_new();
     143          17 :         oi->opaque_lsa_self->del = free_opaque_info_per_type_del;
     144          17 :         oi->t_opaque_lsa_self = NULL;
     145          17 :         return 0;
     146             : }
     147             : 
     148          17 : void ospf_opaque_type9_lsa_term(struct ospf_interface *oi)
     149             : {
     150          17 :         THREAD_OFF(oi->t_opaque_lsa_self);
     151          17 :         if (oi->opaque_lsa_self != NULL)
     152          17 :                 list_delete(&oi->opaque_lsa_self);
     153          17 :         oi->opaque_lsa_self = NULL;
     154          17 :         return;
     155             : }
     156             : 
     157          11 : int ospf_opaque_type10_lsa_init(struct ospf_area *area)
     158             : {
     159          11 :         if (area->opaque_lsa_self != NULL)
     160           0 :                 list_delete(&area->opaque_lsa_self);
     161             : 
     162          11 :         area->opaque_lsa_self = list_new();
     163          11 :         area->opaque_lsa_self->del = free_opaque_info_per_type_del;
     164          11 :         area->t_opaque_lsa_self = NULL;
     165             : 
     166             : #ifdef MONITOR_LSDB_CHANGE
     167          11 :         area->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook;
     168          11 :         area->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook;
     169             : #endif /* MONITOR_LSDB_CHANGE */
     170          11 :         return 0;
     171             : }
     172             : 
     173          11 : void ospf_opaque_type10_lsa_term(struct ospf_area *area)
     174             : {
     175             : #ifdef MONITOR_LSDB_CHANGE
     176          11 :         area->lsdb->new_lsa_hook = area->lsdb->del_lsa_hook = NULL;
     177             : #endif /* MONITOR_LSDB_CHANGE */
     178             : 
     179          11 :         THREAD_OFF(area->t_opaque_lsa_self);
     180          11 :         if (area->opaque_lsa_self != NULL)
     181          11 :                 list_delete(&area->opaque_lsa_self);
     182          11 :         return;
     183             : }
     184             : 
     185           4 : int ospf_opaque_type11_lsa_init(struct ospf *top)
     186             : {
     187           4 :         if (top->opaque_lsa_self != NULL)
     188           0 :                 list_delete(&top->opaque_lsa_self);
     189             : 
     190           4 :         top->opaque_lsa_self = list_new();
     191           4 :         top->opaque_lsa_self->del = free_opaque_info_per_type_del;
     192           4 :         top->t_opaque_lsa_self = NULL;
     193             : 
     194             : #ifdef MONITOR_LSDB_CHANGE
     195           4 :         top->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook;
     196           4 :         top->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook;
     197             : #endif /* MONITOR_LSDB_CHANGE */
     198           4 :         return 0;
     199             : }
     200             : 
     201           4 : void ospf_opaque_type11_lsa_term(struct ospf *top)
     202             : {
     203             : #ifdef MONITOR_LSDB_CHANGE
     204           4 :         top->lsdb->new_lsa_hook = top->lsdb->del_lsa_hook = NULL;
     205             : #endif /* MONITOR_LSDB_CHANGE */
     206             : 
     207           4 :         THREAD_OFF(top->t_opaque_lsa_self);
     208           4 :         if (top->opaque_lsa_self != NULL)
     209           4 :                 list_delete(&top->opaque_lsa_self);
     210           4 :         return;
     211             : }
     212             : 
     213           0 : static const char *ospf_opaque_type_name(uint8_t opaque_type)
     214             : {
     215           0 :         const char *name = "Unknown";
     216             : 
     217           0 :         switch (opaque_type) {
     218             :         case OPAQUE_TYPE_WILDCARD: /* This is a special assignment! */
     219             :                 name = "Wildcard";
     220             :                 break;
     221           0 :         case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA:
     222           0 :                 name = "Traffic Engineering LSA";
     223           0 :                 break;
     224           0 :         case OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC:
     225           0 :                 name = "Sycamore optical topology description";
     226           0 :                 break;
     227           0 :         case OPAQUE_TYPE_GRACE_LSA:
     228           0 :                 name = "Grace-LSA";
     229           0 :                 break;
     230           0 :         case OPAQUE_TYPE_INTER_AS_LSA:
     231           0 :                 name = "Inter-AS TE-v2 LSA";
     232           0 :                 break;
     233           0 :         case OPAQUE_TYPE_ROUTER_INFORMATION_LSA:
     234           0 :                 name = "Router Information LSA";
     235           0 :                 break;
     236           0 :         case OPAQUE_TYPE_EXTENDED_PREFIX_LSA:
     237           0 :                 name = "Extended Prefix Opaque LSA";
     238           0 :                 break;
     239           0 :         case OPAQUE_TYPE_EXTENDED_LINK_LSA:
     240           0 :                 name = "Extended Link Opaque LSA";
     241           0 :                 break;
     242           0 :         default:
     243           0 :                 if (OPAQUE_TYPE_RANGE_UNASSIGNED(opaque_type))
     244             :                         name = "Unassigned";
     245             :                 else {
     246           0 :                         uint32_t bigger_range = opaque_type;
     247             :                         /*
     248             :                          * Get around type-limits warning: comparison is always
     249             :                          * true due to limited range of data type
     250             :                          */
     251           0 :                         if (OPAQUE_TYPE_RANGE_RESERVED(bigger_range))
     252           0 :                                 name = "Private/Experimental";
     253             :                 }
     254             :                 break;
     255             :         }
     256           0 :         return name;
     257             : }
     258             : 
     259             : /*------------------------------------------------------------------------*
     260             :  * Following are management functions to store user specified callbacks.
     261             :  *------------------------------------------------------------------------*/
     262             : 
     263             : struct opaque_info_per_type; /* Forward declaration. */
     264             : 
     265             : static void free_opaque_info_per_type(struct opaque_info_per_type *oipt,
     266             :                                       bool cleanup_owner);
     267             : 
     268             : struct ospf_opaque_functab {
     269             :         uint8_t opaque_type;
     270             :         struct opaque_info_per_type *oipt;
     271             : 
     272             :         int (*new_if_hook)(struct interface *ifp);
     273             :         int (*del_if_hook)(struct interface *ifp);
     274             :         void (*ism_change_hook)(struct ospf_interface *oi, int old_status);
     275             :         void (*nsm_change_hook)(struct ospf_neighbor *nbr, int old_status);
     276             :         void (*config_write_router)(struct vty *vty);
     277             :         void (*config_write_if)(struct vty *vty, struct interface *ifp);
     278             :         void (*config_write_debug)(struct vty *vty);
     279             :         void (*show_opaque_info)(struct vty *vty, struct json_object *json,
     280             :                                  struct ospf_lsa *lsa);
     281             :         int (*lsa_originator)(void *arg);
     282             :         struct ospf_lsa *(*lsa_refresher)(struct ospf_lsa *lsa);
     283             :         int (*new_lsa_hook)(struct ospf_lsa *lsa);
     284             :         int (*del_lsa_hook)(struct ospf_lsa *lsa);
     285             : };
     286             : 
     287             : /* Handle LSA-9/10/11 altogether. */
     288             : static struct list *ospf_opaque_wildcard_funclist;
     289             : static struct list *ospf_opaque_type9_funclist;
     290             : static struct list *ospf_opaque_type10_funclist;
     291             : static struct list *ospf_opaque_type11_funclist;
     292             : 
     293           0 : static void ospf_opaque_del_functab(void *val)
     294             : {
     295           0 :         XFREE(MTYPE_OSPF_OPAQUE_FUNCTAB, val);
     296           0 :         return;
     297             : }
     298             : 
     299           4 : static void ospf_opaque_funclist_init(void)
     300             : {
     301           4 :         struct list *funclist;
     302             : 
     303           4 :         funclist = ospf_opaque_wildcard_funclist = list_new();
     304           4 :         funclist->del = ospf_opaque_del_functab;
     305             : 
     306           4 :         funclist = ospf_opaque_type9_funclist = list_new();
     307           4 :         funclist->del = ospf_opaque_del_functab;
     308             : 
     309           4 :         funclist = ospf_opaque_type10_funclist = list_new();
     310           4 :         funclist->del = ospf_opaque_del_functab;
     311             : 
     312           4 :         funclist = ospf_opaque_type11_funclist = list_new();
     313           4 :         funclist->del = ospf_opaque_del_functab;
     314           4 :         return;
     315             : }
     316             : 
     317           0 : static void ospf_opaque_funclist_term(void)
     318             : {
     319           0 :         struct list *funclist;
     320             : 
     321           0 :         funclist = ospf_opaque_wildcard_funclist;
     322           0 :         list_delete(&funclist);
     323             : 
     324           0 :         funclist = ospf_opaque_type9_funclist;
     325           0 :         list_delete(&funclist);
     326             : 
     327           0 :         funclist = ospf_opaque_type10_funclist;
     328           0 :         list_delete(&funclist);
     329             : 
     330           0 :         funclist = ospf_opaque_type11_funclist;
     331           0 :         list_delete(&funclist);
     332           0 :         return;
     333             : }
     334             : 
     335          24 : static struct list *ospf_get_opaque_funclist(uint8_t lsa_type)
     336             : {
     337          24 :         struct list *funclist = NULL;
     338             : 
     339          24 :         switch (lsa_type) {
     340           0 :         case OPAQUE_TYPE_WILDCARD:
     341             :                 /* XXX
     342             :                  * This is an ugly trick to handle type-9/10/11 LSA altogether.
     343             :                  * Yes, "OPAQUE_TYPE_WILDCARD (value 0)" is not an LSA-type, nor
     344             :                  * an officially assigned opaque-type.
     345             :                  * Though it is possible that the value might be officially used
     346             :                  * in the future, we use it internally as a special label, for
     347             :                  * now.
     348             :                  */
     349           0 :                 funclist = ospf_opaque_wildcard_funclist;
     350           0 :                 break;
     351           4 :         case OSPF_OPAQUE_LINK_LSA:
     352           4 :                 funclist = ospf_opaque_type9_funclist;
     353           4 :                 break;
     354          16 :         case OSPF_OPAQUE_AREA_LSA:
     355          16 :                 funclist = ospf_opaque_type10_funclist;
     356          16 :                 break;
     357           4 :         case OSPF_OPAQUE_AS_LSA:
     358           4 :                 funclist = ospf_opaque_type11_funclist;
     359           4 :                 break;
     360           0 :         default:
     361           0 :                 flog_warn(EC_OSPF_LSA_UNEXPECTED, "%s: Unexpected LSA-type(%u)",
     362             :                           __func__, lsa_type);
     363           0 :                 break;
     364             :         }
     365          24 :         return funclist;
     366             : }
     367             : 
     368             : /* XXX: such a huge argument list can /not/ be healthy... */
     369          24 : int ospf_register_opaque_functab(
     370             :         uint8_t lsa_type, uint8_t opaque_type,
     371             :         int (*new_if_hook)(struct interface *ifp),
     372             :         int (*del_if_hook)(struct interface *ifp),
     373             :         void (*ism_change_hook)(struct ospf_interface *oi, int old_status),
     374             :         void (*nsm_change_hook)(struct ospf_neighbor *nbr, int old_status),
     375             :         void (*config_write_router)(struct vty *vty),
     376             :         void (*config_write_if)(struct vty *vty, struct interface *ifp),
     377             :         void (*config_write_debug)(struct vty *vty),
     378             :         void (*show_opaque_info)(struct vty *vty, struct json_object *json,
     379             :                                  struct ospf_lsa *lsa),
     380             :         int (*lsa_originator)(void *arg),
     381             :         struct ospf_lsa *(*lsa_refresher)(struct ospf_lsa *lsa),
     382             :         int (*new_lsa_hook)(struct ospf_lsa *lsa),
     383             :         int (*del_lsa_hook)(struct ospf_lsa *lsa))
     384             : {
     385          24 :         struct list *funclist;
     386          24 :         struct ospf_opaque_functab *new;
     387             : 
     388          24 :         if ((funclist = ospf_get_opaque_funclist(lsa_type)) == NULL)
     389             :                 return -1;
     390             : 
     391          24 :         struct listnode *node, *nnode;
     392          24 :         struct ospf_opaque_functab *functab;
     393             : 
     394          48 :         for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
     395          24 :                 if (functab->opaque_type == opaque_type) {
     396           0 :                         flog_warn(
     397             :                                 EC_OSPF_LSA,
     398             :                                 "%s: Duplicated entry?: lsa_type(%u), opaque_type(%u)",
     399             :                                 __func__, lsa_type, opaque_type);
     400           0 :                         return -1;
     401             :                 }
     402             : 
     403          24 :         new = XCALLOC(MTYPE_OSPF_OPAQUE_FUNCTAB,
     404             :                       sizeof(struct ospf_opaque_functab));
     405             : 
     406          24 :         new->opaque_type = opaque_type;
     407          24 :         new->oipt = NULL;
     408          24 :         new->new_if_hook = new_if_hook;
     409          24 :         new->del_if_hook = del_if_hook;
     410          24 :         new->ism_change_hook = ism_change_hook;
     411          24 :         new->nsm_change_hook = nsm_change_hook;
     412          24 :         new->config_write_router = config_write_router;
     413          24 :         new->config_write_if = config_write_if;
     414          24 :         new->config_write_debug = config_write_debug;
     415          24 :         new->show_opaque_info = show_opaque_info;
     416          24 :         new->lsa_originator = lsa_originator;
     417          24 :         new->lsa_refresher = lsa_refresher;
     418          24 :         new->new_lsa_hook = new_lsa_hook;
     419          24 :         new->del_lsa_hook = del_lsa_hook;
     420             : 
     421          24 :         listnode_add(funclist, new);
     422             : 
     423          24 :         return 0;
     424             : }
     425             : 
     426           0 : void ospf_delete_opaque_functab(uint8_t lsa_type, uint8_t opaque_type)
     427             : {
     428           0 :         struct list *funclist;
     429           0 :         struct listnode *node, *nnode;
     430           0 :         struct ospf_opaque_functab *functab;
     431             : 
     432           0 :         if ((funclist = ospf_get_opaque_funclist(lsa_type)) != NULL)
     433           0 :                 for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab)) {
     434           0 :                         if (functab->opaque_type == opaque_type) {
     435             :                                 /* Cleanup internal control information, if it
     436             :                                  * still remains. */
     437           0 :                                 if (functab->oipt != NULL)
     438           0 :                                         free_opaque_info_per_type(functab->oipt,
     439             :                                                                   true);
     440             :                                 /* Dequeue listnode entry from the list. */
     441           0 :                                 listnode_delete(funclist, functab);
     442             : 
     443           0 :                                 XFREE(MTYPE_OSPF_OPAQUE_FUNCTAB, functab);
     444           0 :                                 break;
     445             :                         }
     446             :                 }
     447             : 
     448           0 :         return;
     449             : }
     450             : 
     451             : static struct ospf_opaque_functab *
     452           0 : ospf_opaque_functab_lookup(struct ospf_lsa *lsa)
     453             : {
     454           0 :         struct list *funclist;
     455           0 :         struct listnode *node;
     456           0 :         struct ospf_opaque_functab *functab;
     457           0 :         uint8_t key = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr));
     458             : 
     459           0 :         if ((funclist = ospf_get_opaque_funclist(lsa->data->type)) != NULL)
     460           0 :                 for (ALL_LIST_ELEMENTS_RO(funclist, node, functab))
     461           0 :                         if (functab->opaque_type == key)
     462           0 :                                 return functab;
     463             : 
     464             :         return NULL;
     465             : }
     466             : 
     467             : /*------------------------------------------------------------------------*
     468             :  * Following are management functions for self-originated LSA entries.
     469             :  *------------------------------------------------------------------------*/
     470             : 
     471             : /*
     472             :  * Opaque-LSA control information per opaque-type.
     473             :  * Single Opaque-Type may have multiple instances; each of them will be
     474             :  * identified by their opaque-id.
     475             :  */
     476             : struct opaque_info_per_type {
     477             :         uint8_t lsa_type;
     478             :         uint8_t opaque_type;
     479             : 
     480             :         enum { PROC_NORMAL, PROC_SUSPEND } status;
     481             : 
     482             :         /*
     483             :          * Thread for (re-)origination scheduling for this opaque-type.
     484             :          *
     485             :          * Initial origination of Opaque-LSAs is controlled by generic
     486             :          * Opaque-LSA handling module so that same opaque-type entries are
     487             :          * called all at once when certain conditions are met.
     488             :          * However, there might be cases that some Opaque-LSA clients need
     489             :          * to (re-)originate their own Opaque-LSAs out-of-sync with others.
     490             :          * This thread is prepared for that specific purpose.
     491             :          */
     492             :         struct thread *t_opaque_lsa_self;
     493             : 
     494             :         /*
     495             :          * Backpointer to an "owner" which is LSA-type dependent.
     496             :          *   type-9:  struct ospf_interface
     497             :          *   type-10: struct ospf_area
     498             :          *   type-11: struct ospf
     499             :          */
     500             :         void *owner;
     501             : 
     502             :         /* Collection of callback functions for this opaque-type. */
     503             :         struct ospf_opaque_functab *functab;
     504             : 
     505             :         /* List of Opaque-LSA control information per opaque-id. */
     506             :         struct list *id_list;
     507             : };
     508             : 
     509             : /* Opaque-LSA control information per opaque-id. */
     510             : struct opaque_info_per_id {
     511             :         uint32_t opaque_id;
     512             : 
     513             :         /* Thread for refresh/flush scheduling for this opaque-type/id. */
     514             :         struct thread *t_opaque_lsa_self;
     515             : 
     516             :         /* Backpointer to Opaque-LSA control information per opaque-type. */
     517             :         struct opaque_info_per_type *opqctl_type;
     518             : 
     519             :         /* Here comes an actual Opaque-LSA entry for this opaque-type/id. */
     520             :         struct ospf_lsa *lsa;
     521             : };
     522             : 
     523             : static struct opaque_info_per_type *
     524             : register_opaque_info_per_type(struct ospf_opaque_functab *functab,
     525             :                               struct ospf_lsa *new);
     526             : static struct opaque_info_per_type *
     527             : lookup_opaque_info_by_type(struct ospf_lsa *lsa);
     528             : static struct opaque_info_per_id *
     529             : register_opaque_info_per_id(struct opaque_info_per_type *oipt,
     530             :                             struct ospf_lsa *new);
     531             : static struct opaque_info_per_id *
     532             : lookup_opaque_info_by_id(struct opaque_info_per_type *oipt,
     533             :                          struct ospf_lsa *lsa);
     534             : static struct opaque_info_per_id *register_opaque_lsa(struct ospf_lsa *new);
     535             : 
     536             : 
     537             : static struct opaque_info_per_type *
     538           0 : register_opaque_info_per_type(struct ospf_opaque_functab *functab,
     539             :                               struct ospf_lsa *new)
     540             : {
     541           0 :         struct ospf *top;
     542           0 :         struct opaque_info_per_type *oipt;
     543             : 
     544           0 :         oipt = XCALLOC(MTYPE_OPAQUE_INFO_PER_TYPE,
     545             :                        sizeof(struct opaque_info_per_type));
     546             : 
     547           0 :         switch (new->data->type) {
     548           0 :         case OSPF_OPAQUE_LINK_LSA:
     549           0 :                 oipt->owner = new->oi;
     550           0 :                 listnode_add(new->oi->opaque_lsa_self, oipt);
     551           0 :                 break;
     552           0 :         case OSPF_OPAQUE_AREA_LSA:
     553           0 :                 oipt->owner = new->area;
     554           0 :                 listnode_add(new->area->opaque_lsa_self, oipt);
     555           0 :                 break;
     556           0 :         case OSPF_OPAQUE_AS_LSA:
     557           0 :                 top = ospf_lookup_by_vrf_id(new->vrf_id);
     558           0 :                 if (new->area != NULL && (top = new->area->ospf) == NULL) {
     559           0 :                         free_opaque_info_per_type(oipt, true);
     560           0 :                         oipt = NULL;
     561           0 :                         goto out; /* This case may not exist. */
     562             :                 }
     563           0 :                 oipt->owner = top;
     564           0 :                 listnode_add(top->opaque_lsa_self, oipt);
     565           0 :                 break;
     566           0 :         default:
     567           0 :                 flog_warn(EC_OSPF_LSA_UNEXPECTED, "%s: Unexpected LSA-type(%u)",
     568             :                           __func__, new->data->type);
     569           0 :                 free_opaque_info_per_type(oipt, true);
     570           0 :                 oipt = NULL;
     571           0 :                 goto out; /* This case may not exist. */
     572             :         }
     573             : 
     574           0 :         oipt->lsa_type = new->data->type;
     575           0 :         oipt->opaque_type = GET_OPAQUE_TYPE(ntohl(new->data->id.s_addr));
     576           0 :         oipt->status = PROC_NORMAL;
     577           0 :         oipt->functab = functab;
     578           0 :         functab->oipt = oipt;
     579           0 :         oipt->id_list = list_new();
     580           0 :         oipt->id_list->del = free_opaque_info_per_id;
     581             : 
     582           0 : out:
     583           0 :         return oipt;
     584             : }
     585             : 
     586           0 : static void free_opaque_info_per_type(struct opaque_info_per_type *oipt,
     587             :                                       bool cleanup_owner)
     588             : {
     589           0 :         struct opaque_info_per_id *oipi;
     590           0 :         struct ospf_lsa *lsa;
     591           0 :         struct listnode *node, *nnode;
     592           0 :         struct list *l;
     593             : 
     594             :         /* Control information per opaque-id may still exist. */
     595           0 :         for (ALL_LIST_ELEMENTS(oipt->id_list, node, nnode, oipi)) {
     596           0 :                 if ((lsa = oipi->lsa) == NULL)
     597           0 :                         continue;
     598           0 :                 if (IS_LSA_MAXAGE(lsa))
     599           0 :                         continue;
     600           0 :                 ospf_opaque_lsa_flush_schedule(lsa);
     601             :         }
     602             : 
     603           0 :         THREAD_OFF(oipt->t_opaque_lsa_self);
     604           0 :         list_delete(&oipt->id_list);
     605           0 :         if (cleanup_owner) {
     606             :                 /* Remove from its owner's self-originated LSA list. */
     607           0 :                 switch (oipt->lsa_type) {
     608           0 :                 case OSPF_OPAQUE_LINK_LSA:
     609           0 :                         l = ((struct ospf_interface *)oipt->owner)
     610             :                                     ->opaque_lsa_self;
     611           0 :                         break;
     612           0 :                 case OSPF_OPAQUE_AREA_LSA:
     613           0 :                         l = ((struct ospf_area *)oipt->owner)->opaque_lsa_self;
     614           0 :                         break;
     615           0 :                 case OSPF_OPAQUE_AS_LSA:
     616           0 :                         l = ((struct ospf *)oipt->owner)->opaque_lsa_self;
     617           0 :                         break;
     618           0 :                 default:
     619           0 :                         flog_warn(
     620             :                                 EC_OSPF_LSA_UNEXPECTED,
     621             :                                 "free_opaque_info_owner: Unexpected LSA-type(%u)",
     622             :                                 oipt->lsa_type);
     623           0 :                         return;
     624             :                 }
     625           0 :                 listnode_delete(l, oipt);
     626             :         }
     627           0 :         XFREE(MTYPE_OPAQUE_INFO_PER_TYPE, oipt);
     628           0 :         return;
     629             : }
     630             : 
     631           0 : static void free_opaque_info_per_type_del(void *val)
     632             : {
     633           0 :         free_opaque_info_per_type((struct opaque_info_per_type *)val, false);
     634           0 : }
     635             : 
     636             : static struct opaque_info_per_type *
     637           0 : lookup_opaque_info_by_type(struct ospf_lsa *lsa)
     638             : {
     639           0 :         struct ospf *top;
     640           0 :         struct ospf_area *area;
     641           0 :         struct ospf_interface *oi;
     642           0 :         struct list *listtop = NULL;
     643           0 :         struct listnode *node, *nnode;
     644           0 :         struct opaque_info_per_type *oipt = NULL;
     645           0 :         uint8_t key = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr));
     646             : 
     647           0 :         switch (lsa->data->type) {
     648           0 :         case OSPF_OPAQUE_LINK_LSA:
     649           0 :                 if ((oi = lsa->oi) != NULL)
     650           0 :                         listtop = oi->opaque_lsa_self;
     651             :                 else
     652           0 :                         flog_warn(
     653             :                                 EC_OSPF_LSA,
     654             :                                 "Type-9 Opaque-LSA: Reference to OI is missing?");
     655             :                 break;
     656           0 :         case OSPF_OPAQUE_AREA_LSA:
     657           0 :                 if ((area = lsa->area) != NULL)
     658           0 :                         listtop = area->opaque_lsa_self;
     659             :                 else
     660           0 :                         flog_warn(
     661             :                                 EC_OSPF_LSA,
     662             :                                 "Type-10 Opaque-LSA: Reference to AREA is missing?");
     663             :                 break;
     664           0 :         case OSPF_OPAQUE_AS_LSA:
     665           0 :                 top = ospf_lookup_by_vrf_id(lsa->vrf_id);
     666           0 :                 if ((area = lsa->area) != NULL && (top = area->ospf) == NULL) {
     667           0 :                         flog_warn(
     668             :                                 EC_OSPF_LSA,
     669             :                                 "Type-11 Opaque-LSA: Reference to OSPF is missing?");
     670           0 :                         break; /* Unlikely to happen. */
     671             :                 }
     672           0 :                 listtop = top->opaque_lsa_self;
     673           0 :                 break;
     674           0 :         default:
     675           0 :                 flog_warn(EC_OSPF_LSA_UNEXPECTED, "%s: Unexpected LSA-type(%u)",
     676             :                           __func__, lsa->data->type);
     677           0 :                 break;
     678             :         }
     679             : 
     680           0 :         if (listtop != NULL)
     681           0 :                 for (ALL_LIST_ELEMENTS(listtop, node, nnode, oipt))
     682           0 :                         if (oipt->opaque_type == key)
     683           0 :                                 return oipt;
     684             : 
     685             :         return NULL;
     686             : }
     687             : 
     688             : static struct opaque_info_per_id *
     689           0 : register_opaque_info_per_id(struct opaque_info_per_type *oipt,
     690             :                             struct ospf_lsa *new)
     691             : {
     692           0 :         struct opaque_info_per_id *oipi;
     693             : 
     694           0 :         oipi = XCALLOC(MTYPE_OPAQUE_INFO_PER_ID,
     695             :                        sizeof(struct opaque_info_per_id));
     696             : 
     697           0 :         oipi->opaque_id = GET_OPAQUE_ID(ntohl(new->data->id.s_addr));
     698           0 :         oipi->opqctl_type = oipt;
     699           0 :         oipi->lsa = ospf_lsa_lock(new);
     700             : 
     701           0 :         listnode_add(oipt->id_list, oipi);
     702             : 
     703           0 :         return oipi;
     704             : }
     705             : 
     706           0 : static void free_opaque_info_per_id(void *val)
     707             : {
     708           0 :         struct opaque_info_per_id *oipi = (struct opaque_info_per_id *)val;
     709             : 
     710           0 :         THREAD_OFF(oipi->t_opaque_lsa_self);
     711           0 :         if (oipi->lsa != NULL)
     712           0 :                 ospf_lsa_unlock(&oipi->lsa);
     713           0 :         XFREE(MTYPE_OPAQUE_INFO_PER_ID, oipi);
     714           0 :         return;
     715             : }
     716             : 
     717             : static struct opaque_info_per_id *
     718           0 : lookup_opaque_info_by_id(struct opaque_info_per_type *oipt,
     719             :                          struct ospf_lsa *lsa)
     720             : {
     721           0 :         struct listnode *node, *nnode;
     722           0 :         struct opaque_info_per_id *oipi;
     723           0 :         uint32_t key = GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr));
     724             : 
     725           0 :         for (ALL_LIST_ELEMENTS(oipt->id_list, node, nnode, oipi))
     726           0 :                 if (oipi->opaque_id == key)
     727           0 :                         return oipi;
     728             : 
     729             :         return NULL;
     730             : }
     731             : 
     732           0 : static struct opaque_info_per_id *register_opaque_lsa(struct ospf_lsa *new)
     733             : {
     734           0 :         struct ospf_opaque_functab *functab;
     735           0 :         struct opaque_info_per_type *oipt;
     736           0 :         struct opaque_info_per_id *oipi = NULL;
     737             : 
     738           0 :         if ((functab = ospf_opaque_functab_lookup(new)) == NULL)
     739           0 :                 goto out;
     740             : 
     741           0 :         if ((oipt = lookup_opaque_info_by_type(new)) == NULL
     742           0 :             && (oipt = register_opaque_info_per_type(functab, new)) == NULL)
     743           0 :                 goto out;
     744             : 
     745           0 :         if ((oipi = register_opaque_info_per_id(oipt, new)) == NULL)
     746           0 :                 goto out;
     747             : 
     748           0 : out:
     749           0 :         return oipi;
     750             : }
     751             : 
     752           0 : int ospf_opaque_is_owned(struct ospf_lsa *lsa)
     753             : {
     754           0 :         struct opaque_info_per_type *oipt = lookup_opaque_info_by_type(lsa);
     755             : 
     756           0 :         return (oipt != NULL && lookup_opaque_info_by_id(oipt, lsa) != NULL);
     757             : }
     758             : 
     759             : /*------------------------------------------------------------------------*
     760             :  * Following are (vty) configuration functions for Opaque-LSAs handling.
     761             :  *------------------------------------------------------------------------*/
     762             : 
     763           0 : DEFUN (capability_opaque,
     764             :        capability_opaque_cmd,
     765             :        "capability opaque",
     766             :        "Enable specific OSPF feature\n"
     767             :        "Opaque LSA\n")
     768             : {
     769           0 :         VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
     770             : 
     771             :         /* Turn on the "master switch" of opaque-lsa capability. */
     772           0 :         if (!CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE)) {
     773           0 :                 if (IS_DEBUG_OSPF_EVENT)
     774           0 :                         zlog_debug("Opaque capability: OFF -> ON");
     775             : 
     776           0 :                 SET_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE);
     777           0 :                 ospf_renegotiate_optional_capabilities(ospf);
     778             :         }
     779             :         return CMD_SUCCESS;
     780             : }
     781             : 
     782           0 : DEFUN (ospf_opaque,
     783             :        ospf_opaque_cmd,
     784             :        "ospf opaque-lsa",
     785             :        "OSPF specific commands\n"
     786             :        "Enable the Opaque-LSA capability (rfc2370)\n")
     787             : {
     788           0 :         return capability_opaque(self, vty, argc, argv);
     789             : }
     790             : 
     791           0 : DEFUN (no_capability_opaque,
     792             :        no_capability_opaque_cmd,
     793             :        "no capability opaque",
     794             :        NO_STR
     795             :        "Enable specific OSPF feature\n"
     796             :        "Opaque LSA\n")
     797             : {
     798           0 :         VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
     799             : 
     800             :         /* Turn off the "master switch" of opaque-lsa capability. */
     801           0 :         if (CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE)) {
     802           0 :                 if (IS_DEBUG_OSPF_EVENT)
     803           0 :                         zlog_debug("Opaque capability: ON -> OFF");
     804             : 
     805           0 :                 UNSET_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE);
     806           0 :                 ospf_renegotiate_optional_capabilities(ospf);
     807             :         }
     808             :         return CMD_SUCCESS;
     809             : }
     810             : 
     811           0 : DEFUN (no_ospf_opaque,
     812             :        no_ospf_opaque_cmd,
     813             :        "no ospf opaque-lsa",
     814             :        NO_STR
     815             :        "OSPF specific commands\n"
     816             :        "Enable the Opaque-LSA capability (rfc2370)\n")
     817             : {
     818           0 :         return no_capability_opaque(self, vty, argc, argv);
     819             : }
     820             : 
     821           4 : static void ospf_opaque_register_vty(void)
     822             : {
     823           4 :         install_element(OSPF_NODE, &capability_opaque_cmd);
     824           4 :         install_element(OSPF_NODE, &no_capability_opaque_cmd);
     825           4 :         install_element(OSPF_NODE, &ospf_opaque_cmd);
     826           4 :         install_element(OSPF_NODE, &no_ospf_opaque_cmd);
     827           4 :         return;
     828             : }
     829             : 
     830             : /*------------------------------------------------------------------------*
     831             :  * Following are collection of user-registered function callers.
     832             :  *------------------------------------------------------------------------*/
     833             : 
     834          52 : static int opaque_lsa_new_if_callback(struct list *funclist,
     835             :                                       struct interface *ifp)
     836             : {
     837          52 :         struct listnode *node, *nnode;
     838          52 :         struct ospf_opaque_functab *functab;
     839          52 :         int rc = -1;
     840             : 
     841         182 :         for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
     842          78 :                 if (functab->new_if_hook != NULL)
     843          26 :                         if ((*functab->new_if_hook)(ifp) != 0)
     844           0 :                                 goto out;
     845             :         rc = 0;
     846          52 : out:
     847          52 :         return rc;
     848             : }
     849             : 
     850           0 : static int opaque_lsa_del_if_callback(struct list *funclist,
     851             :                                       struct interface *ifp)
     852             : {
     853           0 :         struct listnode *node, *nnode;
     854           0 :         struct ospf_opaque_functab *functab;
     855           0 :         int rc = -1;
     856             : 
     857           0 :         for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
     858           0 :                 if (functab->del_if_hook != NULL)
     859           0 :                         if ((*functab->del_if_hook)(ifp) != 0)
     860           0 :                                 goto out;
     861             :         rc = 0;
     862           0 : out:
     863           0 :         return rc;
     864             : }
     865             : 
     866         196 : static void opaque_lsa_ism_change_callback(struct list *funclist,
     867             :                                            struct ospf_interface *oi,
     868             :                                            int old_status)
     869             : {
     870         196 :         struct listnode *node, *nnode;
     871         196 :         struct ospf_opaque_functab *functab;
     872             : 
     873         686 :         for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
     874         294 :                 if (functab->ism_change_hook != NULL)
     875          98 :                         (*functab->ism_change_hook)(oi, old_status);
     876             : 
     877         196 :         return;
     878             : }
     879             : 
     880         220 : static void opaque_lsa_nsm_change_callback(struct list *funclist,
     881             :                                            struct ospf_neighbor *nbr,
     882             :                                            int old_status)
     883             : {
     884         220 :         struct listnode *node, *nnode;
     885         220 :         struct ospf_opaque_functab *functab;
     886             : 
     887         770 :         for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
     888         330 :                 if (functab->nsm_change_hook != NULL)
     889         110 :                         (*functab->nsm_change_hook)(nbr, old_status);
     890         220 :         return;
     891             : }
     892             : 
     893           0 : static void opaque_lsa_config_write_router_callback(struct list *funclist,
     894             :                                                     struct vty *vty)
     895             : {
     896           0 :         struct listnode *node, *nnode;
     897           0 :         struct ospf_opaque_functab *functab;
     898             : 
     899           0 :         for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
     900           0 :                 if (functab->config_write_router != NULL)
     901           0 :                         (*functab->config_write_router)(vty);
     902           0 :         return;
     903             : }
     904             : 
     905           0 : static void opaque_lsa_config_write_if_callback(struct list *funclist,
     906             :                                                 struct vty *vty,
     907             :                                                 struct interface *ifp)
     908             : {
     909           0 :         struct listnode *node, *nnode;
     910           0 :         struct ospf_opaque_functab *functab;
     911             : 
     912           0 :         for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
     913           0 :                 if (functab->config_write_if != NULL)
     914           0 :                         (*functab->config_write_if)(vty, ifp);
     915           0 :         return;
     916             : }
     917             : 
     918           0 : static void opaque_lsa_config_write_debug_callback(struct list *funclist,
     919             :                                                    struct vty *vty)
     920             : {
     921           0 :         struct listnode *node, *nnode;
     922           0 :         struct ospf_opaque_functab *functab;
     923             : 
     924           0 :         for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
     925           0 :                 if (functab->config_write_debug != NULL)
     926           0 :                         (*functab->config_write_debug)(vty);
     927           0 :         return;
     928             : }
     929             : 
     930           0 : static int opaque_lsa_originate_callback(struct list *funclist,
     931             :                                          void *lsa_type_dependent)
     932             : {
     933           0 :         struct listnode *node, *nnode;
     934           0 :         struct ospf_opaque_functab *functab;
     935           0 :         int rc = -1;
     936             : 
     937           0 :         for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
     938           0 :                 if (functab->lsa_originator != NULL)
     939           0 :                         if ((*functab->lsa_originator)(lsa_type_dependent) != 0)
     940           0 :                                 goto out;
     941             :         rc = 0;
     942           0 : out:
     943           0 :         return rc;
     944             : }
     945             : 
     946         636 : static int new_lsa_callback(struct list *funclist, struct ospf_lsa *lsa)
     947             : {
     948         636 :         struct listnode *node, *nnode;
     949         636 :         struct ospf_opaque_functab *functab;
     950         636 :         int rc = -1;
     951             : 
     952             :         /* This function handles ALL types of LSAs, not only opaque ones. */
     953        2226 :         for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
     954         954 :                 if (functab->new_lsa_hook != NULL)
     955         477 :                         if ((*functab->new_lsa_hook)(lsa) != 0)
     956           0 :                                 goto out;
     957             :         rc = 0;
     958         636 : out:
     959         636 :         return rc;
     960             : }
     961             : 
     962         448 : static int del_lsa_callback(struct list *funclist, struct ospf_lsa *lsa)
     963             : {
     964         448 :         struct listnode *node, *nnode;
     965         448 :         struct ospf_opaque_functab *functab;
     966         448 :         int rc = -1;
     967             : 
     968             :         /* This function handles ALL types of LSAs, not only opaque ones. */
     969        1568 :         for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab))
     970         672 :                 if (functab->del_lsa_hook != NULL)
     971         112 :                         if ((*functab->del_lsa_hook)(lsa) != 0)
     972           0 :                                 goto out;
     973             :         rc = 0;
     974         448 : out:
     975         448 :         return rc;
     976             : }
     977             : 
     978             : /*------------------------------------------------------------------------*
     979             :  * Following are glue functions to call Opaque-LSA specific processing.
     980             :  *------------------------------------------------------------------------*/
     981             : 
     982          13 : int ospf_opaque_new_if(struct interface *ifp)
     983             : {
     984          13 :         struct list *funclist;
     985          13 :         int rc = -1;
     986             : 
     987          13 :         funclist = ospf_opaque_wildcard_funclist;
     988          13 :         if (opaque_lsa_new_if_callback(funclist, ifp) != 0)
     989           0 :                 goto out;
     990             : 
     991          13 :         funclist = ospf_opaque_type9_funclist;
     992          13 :         if (opaque_lsa_new_if_callback(funclist, ifp) != 0)
     993           0 :                 goto out;
     994             : 
     995          13 :         funclist = ospf_opaque_type10_funclist;
     996          13 :         if (opaque_lsa_new_if_callback(funclist, ifp) != 0)
     997           0 :                 goto out;
     998             : 
     999          13 :         funclist = ospf_opaque_type11_funclist;
    1000          13 :         if (opaque_lsa_new_if_callback(funclist, ifp) != 0)
    1001           0 :                 goto out;
    1002             : 
    1003             :         rc = 0;
    1004          13 : out:
    1005          13 :         return rc;
    1006             : }
    1007             : 
    1008           0 : int ospf_opaque_del_if(struct interface *ifp)
    1009             : {
    1010           0 :         struct list *funclist;
    1011           0 :         int rc = -1;
    1012             : 
    1013           0 :         funclist = ospf_opaque_wildcard_funclist;
    1014           0 :         if (opaque_lsa_del_if_callback(funclist, ifp) != 0)
    1015           0 :                 goto out;
    1016             : 
    1017           0 :         funclist = ospf_opaque_type9_funclist;
    1018           0 :         if (opaque_lsa_del_if_callback(funclist, ifp) != 0)
    1019           0 :                 goto out;
    1020             : 
    1021           0 :         funclist = ospf_opaque_type10_funclist;
    1022           0 :         if (opaque_lsa_del_if_callback(funclist, ifp) != 0)
    1023           0 :                 goto out;
    1024             : 
    1025           0 :         funclist = ospf_opaque_type11_funclist;
    1026           0 :         if (opaque_lsa_del_if_callback(funclist, ifp) != 0)
    1027           0 :                 goto out;
    1028             : 
    1029             :         rc = 0;
    1030           0 : out:
    1031           0 :         return rc;
    1032             : }
    1033             : 
    1034          49 : void ospf_opaque_ism_change(struct ospf_interface *oi, int old_status)
    1035             : {
    1036          49 :         struct list *funclist;
    1037             : 
    1038          49 :         funclist = ospf_opaque_wildcard_funclist;
    1039          49 :         opaque_lsa_ism_change_callback(funclist, oi, old_status);
    1040             : 
    1041          49 :         funclist = ospf_opaque_type9_funclist;
    1042          49 :         opaque_lsa_ism_change_callback(funclist, oi, old_status);
    1043             : 
    1044          49 :         funclist = ospf_opaque_type10_funclist;
    1045          49 :         opaque_lsa_ism_change_callback(funclist, oi, old_status);
    1046             : 
    1047          49 :         funclist = ospf_opaque_type11_funclist;
    1048          49 :         opaque_lsa_ism_change_callback(funclist, oi, old_status);
    1049             : 
    1050          49 :         return;
    1051             : }
    1052             : 
    1053          55 : void ospf_opaque_nsm_change(struct ospf_neighbor *nbr, int old_state)
    1054             : {
    1055          55 :         struct ospf *top;
    1056          55 :         struct list *funclist;
    1057             : 
    1058          55 :         if ((top = oi_to_top(nbr->oi)) == NULL)
    1059           0 :                 goto out;
    1060             : 
    1061          55 :         if (old_state != NSM_Full && nbr->state == NSM_Full) {
    1062           8 :                 if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)) {
    1063           0 :                         if (!CHECK_FLAG(top->opaque,
    1064             :                                         OPAQUE_OPERATION_READY_BIT)) {
    1065           0 :                                 if (IS_DEBUG_OSPF_EVENT)
    1066           0 :                                         zlog_debug(
    1067             :                                                 "Opaque-LSA: Now get operational!");
    1068             : 
    1069           0 :                                 SET_FLAG(top->opaque,
    1070             :                                          OPAQUE_OPERATION_READY_BIT);
    1071             :                         }
    1072             : 
    1073           0 :                         ospf_opaque_lsa_originate_schedule(nbr->oi, NULL);
    1074             :                 }
    1075             :         } else if (old_state == NSM_Full && nbr->state != NSM_Full) {
    1076             : #ifdef NOTYET
    1077             : /*
    1078             :  * If no more opaque-capable full-state neighbor remains in the
    1079             :  * flooding scope which corresponds to Opaque-LSA type, periodic
    1080             :  * LS flooding should be stopped.
    1081             :  */
    1082             : #endif /* NOTYET */
    1083          55 :                 ;
    1084             :         }
    1085             : 
    1086          55 :         funclist = ospf_opaque_wildcard_funclist;
    1087          55 :         opaque_lsa_nsm_change_callback(funclist, nbr, old_state);
    1088             : 
    1089          55 :         funclist = ospf_opaque_type9_funclist;
    1090          55 :         opaque_lsa_nsm_change_callback(funclist, nbr, old_state);
    1091             : 
    1092          55 :         funclist = ospf_opaque_type10_funclist;
    1093          55 :         opaque_lsa_nsm_change_callback(funclist, nbr, old_state);
    1094             : 
    1095          55 :         funclist = ospf_opaque_type11_funclist;
    1096          55 :         opaque_lsa_nsm_change_callback(funclist, nbr, old_state);
    1097             : 
    1098          55 : out:
    1099          55 :         return;
    1100             : }
    1101             : 
    1102           0 : void ospf_opaque_config_write_router(struct vty *vty, struct ospf *ospf)
    1103             : {
    1104           0 :         struct list *funclist;
    1105             : 
    1106           0 :         if (CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE))
    1107           0 :                 vty_out(vty, " capability opaque\n");
    1108             : 
    1109           0 :         funclist = ospf_opaque_wildcard_funclist;
    1110           0 :         opaque_lsa_config_write_router_callback(funclist, vty);
    1111             : 
    1112           0 :         funclist = ospf_opaque_type9_funclist;
    1113           0 :         opaque_lsa_config_write_router_callback(funclist, vty);
    1114             : 
    1115           0 :         funclist = ospf_opaque_type10_funclist;
    1116           0 :         opaque_lsa_config_write_router_callback(funclist, vty);
    1117             : 
    1118           0 :         funclist = ospf_opaque_type11_funclist;
    1119           0 :         opaque_lsa_config_write_router_callback(funclist, vty);
    1120             : 
    1121           0 :         return;
    1122             : }
    1123             : 
    1124           0 : void ospf_opaque_config_write_if(struct vty *vty, struct interface *ifp)
    1125             : {
    1126           0 :         struct list *funclist;
    1127             : 
    1128           0 :         funclist = ospf_opaque_wildcard_funclist;
    1129           0 :         opaque_lsa_config_write_if_callback(funclist, vty, ifp);
    1130             : 
    1131           0 :         funclist = ospf_opaque_type9_funclist;
    1132           0 :         opaque_lsa_config_write_if_callback(funclist, vty, ifp);
    1133             : 
    1134           0 :         funclist = ospf_opaque_type10_funclist;
    1135           0 :         opaque_lsa_config_write_if_callback(funclist, vty, ifp);
    1136             : 
    1137           0 :         funclist = ospf_opaque_type11_funclist;
    1138           0 :         opaque_lsa_config_write_if_callback(funclist, vty, ifp);
    1139             : 
    1140           0 :         return;
    1141             : }
    1142             : 
    1143           0 : void ospf_opaque_config_write_debug(struct vty *vty)
    1144             : {
    1145           0 :         struct list *funclist;
    1146             : 
    1147           0 :         funclist = ospf_opaque_wildcard_funclist;
    1148           0 :         opaque_lsa_config_write_debug_callback(funclist, vty);
    1149             : 
    1150           0 :         funclist = ospf_opaque_type9_funclist;
    1151           0 :         opaque_lsa_config_write_debug_callback(funclist, vty);
    1152             : 
    1153           0 :         funclist = ospf_opaque_type10_funclist;
    1154           0 :         opaque_lsa_config_write_debug_callback(funclist, vty);
    1155             : 
    1156           0 :         funclist = ospf_opaque_type11_funclist;
    1157           0 :         opaque_lsa_config_write_debug_callback(funclist, vty);
    1158             : 
    1159           0 :         return;
    1160             : }
    1161             : 
    1162           0 : void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa,
    1163             :                              json_object *json)
    1164             : {
    1165           0 :         struct lsa_header *lsah = lsa->data;
    1166           0 :         uint32_t lsid = ntohl(lsah->id.s_addr);
    1167           0 :         uint8_t opaque_type = GET_OPAQUE_TYPE(lsid);
    1168           0 :         uint32_t opaque_id = GET_OPAQUE_ID(lsid);
    1169           0 :         struct ospf_opaque_functab *functab;
    1170             : 
    1171             :         /* Switch output functionality by vty address. */
    1172           0 :         if (vty != NULL) {
    1173           0 :                 if (!json) {
    1174           0 :                         vty_out(vty, "  Opaque-Type %u (%s)\n", opaque_type,
    1175             :                                 ospf_opaque_type_name(opaque_type));
    1176           0 :                         vty_out(vty, "  Opaque-ID   0x%x\n", opaque_id);
    1177             : 
    1178           0 :                         vty_out(vty, "  Opaque-Info: %u octets of data%s\n",
    1179           0 :                                 ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE,
    1180           0 :                                 VALID_OPAQUE_INFO_LEN(lsah)
    1181             :                                         ? ""
    1182             :                                         : "(Invalid length?)");
    1183             :                 } else {
    1184           0 :                         json_object_string_add(
    1185             :                                 json, "opaqueType",
    1186             :                                 ospf_opaque_type_name(opaque_type));
    1187           0 :                         json_object_int_add(json, "opaqueId", opaque_id);
    1188           0 :                         json_object_int_add(json, "opaqueDataLength",
    1189           0 :                                             ntohs(lsah->length)
    1190           0 :                                                     - OSPF_LSA_HEADER_SIZE);
    1191           0 :                         json_object_boolean_add(json, "opaqueDataLengthValid",
    1192           0 :                                                 VALID_OPAQUE_INFO_LEN(lsah));
    1193             :                 }
    1194             :         } else {
    1195           0 :                 zlog_debug("    Opaque-Type %u (%s)", opaque_type,
    1196             :                            ospf_opaque_type_name(opaque_type));
    1197           0 :                 zlog_debug("    Opaque-ID   0x%x", opaque_id);
    1198             : 
    1199           0 :                 zlog_debug("    Opaque-Info: %u octets of data%s",
    1200             :                            ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE,
    1201             :                            VALID_OPAQUE_INFO_LEN(lsah) ? ""
    1202             :                                                        : "(Invalid length?)");
    1203             :         }
    1204             : 
    1205             :         /* Call individual output functions. */
    1206           0 :         if ((functab = ospf_opaque_functab_lookup(lsa)) != NULL)
    1207           0 :                 if (functab->show_opaque_info != NULL)
    1208           0 :                         (*functab->show_opaque_info)(vty, json, lsa);
    1209             : 
    1210           0 :         return;
    1211             : }
    1212             : 
    1213           0 : void ospf_opaque_lsa_dump(struct stream *s, uint16_t length)
    1214             : {
    1215           0 :         struct ospf_lsa lsa = {};
    1216             : 
    1217           0 :         lsa.data = (struct lsa_header *)stream_pnt(s);
    1218           0 :         lsa.size = length;
    1219           0 :         show_opaque_info_detail(NULL, &lsa, NULL);
    1220           0 :         return;
    1221             : }
    1222             : 
    1223         159 : static int ospf_opaque_lsa_install_hook(struct ospf_lsa *lsa)
    1224             : {
    1225         159 :         struct list *funclist;
    1226         159 :         int rc = -1;
    1227             : 
    1228             :         /*
    1229             :          * Some Opaque-LSA user may want to monitor every LSA installation
    1230             :          * into the LSDB, regardless with target LSA type.
    1231             :          */
    1232         159 :         funclist = ospf_opaque_wildcard_funclist;
    1233         159 :         if (new_lsa_callback(funclist, lsa) != 0)
    1234           0 :                 goto out;
    1235             : 
    1236         159 :         funclist = ospf_opaque_type9_funclist;
    1237         159 :         if (new_lsa_callback(funclist, lsa) != 0)
    1238           0 :                 goto out;
    1239             : 
    1240         159 :         funclist = ospf_opaque_type10_funclist;
    1241         159 :         if (new_lsa_callback(funclist, lsa) != 0)
    1242           0 :                 goto out;
    1243             : 
    1244         159 :         funclist = ospf_opaque_type11_funclist;
    1245         159 :         if (new_lsa_callback(funclist, lsa) != 0)
    1246           0 :                 goto out;
    1247             : 
    1248             :         rc = 0;
    1249         159 : out:
    1250         159 :         return rc;
    1251             : }
    1252             : 
    1253         112 : static int ospf_opaque_lsa_delete_hook(struct ospf_lsa *lsa)
    1254             : {
    1255         112 :         struct list *funclist;
    1256         112 :         int rc = -1;
    1257             : 
    1258             :         /*
    1259             :          * Some Opaque-LSA user may want to monitor every LSA deletion
    1260             :          * from the LSDB, regardless with target LSA type.
    1261             :          */
    1262         112 :         funclist = ospf_opaque_wildcard_funclist;
    1263         112 :         if (del_lsa_callback(funclist, lsa) != 0)
    1264           0 :                 goto out;
    1265             : 
    1266         112 :         funclist = ospf_opaque_type9_funclist;
    1267         112 :         if (del_lsa_callback(funclist, lsa) != 0)
    1268           0 :                 goto out;
    1269             : 
    1270         112 :         funclist = ospf_opaque_type10_funclist;
    1271         112 :         if (del_lsa_callback(funclist, lsa) != 0)
    1272           0 :                 goto out;
    1273             : 
    1274         112 :         funclist = ospf_opaque_type11_funclist;
    1275         112 :         if (del_lsa_callback(funclist, lsa) != 0)
    1276           0 :                 goto out;
    1277             : 
    1278             :         rc = 0;
    1279         112 : out:
    1280         112 :         return rc;
    1281             : }
    1282             : 
    1283             : /*------------------------------------------------------------------------*
    1284             :  * Following are Opaque-LSA origination/refresh management functions.
    1285             :  *------------------------------------------------------------------------*/
    1286             : 
    1287             : static void ospf_opaque_type9_lsa_originate(struct thread *t);
    1288             : static void ospf_opaque_type10_lsa_originate(struct thread *t);
    1289             : static void ospf_opaque_type11_lsa_originate(struct thread *t);
    1290             : static void ospf_opaque_lsa_reoriginate_resume(struct list *listtop, void *arg);
    1291             : 
    1292           0 : void ospf_opaque_lsa_originate_schedule(struct ospf_interface *oi, int *delay0)
    1293             : {
    1294           0 :         struct ospf *top;
    1295           0 :         struct ospf_area *area;
    1296           0 :         struct listnode *node, *nnode;
    1297           0 :         struct opaque_info_per_type *oipt;
    1298           0 :         int delay = 0;
    1299             : 
    1300           0 :         if ((top = oi_to_top(oi)) == NULL || (area = oi->area) == NULL) {
    1301           0 :                 if (IS_DEBUG_OSPF_EVENT)
    1302           0 :                         zlog_debug("%s: Invalid argument?", __func__);
    1303           0 :                 return;
    1304             :         }
    1305             : 
    1306             :         /* It may not a right time to schedule origination now. */
    1307           0 :         if (!CHECK_FLAG(top->opaque, OPAQUE_OPERATION_READY_BIT)) {
    1308           0 :                 if (IS_DEBUG_OSPF_EVENT)
    1309           0 :                         zlog_debug("%s: Not operational.", __func__);
    1310           0 :                 return; /* This is not an error. */
    1311             :         }
    1312             : 
    1313           0 :         if (delay0 != NULL)
    1314           0 :                 delay = *delay0;
    1315             : 
    1316             :         /*
    1317             :          * There might be some entries that have been waiting for triggering
    1318             :          * of per opaque-type re-origination get resumed.
    1319             :          */
    1320           0 :         ospf_opaque_lsa_reoriginate_resume(oi->opaque_lsa_self, (void *)oi);
    1321           0 :         ospf_opaque_lsa_reoriginate_resume(area->opaque_lsa_self, (void *)area);
    1322           0 :         ospf_opaque_lsa_reoriginate_resume(top->opaque_lsa_self, (void *)top);
    1323             : 
    1324             :         /*
    1325             :          * Now, schedule origination of all Opaque-LSAs per opaque-type.
    1326             :          */
    1327           0 :         if (!list_isempty(ospf_opaque_type9_funclist)
    1328           0 :             && list_isempty(oi->opaque_lsa_self)
    1329           0 :             && oi->t_opaque_lsa_self == NULL) {
    1330           0 :                 if (IS_DEBUG_OSPF_EVENT)
    1331           0 :                         zlog_debug(
    1332             :                                 "Schedule Type-9 Opaque-LSA origination in %d ms later.",
    1333             :                                 delay);
    1334           0 :                 oi->t_opaque_lsa_self = NULL;
    1335           0 :                 thread_add_timer_msec(master, ospf_opaque_type9_lsa_originate,
    1336             :                                       oi, delay, &oi->t_opaque_lsa_self);
    1337           0 :                 delay += top->min_ls_interval;
    1338             :         }
    1339             : 
    1340           0 :         if (!list_isempty(ospf_opaque_type10_funclist)
    1341           0 :             && list_isempty(area->opaque_lsa_self)
    1342           0 :             && area->t_opaque_lsa_self == NULL) {
    1343             :                 /*
    1344             :                  * One AREA may contain multiple OIs, but above 2nd and 3rd
    1345             :                  * conditions prevent from scheduling the originate function
    1346             :                  * again and again.
    1347             :                  */
    1348           0 :                 if (IS_DEBUG_OSPF_EVENT)
    1349           0 :                         zlog_debug(
    1350             :                                 "Schedule Type-10 Opaque-LSA origination in %d ms later.",
    1351             :                                 delay);
    1352           0 :                 area->t_opaque_lsa_self = NULL;
    1353           0 :                 thread_add_timer_msec(master, ospf_opaque_type10_lsa_originate,
    1354             :                                       area, delay, &area->t_opaque_lsa_self);
    1355           0 :                 delay += top->min_ls_interval;
    1356             :         }
    1357             : 
    1358           0 :         if (!list_isempty(ospf_opaque_type11_funclist)
    1359           0 :             && list_isempty(top->opaque_lsa_self)
    1360           0 :             && top->t_opaque_lsa_self == NULL) {
    1361             :                 /*
    1362             :                  * One OSPF may contain multiple AREAs, but above 2nd and 3rd
    1363             :                  * conditions prevent from scheduling the originate function
    1364             :                  * again and again.
    1365             :                  */
    1366           0 :                 if (IS_DEBUG_OSPF_EVENT)
    1367           0 :                         zlog_debug(
    1368             :                                 "Schedule Type-11 Opaque-LSA origination in %d ms later.",
    1369             :                                 delay);
    1370           0 :                 top->t_opaque_lsa_self = NULL;
    1371           0 :                 thread_add_timer_msec(master, ospf_opaque_type11_lsa_originate,
    1372             :                                       top, delay, &top->t_opaque_lsa_self);
    1373           0 :                 delay += top->min_ls_interval;
    1374             :         }
    1375             : 
    1376             :         /*
    1377             :          * Following section treats a special situation that this node's
    1378             :          * opaque capability has changed as "ON -> OFF -> ON".
    1379             :          */
    1380           0 :         if (!list_isempty(ospf_opaque_type9_funclist)
    1381           0 :             && !list_isempty(oi->opaque_lsa_self)) {
    1382           0 :                 for (ALL_LIST_ELEMENTS(oi->opaque_lsa_self, node, nnode,
    1383             :                                        oipt)) {
    1384             :                         /*
    1385             :                          * removed the test for
    1386             :                          *   (! list_isempty (oipt->id_list))   * Handler is
    1387             :                          * already active. *
    1388             :                          * because opaque cababilities ON -> OFF -> ON result in
    1389             :                          * list_isempty (oipt->id_list)
    1390             :                          * not being empty.
    1391             :                          */
    1392           0 :                         if (oipt->t_opaque_lsa_self
    1393             :                                     != NULL /* Waiting for a thread call. */
    1394           0 :                             || oipt->status == PROC_SUSPEND) /* Cannot
    1395             :                                                                 originate
    1396             :                                                                 now. */
    1397           0 :                                 continue;
    1398             : 
    1399           0 :                         ospf_opaque_lsa_reoriginate_schedule(
    1400             :                                 (void *)oi, OSPF_OPAQUE_LINK_LSA,
    1401           0 :                                 oipt->opaque_type);
    1402             :                 }
    1403             :         }
    1404             : 
    1405           0 :         if (!list_isempty(ospf_opaque_type10_funclist)
    1406           0 :             && !list_isempty(area->opaque_lsa_self)) {
    1407           0 :                 for (ALL_LIST_ELEMENTS(area->opaque_lsa_self, node, nnode,
    1408             :                                        oipt)) {
    1409             :                         /*
    1410             :                          * removed the test for
    1411             :                          *   (! list_isempty (oipt->id_list))   * Handler is
    1412             :                          * already active. *
    1413             :                          * because opaque cababilities ON -> OFF -> ON result in
    1414             :                          * list_isempty (oipt->id_list)
    1415             :                          * not being empty.
    1416             :                          */
    1417           0 :                         if (oipt->t_opaque_lsa_self
    1418             :                                     != NULL /* Waiting for a thread call. */
    1419           0 :                             || oipt->status == PROC_SUSPEND) /* Cannot
    1420             :                                                                 originate
    1421             :                                                                 now. */
    1422           0 :                                 continue;
    1423             : 
    1424           0 :                         ospf_opaque_lsa_reoriginate_schedule(
    1425             :                                 (void *)area, OSPF_OPAQUE_AREA_LSA,
    1426           0 :                                 oipt->opaque_type);
    1427             :                 }
    1428             :         }
    1429             : 
    1430           0 :         if (!list_isempty(ospf_opaque_type11_funclist)
    1431           0 :             && !list_isempty(top->opaque_lsa_self)) {
    1432           0 :                 for (ALL_LIST_ELEMENTS(top->opaque_lsa_self, node, nnode,
    1433             :                                        oipt)) {
    1434             :                         /*
    1435             :                          * removed the test for
    1436             :                          *   (! list_isempty (oipt->id_list))   * Handler is
    1437             :                          * already active. *
    1438             :                          * because opaque cababilities ON -> OFF -> ON result in
    1439             :                          * list_isempty (oipt->id_list)
    1440             :                          * not being empty.
    1441             :                          */
    1442           0 :                         if (oipt->t_opaque_lsa_self
    1443             :                                     != NULL /* Waiting for a thread call. */
    1444           0 :                             || oipt->status == PROC_SUSPEND) /* Cannot
    1445             :                                                                 originate
    1446             :                                                                 now. */
    1447           0 :                                 continue;
    1448             : 
    1449           0 :                         ospf_opaque_lsa_reoriginate_schedule((void *)top,
    1450             :                                                              OSPF_OPAQUE_AS_LSA,
    1451           0 :                                                              oipt->opaque_type);
    1452             :                 }
    1453             :         }
    1454             : 
    1455           0 :         if (delay0 != NULL)
    1456           0 :                 *delay0 = delay;
    1457             : }
    1458             : 
    1459           0 : static void ospf_opaque_type9_lsa_originate(struct thread *t)
    1460             : {
    1461           0 :         struct ospf_interface *oi;
    1462             : 
    1463           0 :         oi = THREAD_ARG(t);
    1464           0 :         oi->t_opaque_lsa_self = NULL;
    1465             : 
    1466           0 :         if (IS_DEBUG_OSPF_EVENT)
    1467           0 :                 zlog_debug("Timer[Type9-LSA]: Originate Opaque-LSAs for OI %s",
    1468             :                            IF_NAME(oi));
    1469             : 
    1470           0 :         opaque_lsa_originate_callback(ospf_opaque_type9_funclist, oi);
    1471           0 : }
    1472             : 
    1473           0 : static void ospf_opaque_type10_lsa_originate(struct thread *t)
    1474             : {
    1475           0 :         struct ospf_area *area;
    1476             : 
    1477           0 :         area = THREAD_ARG(t);
    1478           0 :         area->t_opaque_lsa_self = NULL;
    1479             : 
    1480           0 :         if (IS_DEBUG_OSPF_EVENT)
    1481           0 :                 zlog_debug(
    1482             :                         "Timer[Type10-LSA]: Originate Opaque-LSAs for Area %pI4",
    1483             :                         &area->area_id);
    1484             : 
    1485           0 :         opaque_lsa_originate_callback(ospf_opaque_type10_funclist, area);
    1486           0 : }
    1487             : 
    1488           0 : static void ospf_opaque_type11_lsa_originate(struct thread *t)
    1489             : {
    1490           0 :         struct ospf *top;
    1491             : 
    1492           0 :         top = THREAD_ARG(t);
    1493           0 :         top->t_opaque_lsa_self = NULL;
    1494             : 
    1495           0 :         if (IS_DEBUG_OSPF_EVENT)
    1496           0 :                 zlog_debug(
    1497             :                         "Timer[Type11-LSA]: Originate AS-External Opaque-LSAs");
    1498             : 
    1499           0 :         opaque_lsa_originate_callback(ospf_opaque_type11_funclist, top);
    1500           0 : }
    1501             : 
    1502           0 : static void ospf_opaque_lsa_reoriginate_resume(struct list *listtop, void *arg)
    1503             : {
    1504           0 :         struct listnode *node, *nnode;
    1505           0 :         struct opaque_info_per_type *oipt;
    1506           0 :         struct ospf_opaque_functab *functab;
    1507             : 
    1508           0 :         if (listtop == NULL)
    1509           0 :                 goto out;
    1510             : 
    1511             :         /*
    1512             :          * Pickup oipt entries those which in SUSPEND status, and give
    1513             :          * them a chance to start re-origination now.
    1514             :          */
    1515           0 :         for (ALL_LIST_ELEMENTS(listtop, node, nnode, oipt)) {
    1516           0 :                 if (oipt->status != PROC_SUSPEND)
    1517           0 :                         continue;
    1518             : 
    1519           0 :                 oipt->status = PROC_NORMAL;
    1520             : 
    1521           0 :                 if ((functab = oipt->functab) == NULL
    1522           0 :                     || functab->lsa_originator == NULL)
    1523           0 :                         continue;
    1524             : 
    1525           0 :                 if ((*functab->lsa_originator)(arg) != 0) {
    1526           0 :                         flog_warn(EC_OSPF_LSA, "%s: Failed (opaque-type=%u)",
    1527             :                                   __func__, oipt->opaque_type);
    1528           0 :                         continue;
    1529             :                 }
    1530             :         }
    1531             : 
    1532           0 : out:
    1533           0 :         return;
    1534             : }
    1535             : 
    1536           0 : struct ospf_lsa *ospf_opaque_lsa_install(struct ospf_lsa *lsa, int rt_recalc)
    1537             : {
    1538           0 :         struct ospf_lsa *new = NULL;
    1539           0 :         struct opaque_info_per_type *oipt;
    1540           0 :         struct opaque_info_per_id *oipi;
    1541           0 :         struct ospf *top;
    1542             : 
    1543             :         /* Don't take "rt_recalc" into consideration for now. */ /* XXX */
    1544             : 
    1545           0 :         if (!IS_LSA_SELF(lsa)) {
    1546           0 :                 new = lsa; /* Don't touch this LSA. */
    1547           0 :                 goto out;
    1548             :         }
    1549             : 
    1550           0 :         if (IS_DEBUG_OSPF(lsa, LSA_INSTALL))
    1551           0 :                 zlog_debug(
    1552             :                         "Install Type-%u Opaque-LSA: [opaque-type=%u, opaque-id=%x]",
    1553             :                         lsa->data->type,
    1554             :                         GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)),
    1555             :                         GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)));
    1556             : 
    1557             :         /* Replace the existing lsa with the new one. */
    1558           0 :         if ((oipt = lookup_opaque_info_by_type(lsa)) != NULL
    1559           0 :             && (oipi = lookup_opaque_info_by_id(oipt, lsa)) != NULL) {
    1560           0 :                 ospf_lsa_unlock(&oipi->lsa);
    1561           0 :                 oipi->lsa = ospf_lsa_lock(lsa);
    1562             :         }
    1563             :         /* Register the new lsa entry */
    1564           0 :         else if (register_opaque_lsa(lsa) == NULL) {
    1565           0 :                 flog_warn(EC_OSPF_LSA, "%s: register_opaque_lsa() ?", __func__);
    1566           0 :                 goto out;
    1567             :         }
    1568             : 
    1569             :         /*
    1570             :          * Make use of a common mechanism (ospf_lsa_refresh_walker)
    1571             :          * for periodic refresh of self-originated Opaque-LSAs.
    1572             :          */
    1573           0 :         switch (lsa->data->type) {
    1574           0 :         case OSPF_OPAQUE_LINK_LSA:
    1575           0 :                 if ((top = oi_to_top(lsa->oi)) == NULL) {
    1576             :                         /* Above conditions must have passed. */
    1577           0 :                         flog_warn(EC_OSPF_LSA, "%s: Something wrong?",
    1578             :                                   __func__);
    1579           0 :                         goto out;
    1580             :                 }
    1581             :                 break;
    1582           0 :         case OSPF_OPAQUE_AREA_LSA:
    1583           0 :                 if (lsa->area == NULL || (top = lsa->area->ospf) == NULL) {
    1584             :                         /* Above conditions must have passed. */
    1585           0 :                         flog_warn(EC_OSPF_LSA, "%s: Something wrong?",
    1586             :                                   __func__);
    1587           0 :                         goto out;
    1588             :                 }
    1589             :                 break;
    1590           0 :         case OSPF_OPAQUE_AS_LSA:
    1591           0 :                 top = ospf_lookup_by_vrf_id(lsa->vrf_id);
    1592           0 :                 if (lsa->area != NULL && (top = lsa->area->ospf) == NULL) {
    1593             :                         /* Above conditions must have passed. */
    1594           0 :                         flog_warn(EC_OSPF_LSA, "%s: Something wrong?",
    1595             :                                   __func__);
    1596           0 :                         goto out;
    1597             :                 }
    1598             :                 break;
    1599           0 :         default:
    1600           0 :                 flog_warn(EC_OSPF_LSA_UNEXPECTED, "%s: Unexpected LSA-type(%u)",
    1601             :                           __func__, lsa->data->type);
    1602           0 :                 goto out;
    1603             :         }
    1604             : 
    1605           0 :         ospf_refresher_register_lsa(top, lsa);
    1606           0 :         new = lsa;
    1607             : 
    1608           0 : out:
    1609           0 :         return new;
    1610             : }
    1611             : 
    1612           0 : struct ospf_lsa *ospf_opaque_lsa_refresh(struct ospf_lsa *lsa)
    1613             : {
    1614           0 :         struct ospf *ospf;
    1615           0 :         struct ospf_opaque_functab *functab;
    1616           0 :         struct ospf_lsa *new = NULL;
    1617             : 
    1618           0 :         ospf = ospf_lookup_by_vrf_id(lsa->vrf_id);
    1619             : 
    1620           0 :         if ((functab = ospf_opaque_functab_lookup(lsa)) == NULL
    1621           0 :             || functab->lsa_refresher == NULL) {
    1622             :                 /*
    1623             :                  * Though this LSA seems to have originated on this node, the
    1624             :                  * handling module for this "lsa-type and opaque-type" was
    1625             :                  * already deleted sometime ago.
    1626             :                  * Anyway, this node still has a responsibility to flush this
    1627             :                  * LSA from the routing domain.
    1628             :                  */
    1629           0 :                 if (IS_DEBUG_OSPF_EVENT)
    1630           0 :                         zlog_debug("LSA[Type%d:%pI4]: Flush stray Opaque-LSA",
    1631             :                                    lsa->data->type, &lsa->data->id);
    1632             : 
    1633           0 :                 lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
    1634           0 :                 ospf_lsa_flush(ospf, lsa);
    1635             :         } else
    1636           0 :                 new = (*functab->lsa_refresher)(lsa);
    1637             : 
    1638           0 :         return new;
    1639             : }
    1640             : 
    1641             : /*------------------------------------------------------------------------*
    1642             :  * Following are re-origination/refresh/flush operations of Opaque-LSAs,
    1643             :  * triggered by external interventions (vty session, signaling, etc).
    1644             :  *------------------------------------------------------------------------*/
    1645             : 
    1646             : #define OSPF_OPAQUE_TIMER_ON(T,F,L,V) thread_add_timer_msec (master, (F), (L), (V), &(T))
    1647             : 
    1648             : static struct ospf_lsa *pseudo_lsa(struct ospf_interface *oi,
    1649             :                                    struct ospf_area *area, uint8_t lsa_type,
    1650             :                                    uint8_t opaque_type);
    1651             : static void ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t);
    1652             : static void ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t);
    1653             : static void ospf_opaque_type11_lsa_reoriginate_timer(struct thread *t);
    1654             : static void ospf_opaque_lsa_refresh_timer(struct thread *t);
    1655             : 
    1656           0 : void ospf_opaque_lsa_reoriginate_schedule(void *lsa_type_dependent,
    1657             :                                           uint8_t lsa_type, uint8_t opaque_type)
    1658             : {
    1659           0 :         struct ospf *top = NULL;
    1660           0 :         struct ospf_area dummy, *area = NULL;
    1661           0 :         struct ospf_interface *oi = NULL;
    1662             : 
    1663           0 :         struct ospf_lsa *lsa;
    1664           0 :         struct opaque_info_per_type *oipt;
    1665           0 :         void (*func)(struct thread * t) = NULL;
    1666           0 :         int delay;
    1667             : 
    1668           0 :         switch (lsa_type) {
    1669           0 :         case OSPF_OPAQUE_LINK_LSA:
    1670           0 :                 if ((oi = (struct ospf_interface *)lsa_type_dependent)
    1671             :                     == NULL) {
    1672           0 :                         flog_warn(EC_OSPF_LSA,
    1673             :                                   "%s: Type-9 Opaque-LSA: Invalid parameter?",
    1674             :                                   __func__);
    1675           0 :                         goto out;
    1676             :                 }
    1677           0 :                 if ((top = oi_to_top(oi)) == NULL) {
    1678           0 :                         flog_warn(EC_OSPF_LSA, "%s: OI(%s) -> TOP?", __func__,
    1679             :                                   IF_NAME(oi));
    1680           0 :                         goto out;
    1681             :                 }
    1682           0 :                 if (!list_isempty(ospf_opaque_type9_funclist)
    1683           0 :                     && list_isempty(oi->opaque_lsa_self)
    1684           0 :                     && oi->t_opaque_lsa_self != NULL) {
    1685           0 :                         flog_warn(
    1686             :                                 EC_OSPF_LSA,
    1687             :                                 "Type-9 Opaque-LSA (opaque_type=%u): Common origination for OI(%s) has already started",
    1688             :                                 opaque_type, IF_NAME(oi));
    1689           0 :                         goto out;
    1690             :                 }
    1691             :                 func = ospf_opaque_type9_lsa_reoriginate_timer;
    1692             :                 break;
    1693           0 :         case OSPF_OPAQUE_AREA_LSA:
    1694           0 :                 if ((area = (struct ospf_area *)lsa_type_dependent) == NULL) {
    1695           0 :                         flog_warn(EC_OSPF_LSA,
    1696             :                                   "%s: Type-10 Opaque-LSA: Invalid parameter?",
    1697             :                                   __func__);
    1698           0 :                         goto out;
    1699             :                 }
    1700           0 :                 if ((top = area->ospf) == NULL) {
    1701           0 :                         flog_warn(EC_OSPF_LSA, "%s: AREA(%pI4) -> TOP?",
    1702             :                                   __func__, &area->area_id);
    1703           0 :                         goto out;
    1704             :                 }
    1705           0 :                 if (!list_isempty(ospf_opaque_type10_funclist)
    1706           0 :                     && list_isempty(area->opaque_lsa_self)
    1707           0 :                     && area->t_opaque_lsa_self != NULL) {
    1708           0 :                         flog_warn(
    1709             :                                 EC_OSPF_LSA,
    1710             :                                 "Type-10 Opaque-LSA (opaque_type=%u): Common origination for AREA(%pI4) has already started",
    1711             :                                 opaque_type, &area->area_id);
    1712           0 :                         goto out;
    1713             :                 }
    1714             :                 func = ospf_opaque_type10_lsa_reoriginate_timer;
    1715             :                 break;
    1716           0 :         case OSPF_OPAQUE_AS_LSA:
    1717           0 :                 if ((top = (struct ospf *)lsa_type_dependent) == NULL) {
    1718           0 :                         flog_warn(EC_OSPF_LSA,
    1719             :                                   "%s: Type-11 Opaque-LSA: Invalid parameter?",
    1720             :                                   __func__);
    1721           0 :                         goto out;
    1722             :                 }
    1723           0 :                 if (!list_isempty(ospf_opaque_type11_funclist)
    1724           0 :                     && list_isempty(top->opaque_lsa_self)
    1725           0 :                     && top->t_opaque_lsa_self != NULL) {
    1726           0 :                         flog_warn(
    1727             :                                 EC_OSPF_LSA,
    1728             :                                 "Type-11 Opaque-LSA (opaque_type=%u): Common origination has already started",
    1729             :                                 opaque_type);
    1730           0 :                         goto out;
    1731             :                 }
    1732             : 
    1733             :                 /* Fake "area" to pass "ospf" to a lookup function later. */
    1734           0 :                 dummy.ospf = top;
    1735           0 :                 area = &dummy;
    1736             : 
    1737           0 :                 func = ospf_opaque_type11_lsa_reoriginate_timer;
    1738           0 :                 break;
    1739           0 :         default:
    1740           0 :                 flog_warn(EC_OSPF_LSA_UNEXPECTED, "%s: Unexpected LSA-type(%u)",
    1741             :                           __func__, lsa_type);
    1742           0 :                 goto out;
    1743             :         }
    1744             : 
    1745             :         /* It may not a right time to schedule reorigination now. */
    1746           0 :         if (!CHECK_FLAG(top->opaque, OPAQUE_OPERATION_READY_BIT)) {
    1747           0 :                 if (IS_DEBUG_OSPF_EVENT)
    1748           0 :                         zlog_debug("%s: Not operational.", __func__);
    1749           0 :                 goto out; /* This is not an error. */
    1750             :         }
    1751             : 
    1752             :         /* Generate a dummy lsa to be passed for a lookup function. */
    1753           0 :         lsa = pseudo_lsa(oi, area, lsa_type, opaque_type);
    1754           0 :         lsa->vrf_id = top->vrf_id;
    1755             : 
    1756           0 :         if ((oipt = lookup_opaque_info_by_type(lsa)) == NULL) {
    1757           0 :                 struct ospf_opaque_functab *functab;
    1758           0 :                 if ((functab = ospf_opaque_functab_lookup(lsa)) == NULL) {
    1759           0 :                         flog_warn(
    1760             :                                 EC_OSPF_LSA,
    1761             :                                 "%s: No associated function?: lsa_type(%u), opaque_type(%u)",
    1762             :                                 __func__, lsa_type, opaque_type);
    1763           0 :                         goto out;
    1764             :                 }
    1765           0 :                 if ((oipt = register_opaque_info_per_type(functab, lsa))
    1766             :                     == NULL) {
    1767           0 :                         flog_warn(
    1768             :                                 EC_OSPF_LSA,
    1769             :                                 "%s: Cannot get a control info?: lsa_type(%u), opaque_type(%u)",
    1770             :                                 __func__, lsa_type, opaque_type);
    1771           0 :                         goto out;
    1772             :                 }
    1773             :         }
    1774             : 
    1775           0 :         if (oipt->t_opaque_lsa_self != NULL) {
    1776           0 :                 if (IS_DEBUG_OSPF_EVENT)
    1777           0 :                         zlog_debug(
    1778             :                                 "Type-%u Opaque-LSA has already scheduled to RE-ORIGINATE: [opaque-type=%u]",
    1779             :                                 lsa_type,
    1780             :                                 GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)));
    1781           0 :                 goto out;
    1782             :         }
    1783             : 
    1784             :         /*
    1785             :          * Different from initial origination time, in which various conditions
    1786             :          * (opaque capability, neighbor status etc) are assured by caller of
    1787             :          * the originating function "ospf_opaque_lsa_originate_schedule ()",
    1788             :          * it is highly possible that these conditions might not be satisfied
    1789             :          * at the time of re-origination function is to be called.
    1790             :          */
    1791           0 :         delay = top->min_ls_interval; /* XXX */
    1792             : 
    1793           0 :         if (IS_DEBUG_OSPF_EVENT)
    1794           0 :                 zlog_debug(
    1795             :                         "Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d ms later: [opaque-type=%u]",
    1796             :                         lsa_type, delay,
    1797             :                         GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)));
    1798             : 
    1799           0 :         OSPF_OPAQUE_TIMER_ON(oipt->t_opaque_lsa_self, func, oipt, delay);
    1800             : 
    1801           0 : out:
    1802           0 :         return;
    1803             : }
    1804             : 
    1805           0 : static struct ospf_lsa *pseudo_lsa(struct ospf_interface *oi,
    1806             :                                    struct ospf_area *area, uint8_t lsa_type,
    1807             :                                    uint8_t opaque_type)
    1808             : {
    1809           0 :         static struct ospf_lsa lsa = {0};
    1810           0 :         static struct lsa_header lsah = {0};
    1811           0 :         uint32_t tmp;
    1812             : 
    1813           0 :         lsa.oi = oi;
    1814           0 :         lsa.area = area;
    1815           0 :         lsa.data = &lsah;
    1816           0 :         lsa.vrf_id = VRF_DEFAULT;
    1817             : 
    1818           0 :         lsah.type = lsa_type;
    1819           0 :         tmp = SET_OPAQUE_LSID(opaque_type, 0); /* Opaque-ID is unused here. */
    1820           0 :         lsah.id.s_addr = htonl(tmp);
    1821             : 
    1822           0 :         return &lsa;
    1823             : }
    1824             : 
    1825           0 : static void ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t)
    1826             : {
    1827           0 :         struct opaque_info_per_type *oipt;
    1828           0 :         struct ospf_opaque_functab *functab;
    1829           0 :         struct ospf *top;
    1830           0 :         struct ospf_interface *oi;
    1831             : 
    1832           0 :         oipt = THREAD_ARG(t);
    1833             : 
    1834           0 :         if ((functab = oipt->functab) == NULL
    1835           0 :             || functab->lsa_originator == NULL) {
    1836           0 :                 flog_warn(EC_OSPF_LSA, "%s: No associated function?", __func__);
    1837           0 :                 return;
    1838             :         }
    1839             : 
    1840           0 :         oi = (struct ospf_interface *)oipt->owner;
    1841           0 :         if ((top = oi_to_top(oi)) == NULL) {
    1842           0 :                 flog_warn(EC_OSPF_LSA, "%s: Something wrong?", __func__);
    1843           0 :                 return;
    1844             :         }
    1845             : 
    1846           0 :         if (!CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE)
    1847           0 :             || !ospf_if_is_enable(oi)
    1848           0 :             || ospf_nbr_count_opaque_capable(oi) == 0) {
    1849           0 :                 if (IS_DEBUG_OSPF_EVENT)
    1850           0 :                         zlog_debug(
    1851             :                                 "Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...",
    1852             :                                 oipt->opaque_type);
    1853             : 
    1854           0 :                 oipt->status = PROC_SUSPEND;
    1855           0 :                 return;
    1856             :         }
    1857             : 
    1858           0 :         if (IS_DEBUG_OSPF_EVENT)
    1859           0 :                 zlog_debug(
    1860             :                         "Timer[Type9-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for OI (%s)",
    1861             :                         oipt->opaque_type, IF_NAME(oi));
    1862             : 
    1863           0 :         (*functab->lsa_originator)(oi);
    1864             : }
    1865             : 
    1866           0 : static void ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t)
    1867             : {
    1868           0 :         struct opaque_info_per_type *oipt;
    1869           0 :         struct ospf_opaque_functab *functab;
    1870           0 :         struct listnode *node, *nnode;
    1871           0 :         struct ospf *top;
    1872           0 :         struct ospf_area *area;
    1873           0 :         struct ospf_interface *oi;
    1874           0 :         int n;
    1875             : 
    1876           0 :         oipt = THREAD_ARG(t);
    1877             : 
    1878           0 :         if ((functab = oipt->functab) == NULL
    1879           0 :             || functab->lsa_originator == NULL) {
    1880           0 :                 flog_warn(EC_OSPF_LSA, "%s: No associated function?", __func__);
    1881           0 :                 return;
    1882             :         }
    1883             : 
    1884           0 :         area = (struct ospf_area *)oipt->owner;
    1885           0 :         if (area == NULL || (top = area->ospf) == NULL) {
    1886           0 :                 flog_warn(EC_OSPF_LSA, "%s: Something wrong?", __func__);
    1887           0 :                 return;
    1888             :         }
    1889             : 
    1890             :         /* There must be at least one "opaque-capable, full-state" neighbor. */
    1891           0 :         n = 0;
    1892           0 :         for (ALL_LIST_ELEMENTS(area->oiflist, node, nnode, oi)) {
    1893           0 :                 if ((n = ospf_nbr_count_opaque_capable(oi)) > 0)
    1894             :                         break;
    1895             :         }
    1896             : 
    1897           0 :         if (n == 0 || !CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE)) {
    1898           0 :                 if (IS_DEBUG_OSPF_EVENT)
    1899           0 :                         zlog_debug(
    1900             :                                 "Suspend re-origination of Type-10 Opaque-LSAs (opaque-type=%u) for a while...",
    1901             :                                 oipt->opaque_type);
    1902             : 
    1903           0 :                 oipt->status = PROC_SUSPEND;
    1904           0 :                 return;
    1905             :         }
    1906             : 
    1907           0 :         if (IS_DEBUG_OSPF_EVENT)
    1908           0 :                 zlog_debug(
    1909             :                         "Timer[Type10-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for Area %pI4",
    1910             :                         oipt->opaque_type, &area->area_id);
    1911             : 
    1912           0 :         (*functab->lsa_originator)(area);
    1913             : }
    1914             : 
    1915           0 : static void ospf_opaque_type11_lsa_reoriginate_timer(struct thread *t)
    1916             : {
    1917           0 :         struct opaque_info_per_type *oipt;
    1918           0 :         struct ospf_opaque_functab *functab;
    1919           0 :         struct ospf *top;
    1920             : 
    1921           0 :         oipt = THREAD_ARG(t);
    1922             : 
    1923           0 :         if ((functab = oipt->functab) == NULL
    1924           0 :             || functab->lsa_originator == NULL) {
    1925           0 :                 flog_warn(EC_OSPF_LSA, "%s: No associated function?", __func__);
    1926           0 :                 return;
    1927             :         }
    1928             : 
    1929           0 :         if ((top = (struct ospf *)oipt->owner) == NULL) {
    1930           0 :                 flog_warn(EC_OSPF_LSA, "%s: Something wrong?", __func__);
    1931           0 :                 return;
    1932             :         }
    1933             : 
    1934           0 :         if (!CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE)) {
    1935           0 :                 if (IS_DEBUG_OSPF_EVENT)
    1936           0 :                         zlog_debug(
    1937             :                                 "Suspend re-origination of Type-11 Opaque-LSAs (opaque-type=%u) for a while...",
    1938             :                                 oipt->opaque_type);
    1939             : 
    1940           0 :                 oipt->status = PROC_SUSPEND;
    1941           0 :                 return;
    1942             :         }
    1943             : 
    1944           0 :         if (IS_DEBUG_OSPF_EVENT)
    1945           0 :                 zlog_debug(
    1946             :                         "Timer[Type11-LSA]: Re-originate Opaque-LSAs (opaque-type=%u).",
    1947             :                         oipt->opaque_type);
    1948             : 
    1949           0 :         (*functab->lsa_originator)(top);
    1950             : }
    1951             : 
    1952           0 : void ospf_opaque_lsa_refresh_schedule(struct ospf_lsa *lsa0)
    1953             : {
    1954           0 :         struct opaque_info_per_type *oipt;
    1955           0 :         struct opaque_info_per_id *oipi;
    1956           0 :         struct ospf_lsa *lsa;
    1957           0 :         struct ospf *top;
    1958           0 :         int delay;
    1959             : 
    1960           0 :         if ((oipt = lookup_opaque_info_by_type(lsa0)) == NULL
    1961           0 :             || (oipi = lookup_opaque_info_by_id(oipt, lsa0)) == NULL) {
    1962           0 :                 flog_warn(EC_OSPF_LSA, "%s: Invalid parameter?", __func__);
    1963           0 :                 goto out;
    1964             :         }
    1965             : 
    1966             :         /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
    1967           0 :         if ((lsa = oipi->lsa) == NULL) {
    1968           0 :                 flog_warn(EC_OSPF_LSA, "%s: Something wrong?", __func__);
    1969           0 :                 goto out;
    1970             :         }
    1971             : 
    1972           0 :         if (oipi->t_opaque_lsa_self != NULL) {
    1973           0 :                 if (IS_DEBUG_OSPF_EVENT)
    1974           0 :                         zlog_debug(
    1975             :                                 "Type-%u Opaque-LSA has already scheduled to REFRESH: [opaque-type=%u, opaque-id=%x]",
    1976             :                                 lsa->data->type,
    1977             :                                 GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)),
    1978             :                                 GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)));
    1979           0 :                 goto out;
    1980             :         }
    1981             : 
    1982             :         /* Delete this lsa from neighbor retransmit-list. */
    1983           0 :         switch (lsa->data->type) {
    1984           0 :         case OSPF_OPAQUE_LINK_LSA:
    1985             :         case OSPF_OPAQUE_AREA_LSA:
    1986           0 :                 ospf_ls_retransmit_delete_nbr_area(lsa->area, lsa);
    1987           0 :                 break;
    1988           0 :         case OSPF_OPAQUE_AS_LSA:
    1989           0 :                 top = ospf_lookup_by_vrf_id(lsa0->vrf_id);
    1990           0 :                 if ((lsa0->area != NULL) && (lsa0->area->ospf != NULL))
    1991           0 :                         top = lsa0->area->ospf;
    1992           0 :                 ospf_ls_retransmit_delete_nbr_as(top, lsa);
    1993           0 :                 break;
    1994           0 :         default:
    1995           0 :                 flog_warn(EC_OSPF_LSA_UNEXPECTED, "%s: Unexpected LSA-type(%u)",
    1996             :                           __func__, lsa->data->type);
    1997           0 :                 goto out;
    1998             :         }
    1999             : 
    2000           0 :         delay = ospf_lsa_refresh_delay(lsa);
    2001             : 
    2002           0 :         if (IS_DEBUG_OSPF_EVENT)
    2003           0 :                 zlog_debug(
    2004             :                         "Schedule Type-%u Opaque-LSA to REFRESH in %d sec later: [opaque-type=%u, opaque-id=%x]",
    2005             :                         lsa->data->type, delay,
    2006             :                         GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)),
    2007             :                         GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)));
    2008             : 
    2009           0 :         OSPF_OPAQUE_TIMER_ON(oipi->t_opaque_lsa_self,
    2010             :                              ospf_opaque_lsa_refresh_timer, oipi, delay * 1000);
    2011           0 : out:
    2012           0 :         return;
    2013             : }
    2014             : 
    2015           0 : static void ospf_opaque_lsa_refresh_timer(struct thread *t)
    2016             : {
    2017           0 :         struct opaque_info_per_id *oipi;
    2018           0 :         struct ospf_opaque_functab *functab;
    2019           0 :         struct ospf_lsa *lsa;
    2020             : 
    2021           0 :         if (IS_DEBUG_OSPF_EVENT)
    2022           0 :                 zlog_debug("Timer[Opaque-LSA]: (Opaque-LSA Refresh expire)");
    2023             : 
    2024           0 :         oipi = THREAD_ARG(t);
    2025             : 
    2026           0 :         if ((lsa = oipi->lsa) != NULL)
    2027           0 :                 if ((functab = oipi->opqctl_type->functab) != NULL)
    2028           0 :                         if (functab->lsa_refresher != NULL)
    2029           0 :                                 (*functab->lsa_refresher)(lsa);
    2030           0 : }
    2031             : 
    2032           0 : void ospf_opaque_lsa_flush_schedule(struct ospf_lsa *lsa0)
    2033             : {
    2034           0 :         struct opaque_info_per_type *oipt;
    2035           0 :         struct opaque_info_per_id *oipi;
    2036           0 :         struct ospf_lsa *lsa;
    2037           0 :         struct ospf *top;
    2038             : 
    2039           0 :         top = ospf_lookup_by_vrf_id(lsa0->vrf_id);
    2040             : 
    2041           0 :         if ((oipt = lookup_opaque_info_by_type(lsa0)) == NULL
    2042           0 :             || (oipi = lookup_opaque_info_by_id(oipt, lsa0)) == NULL) {
    2043           0 :                 flog_warn(EC_OSPF_LSA, "%s: Invalid parameter?", __func__);
    2044           0 :                 goto out;
    2045             :         }
    2046             : 
    2047             :         /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
    2048           0 :         if ((lsa = oipi->lsa) == NULL) {
    2049           0 :                 flog_warn(EC_OSPF_LSA, "%s: Something wrong?", __func__);
    2050           0 :                 goto out;
    2051             :         }
    2052             : 
    2053           0 :         if (lsa->opaque_zero_len_delete &&
    2054           0 :             lsa->data->length != htons(sizeof(struct lsa_header))) {
    2055             :                 /* minimize the size of the withdrawal: */
    2056             :                 /*     increment the sequence number and make len just header */
    2057             :                 /*     and update checksum */
    2058           0 :                 lsa->data->ls_seqnum = lsa_seqnum_increment(lsa);
    2059           0 :                 lsa->data->length = htons(sizeof(struct lsa_header));
    2060           0 :                 lsa->data->checksum = 0;
    2061           0 :                 lsa->data->checksum = ospf_lsa_checksum(lsa->data);
    2062             :         }
    2063             : 
    2064             :         /* Delete this lsa from neighbor retransmit-list. */
    2065           0 :         switch (lsa->data->type) {
    2066           0 :         case OSPF_OPAQUE_LINK_LSA:
    2067             :         case OSPF_OPAQUE_AREA_LSA:
    2068           0 :                 ospf_ls_retransmit_delete_nbr_area(lsa->area, lsa);
    2069           0 :                 break;
    2070           0 :         case OSPF_OPAQUE_AS_LSA:
    2071           0 :                 if ((lsa0->area != NULL) && (lsa0->area->ospf != NULL))
    2072           0 :                         top = lsa0->area->ospf;
    2073           0 :                 ospf_ls_retransmit_delete_nbr_as(top, lsa);
    2074           0 :                 break;
    2075           0 :         default:
    2076           0 :                 flog_warn(EC_OSPF_LSA_UNEXPECTED, "%s: Unexpected LSA-type(%u)",
    2077             :                           __func__, lsa->data->type);
    2078           0 :                 goto out;
    2079             :         }
    2080             : 
    2081             :         /* This lsa will be flushed and removed eventually. */
    2082           0 :         ospf_lsa_flush(top, lsa);
    2083             : 
    2084             :         /* Dequeue listnode entry from the list. */
    2085           0 :         listnode_delete(oipt->id_list, oipi);
    2086             : 
    2087           0 :         if (IS_DEBUG_OSPF_EVENT)
    2088           0 :                 zlog_debug(
    2089             :                         "Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]",
    2090             :                         lsa->data->type,
    2091             :                         GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)),
    2092             :                         GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)));
    2093             : 
    2094             :         /* Disassociate internal control information with the given lsa. */
    2095           0 :         free_opaque_info_per_id((void *)oipi);
    2096             : 
    2097           0 : out:
    2098           0 :         return;
    2099             : }
    2100             : 
    2101           0 : void ospf_opaque_self_originated_lsa_received(struct ospf_neighbor *nbr,
    2102             :                                               struct ospf_lsa *lsa)
    2103             : {
    2104           0 :         struct ospf *top;
    2105             : 
    2106           0 :         if ((top = oi_to_top(nbr->oi)) == NULL)
    2107             :                 return;
    2108             : 
    2109           0 :         if (IS_DEBUG_OSPF_EVENT)
    2110           0 :                 zlog_debug(
    2111             :                         "LSA[Type%d:%pI4]: processing self-originated Opaque-LSA",
    2112             :                         lsa->data->type, &lsa->data->id);
    2113             : 
    2114             :         /*
    2115             :          * Since these LSA entries are not yet installed into corresponding
    2116             :          * LSDB, just flush them without calling ospf_ls_maxage() afterward.
    2117             :          */
    2118           0 :         lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
    2119           0 :         switch (lsa->data->type) {
    2120           0 :         case OSPF_OPAQUE_LINK_LSA:
    2121           0 :                 ospf_flood_through_area(nbr->oi->area, NULL /*inbr*/, lsa);
    2122           0 :                 break;
    2123           0 :         case OSPF_OPAQUE_AREA_LSA:
    2124           0 :                 ospf_flood_through_area(nbr->oi->area, NULL /*inbr*/, lsa);
    2125           0 :                 break;
    2126           0 :         case OSPF_OPAQUE_AS_LSA:
    2127           0 :                 ospf_flood_through_as(top, NULL /*inbr*/, lsa);
    2128           0 :                 break;
    2129           0 :         default:
    2130           0 :                 flog_warn(EC_OSPF_LSA_UNEXPECTED, "%s: Unexpected LSA-type(%u)",
    2131             :                           __func__, lsa->data->type);
    2132           0 :                 return;
    2133             :         }
    2134           0 :         ospf_lsa_discard(lsa); /* List "lsas" will be deleted by caller. */
    2135             : }
    2136             : 
    2137             : /*------------------------------------------------------------------------*
    2138             :  * Following are util functions; probably be used by Opaque-LSAs only...
    2139             :  *------------------------------------------------------------------------*/
    2140             : 
    2141          55 : struct ospf *oi_to_top(struct ospf_interface *oi)
    2142             : {
    2143          55 :         struct ospf *top = NULL;
    2144          55 :         struct ospf_area *area;
    2145             : 
    2146          55 :         if (oi == NULL || (area = oi->area) == NULL
    2147          55 :             || (top = area->ospf) == NULL)
    2148           0 :                 flog_warn(EC_OSPF_LSA,
    2149             :                           "Broken relationship for \"OI -> AREA -> OSPF\"?");
    2150             : 
    2151          55 :         return top;
    2152             : }

Generated by: LCOV version v1.16-topotato