2 * This is an implementation of rfc2370.
3 * Copyright (C) 2001 KDD R&D Laboratories, Inc.
4 * http://www.kddlabs.co.jp/
6 * This file is part of GNU Zebra.
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
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.
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
36 #include "sockunion.h" /* for inet_aton() */
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"
54 DEFINE_MTYPE_STATIC(OSPFD
, OSPF_OPAQUE_FUNCTAB
, "OSPF opaque function table")
55 DEFINE_MTYPE_STATIC(OSPFD
, OPAQUE_INFO_PER_TYPE
, "OSPF opaque per-type info")
56 DEFINE_MTYPE_STATIC(OSPFD
, OPAQUE_INFO_PER_ID
, "OSPF opaque per-ID info")
58 /*------------------------------------------------------------------------*
59 * Followings are initialize/terminate functions for Opaque-LSAs handling.
60 *------------------------------------------------------------------------*/
62 #include "ospfd/ospf_te.h"
63 #include "ospfd/ospf_ri.h"
65 #ifdef SUPPORT_OSPF_API
66 int ospf_apiserver_init(void);
67 void ospf_apiserver_term(void);
68 /* Init apiserver? It's disabled by default. */
69 int ospf_apiserver_enable
;
70 #endif /* SUPPORT_OSPF_API */
72 static void ospf_opaque_register_vty(void);
73 static void ospf_opaque_funclist_init(void);
74 static void ospf_opaque_funclist_term(void);
75 static void free_opaque_info_per_type(void *val
);
76 static void free_opaque_info_per_id(void *val
);
77 static int ospf_opaque_lsa_install_hook(struct ospf_lsa
*lsa
);
78 static int ospf_opaque_lsa_delete_hook(struct ospf_lsa
*lsa
);
80 void ospf_opaque_init(void)
82 ospf_opaque_register_vty();
83 ospf_opaque_funclist_init();
85 if (ospf_mpls_te_init() != 0)
88 if (ospf_router_info_init() != 0)
91 #ifdef SUPPORT_OSPF_API
92 if ((ospf_apiserver_enable
) && (ospf_apiserver_init() != 0))
94 #endif /* SUPPORT_OSPF_API */
99 void ospf_opaque_term(void)
103 ospf_router_info_term();
105 #ifdef SUPPORT_OSPF_API
106 ospf_apiserver_term();
107 #endif /* SUPPORT_OSPF_API */
109 ospf_opaque_funclist_term();
113 int ospf_opaque_type9_lsa_init(struct ospf_interface
*oi
)
115 if (oi
->opaque_lsa_self
!= NULL
)
116 list_delete_and_null(&oi
->opaque_lsa_self
);
118 oi
->opaque_lsa_self
= list_new();
119 oi
->opaque_lsa_self
->del
= free_opaque_info_per_type
;
120 oi
->t_opaque_lsa_self
= NULL
;
124 void ospf_opaque_type9_lsa_term(struct ospf_interface
*oi
)
126 OSPF_TIMER_OFF(oi
->t_opaque_lsa_self
);
127 if (oi
->opaque_lsa_self
!= NULL
)
128 list_delete_and_null(&oi
->opaque_lsa_self
);
129 oi
->opaque_lsa_self
= NULL
;
133 int ospf_opaque_type10_lsa_init(struct ospf_area
*area
)
135 if (area
->opaque_lsa_self
!= NULL
)
136 list_delete_and_null(&area
->opaque_lsa_self
);
138 area
->opaque_lsa_self
= list_new();
139 area
->opaque_lsa_self
->del
= free_opaque_info_per_type
;
140 area
->t_opaque_lsa_self
= NULL
;
142 #ifdef MONITOR_LSDB_CHANGE
143 area
->lsdb
->new_lsa_hook
= ospf_opaque_lsa_install_hook
;
144 area
->lsdb
->del_lsa_hook
= ospf_opaque_lsa_delete_hook
;
145 #endif /* MONITOR_LSDB_CHANGE */
149 void ospf_opaque_type10_lsa_term(struct ospf_area
*area
)
151 #ifdef MONITOR_LSDB_CHANGE
152 area
->lsdb
->new_lsa_hook
= area
->lsdb
->del_lsa_hook
= NULL
;
153 #endif /* MONITOR_LSDB_CHANGE */
155 OSPF_TIMER_OFF(area
->t_opaque_lsa_self
);
156 if (area
->opaque_lsa_self
!= NULL
)
157 list_delete_and_null(&area
->opaque_lsa_self
);
161 int ospf_opaque_type11_lsa_init(struct ospf
*top
)
163 if (top
->opaque_lsa_self
!= NULL
)
164 list_delete_and_null(&top
->opaque_lsa_self
);
166 top
->opaque_lsa_self
= list_new();
167 top
->opaque_lsa_self
->del
= free_opaque_info_per_type
;
168 top
->t_opaque_lsa_self
= NULL
;
170 #ifdef MONITOR_LSDB_CHANGE
171 top
->lsdb
->new_lsa_hook
= ospf_opaque_lsa_install_hook
;
172 top
->lsdb
->del_lsa_hook
= ospf_opaque_lsa_delete_hook
;
173 #endif /* MONITOR_LSDB_CHANGE */
177 void ospf_opaque_type11_lsa_term(struct ospf
*top
)
179 #ifdef MONITOR_LSDB_CHANGE
180 top
->lsdb
->new_lsa_hook
= top
->lsdb
->del_lsa_hook
= NULL
;
181 #endif /* MONITOR_LSDB_CHANGE */
183 OSPF_TIMER_OFF(top
->t_opaque_lsa_self
);
184 if (top
->opaque_lsa_self
!= NULL
)
185 list_delete_and_null(&top
->opaque_lsa_self
);
189 static const char *ospf_opaque_type_name(u_char opaque_type
)
191 const char *name
= "Unknown";
193 switch (opaque_type
) {
194 case OPAQUE_TYPE_WILDCARD
: /* This is a special assignment! */
197 case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA
:
198 name
= "Traffic Engineering LSA";
200 case OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC
:
201 name
= "Sycamore optical topology description";
203 case OPAQUE_TYPE_GRACE_LSA
:
206 case OPAQUE_TYPE_INTER_AS_LSA
:
207 name
= "Inter-AS TE-v2 LSA";
209 case OPAQUE_TYPE_ROUTER_INFORMATION_LSA
:
210 name
= "Router Information LSA";
213 if (OPAQUE_TYPE_RANGE_UNASSIGNED(opaque_type
))
216 u_int32_t bigger_range
= opaque_type
;
218 * Get around type-limits warning: comparison is always
219 * true due to limited range of data type
221 if (OPAQUE_TYPE_RANGE_RESERVED(bigger_range
))
222 name
= "Private/Experimental";
229 /*------------------------------------------------------------------------*
230 * Followings are management functions to store user specified callbacks.
231 *------------------------------------------------------------------------*/
233 struct opaque_info_per_type
; /* Forward declaration. */
235 struct ospf_opaque_functab
{
237 struct opaque_info_per_type
*oipt
;
239 int (*new_if_hook
)(struct interface
*ifp
);
240 int (*del_if_hook
)(struct interface
*ifp
);
241 void (*ism_change_hook
)(struct ospf_interface
*oi
, int old_status
);
242 void (*nsm_change_hook
)(struct ospf_neighbor
*nbr
, int old_status
);
243 void (*config_write_router
)(struct vty
*vty
);
244 void (*config_write_if
)(struct vty
*vty
, struct interface
*ifp
);
245 void (*config_write_debug
)(struct vty
*vty
);
246 void (*show_opaque_info
)(struct vty
*vty
, struct ospf_lsa
*lsa
);
247 int (*lsa_originator
)(void *arg
);
248 struct ospf_lsa
*(*lsa_refresher
)(struct ospf_lsa
*lsa
);
249 int (*new_lsa_hook
)(struct ospf_lsa
*lsa
);
250 int (*del_lsa_hook
)(struct ospf_lsa
*lsa
);
253 /* Handle LSA-9/10/11 altogether. */
254 static struct list
*ospf_opaque_wildcard_funclist
;
255 static struct list
*ospf_opaque_type9_funclist
;
256 static struct list
*ospf_opaque_type10_funclist
;
257 static struct list
*ospf_opaque_type11_funclist
;
259 static void ospf_opaque_del_functab(void *val
)
261 XFREE(MTYPE_OSPF_OPAQUE_FUNCTAB
, val
);
265 static void ospf_opaque_funclist_init(void)
267 struct list
*funclist
;
269 funclist
= ospf_opaque_wildcard_funclist
= list_new();
270 funclist
->del
= ospf_opaque_del_functab
;
272 funclist
= ospf_opaque_type9_funclist
= list_new();
273 funclist
->del
= ospf_opaque_del_functab
;
275 funclist
= ospf_opaque_type10_funclist
= list_new();
276 funclist
->del
= ospf_opaque_del_functab
;
278 funclist
= ospf_opaque_type11_funclist
= list_new();
279 funclist
->del
= ospf_opaque_del_functab
;
283 static void ospf_opaque_funclist_term(void)
285 struct list
*funclist
;
287 funclist
= ospf_opaque_wildcard_funclist
;
288 list_delete_and_null(&funclist
);
290 funclist
= ospf_opaque_type9_funclist
;
291 list_delete_and_null(&funclist
);
293 funclist
= ospf_opaque_type10_funclist
;
294 list_delete_and_null(&funclist
);
296 funclist
= ospf_opaque_type11_funclist
;
297 list_delete_and_null(&funclist
);
301 static struct list
*ospf_get_opaque_funclist(u_char lsa_type
)
303 struct list
*funclist
= NULL
;
306 case OPAQUE_TYPE_WILDCARD
:
308 * This is an ugly trick to handle type-9/10/11 LSA altogether.
309 * Yes, "OPAQUE_TYPE_WILDCARD (value 0)" is not an LSA-type, nor
310 * an officially assigned opaque-type.
311 * Though it is possible that the value might be officially used
312 * in the future, we use it internally as a special label, for
315 funclist
= ospf_opaque_wildcard_funclist
;
317 case OSPF_OPAQUE_LINK_LSA
:
318 funclist
= ospf_opaque_type9_funclist
;
320 case OSPF_OPAQUE_AREA_LSA
:
321 funclist
= ospf_opaque_type10_funclist
;
323 case OSPF_OPAQUE_AS_LSA
:
324 funclist
= ospf_opaque_type11_funclist
;
327 zlog_warn("ospf_get_opaque_funclist: Unexpected LSA-type(%u)",
334 /* XXX: such a huge argument list can /not/ be healthy... */
335 int ospf_register_opaque_functab(
336 u_char lsa_type
, u_char opaque_type
,
337 int (*new_if_hook
)(struct interface
*ifp
),
338 int (*del_if_hook
)(struct interface
*ifp
),
339 void (*ism_change_hook
)(struct ospf_interface
*oi
, int old_status
),
340 void (*nsm_change_hook
)(struct ospf_neighbor
*nbr
, int old_status
),
341 void (*config_write_router
)(struct vty
*vty
),
342 void (*config_write_if
)(struct vty
*vty
, struct interface
*ifp
),
343 void (*config_write_debug
)(struct vty
*vty
),
344 void (*show_opaque_info
)(struct vty
*vty
, struct ospf_lsa
*lsa
),
345 int (*lsa_originator
)(void *arg
),
346 struct ospf_lsa
*(*lsa_refresher
)(struct ospf_lsa
*lsa
),
347 int (*new_lsa_hook
)(struct ospf_lsa
*lsa
),
348 int (*del_lsa_hook
)(struct ospf_lsa
*lsa
))
350 struct list
*funclist
;
351 struct ospf_opaque_functab
*new;
354 if ((funclist
= ospf_get_opaque_funclist(lsa_type
)) == NULL
) {
356 "ospf_register_opaque_functab: Cannot get funclist"
357 " for Type-%u LSAs?",
361 struct listnode
*node
, *nnode
;
362 struct ospf_opaque_functab
*functab
;
364 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
365 if (functab
->opaque_type
== opaque_type
) {
367 "ospf_register_opaque_functab: Duplicated entry?:"
368 " lsa_type(%u), opaque_type(%u)",
369 lsa_type
, opaque_type
);
374 if ((new = XCALLOC(MTYPE_OSPF_OPAQUE_FUNCTAB
,
375 sizeof(struct ospf_opaque_functab
)))
377 zlog_warn("ospf_register_opaque_functab: XMALLOC: %s",
378 safe_strerror(errno
));
382 new->opaque_type
= opaque_type
;
384 new->new_if_hook
= new_if_hook
;
385 new->del_if_hook
= del_if_hook
;
386 new->ism_change_hook
= ism_change_hook
;
387 new->nsm_change_hook
= nsm_change_hook
;
388 new->config_write_router
= config_write_router
;
389 new->config_write_if
= config_write_if
;
390 new->config_write_debug
= config_write_debug
;
391 new->show_opaque_info
= show_opaque_info
;
392 new->lsa_originator
= lsa_originator
;
393 new->lsa_refresher
= lsa_refresher
;
394 new->new_lsa_hook
= new_lsa_hook
;
395 new->del_lsa_hook
= del_lsa_hook
;
397 listnode_add(funclist
, new);
404 void ospf_delete_opaque_functab(u_char lsa_type
, u_char opaque_type
)
406 struct list
*funclist
;
407 struct listnode
*node
, *nnode
;
408 struct ospf_opaque_functab
*functab
;
410 if ((funclist
= ospf_get_opaque_funclist(lsa_type
)) != NULL
)
411 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
)) {
412 if (functab
->opaque_type
== opaque_type
) {
413 /* Cleanup internal control information, if it
415 if (functab
->oipt
!= NULL
)
416 free_opaque_info_per_type(
419 /* Dequeue listnode entry from the list. */
420 listnode_delete(funclist
, functab
);
422 /* Avoid misjudgement in the next lookup. */
423 if (listcount(funclist
) == 0)
424 funclist
->head
= funclist
->tail
= NULL
;
426 XFREE(MTYPE_OSPF_OPAQUE_FUNCTAB
, functab
);
434 static struct ospf_opaque_functab
*
435 ospf_opaque_functab_lookup(struct ospf_lsa
*lsa
)
437 struct list
*funclist
;
438 struct listnode
*node
;
439 struct ospf_opaque_functab
*functab
;
440 u_char key
= GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
));
442 if ((funclist
= ospf_get_opaque_funclist(lsa
->data
->type
)) != NULL
)
443 for (ALL_LIST_ELEMENTS_RO(funclist
, node
, functab
))
444 if (functab
->opaque_type
== key
)
450 /*------------------------------------------------------------------------*
451 * Followings are management functions for self-originated LSA entries.
452 *------------------------------------------------------------------------*/
455 * Opaque-LSA control information per opaque-type.
456 * Single Opaque-Type may have multiple instances; each of them will be
457 * identified by their opaque-id.
459 struct opaque_info_per_type
{
463 enum { PROC_NORMAL
, PROC_SUSPEND
} status
;
466 * Thread for (re-)origination scheduling for this opaque-type.
468 * Initial origination of Opaque-LSAs is controlled by generic
469 * Opaque-LSA handling module so that same opaque-type entries are
470 * called all at once when certain conditions are met.
471 * However, there might be cases that some Opaque-LSA clients need
472 * to (re-)originate their own Opaque-LSAs out-of-sync with others.
473 * This thread is prepared for that specific purpose.
475 struct thread
*t_opaque_lsa_self
;
478 * Backpointer to an "owner" which is LSA-type dependent.
479 * type-9: struct ospf_interface
480 * type-10: struct ospf_area
481 * type-11: struct ospf
485 /* Collection of callback functions for this opaque-type. */
486 struct ospf_opaque_functab
*functab
;
488 /* List of Opaque-LSA control informations per opaque-id. */
489 struct list
*id_list
;
492 /* Opaque-LSA control information per opaque-id. */
493 struct opaque_info_per_id
{
496 /* Thread for refresh/flush scheduling for this opaque-type/id. */
497 struct thread
*t_opaque_lsa_self
;
499 /* Backpointer to Opaque-LSA control information per opaque-type. */
500 struct opaque_info_per_type
*opqctl_type
;
502 /* Here comes an actual Opaque-LSA entry for this opaque-type/id. */
503 struct ospf_lsa
*lsa
;
506 static struct opaque_info_per_type
*
507 register_opaque_info_per_type(struct ospf_opaque_functab
*functab
,
508 struct ospf_lsa
*new);
509 static struct opaque_info_per_type
*
510 lookup_opaque_info_by_type(struct ospf_lsa
*lsa
);
511 static struct opaque_info_per_id
*
512 register_opaque_info_per_id(struct opaque_info_per_type
*oipt
,
513 struct ospf_lsa
*new);
514 static struct opaque_info_per_id
*
515 lookup_opaque_info_by_id(struct opaque_info_per_type
*oipt
,
516 struct ospf_lsa
*lsa
);
517 static struct opaque_info_per_id
*register_opaque_lsa(struct ospf_lsa
*new);
520 static struct opaque_info_per_type
*
521 register_opaque_info_per_type(struct ospf_opaque_functab
*functab
,
522 struct ospf_lsa
*new)
525 struct opaque_info_per_type
*oipt
;
527 if ((oipt
= XCALLOC(MTYPE_OPAQUE_INFO_PER_TYPE
,
528 sizeof(struct opaque_info_per_type
)))
530 zlog_warn("register_opaque_info_per_type: XMALLOC: %s",
531 safe_strerror(errno
));
535 switch (new->data
->type
) {
536 case OSPF_OPAQUE_LINK_LSA
:
537 oipt
->owner
= new->oi
;
538 listnode_add(new->oi
->opaque_lsa_self
, oipt
);
540 case OSPF_OPAQUE_AREA_LSA
:
541 oipt
->owner
= new->area
;
542 listnode_add(new->area
->opaque_lsa_self
, oipt
);
544 case OSPF_OPAQUE_AS_LSA
:
545 top
= ospf_lookup_by_vrf_id(new->vrf_id
);
546 if (new->area
!= NULL
&& (top
= new->area
->ospf
) == NULL
) {
547 free_opaque_info_per_type((void *)oipt
);
549 goto out
; /* This case may not exist. */
552 listnode_add(top
->opaque_lsa_self
, oipt
);
556 "register_opaque_info_per_type: Unexpected LSA-type(%u)",
558 free_opaque_info_per_type((void *)oipt
);
560 goto out
; /* This case may not exist. */
563 oipt
->lsa_type
= new->data
->type
;
564 oipt
->opaque_type
= GET_OPAQUE_TYPE(ntohl(new->data
->id
.s_addr
));
565 oipt
->status
= PROC_NORMAL
;
566 oipt
->t_opaque_lsa_self
= NULL
;
567 oipt
->functab
= functab
;
568 functab
->oipt
= oipt
;
569 oipt
->id_list
= list_new();
570 oipt
->id_list
->del
= free_opaque_info_per_id
;
576 static void free_opaque_info_per_type(void *val
)
578 struct opaque_info_per_type
*oipt
= (struct opaque_info_per_type
*)val
;
579 struct opaque_info_per_id
*oipi
;
580 struct ospf_lsa
*lsa
;
581 struct listnode
*node
, *nnode
;
583 /* Control information per opaque-id may still exist. */
584 for (ALL_LIST_ELEMENTS(oipt
->id_list
, node
, nnode
, oipi
)) {
585 if ((lsa
= oipi
->lsa
) == NULL
)
587 if (IS_LSA_MAXAGE(lsa
))
589 ospf_opaque_lsa_flush_schedule(lsa
);
592 /* Remove "oipt" from its owner's self-originated LSA list. */
593 switch (oipt
->lsa_type
) {
594 case OSPF_OPAQUE_LINK_LSA
: {
595 struct ospf_interface
*oi
=
596 (struct ospf_interface
*)(oipt
->owner
);
597 listnode_delete(oi
->opaque_lsa_self
, oipt
);
600 case OSPF_OPAQUE_AREA_LSA
: {
601 struct ospf_area
*area
= (struct ospf_area
*)(oipt
->owner
);
602 listnode_delete(area
->opaque_lsa_self
, oipt
);
605 case OSPF_OPAQUE_AS_LSA
: {
606 struct ospf
*top
= (struct ospf
*)(oipt
->owner
);
607 listnode_delete(top
->opaque_lsa_self
, oipt
);
611 zlog_warn("free_opaque_info_per_type: Unexpected LSA-type(%u)",
613 break; /* This case may not exist. */
616 OSPF_TIMER_OFF(oipt
->t_opaque_lsa_self
);
617 list_delete_and_null(&oipt
->id_list
);
618 XFREE(MTYPE_OPAQUE_INFO_PER_TYPE
, oipt
);
622 static struct opaque_info_per_type
*
623 lookup_opaque_info_by_type(struct ospf_lsa
*lsa
)
626 struct ospf_area
*area
;
627 struct ospf_interface
*oi
;
628 struct list
*listtop
= NULL
;
629 struct listnode
*node
, *nnode
;
630 struct opaque_info_per_type
*oipt
= NULL
;
631 u_char key
= GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
));
633 switch (lsa
->data
->type
) {
634 case OSPF_OPAQUE_LINK_LSA
:
635 if ((oi
= lsa
->oi
) != NULL
)
636 listtop
= oi
->opaque_lsa_self
;
639 "Type-9 Opaque-LSA: Reference to OI is missing?");
641 case OSPF_OPAQUE_AREA_LSA
:
642 if ((area
= lsa
->area
) != NULL
)
643 listtop
= area
->opaque_lsa_self
;
646 "Type-10 Opaque-LSA: Reference to AREA is missing?");
648 case OSPF_OPAQUE_AS_LSA
:
649 top
= ospf_lookup_by_vrf_id(lsa
->vrf_id
);
650 if ((area
= lsa
->area
) != NULL
&& (top
= area
->ospf
) == NULL
) {
652 "Type-11 Opaque-LSA: Reference to OSPF is missing?");
653 break; /* Unlikely to happen. */
655 listtop
= top
->opaque_lsa_self
;
658 zlog_warn("lookup_opaque_info_by_type: Unexpected LSA-type(%u)",
664 for (ALL_LIST_ELEMENTS(listtop
, node
, nnode
, oipt
))
665 if (oipt
->opaque_type
== key
)
671 static struct opaque_info_per_id
*
672 register_opaque_info_per_id(struct opaque_info_per_type
*oipt
,
673 struct ospf_lsa
*new)
675 struct opaque_info_per_id
*oipi
;
677 if ((oipi
= XCALLOC(MTYPE_OPAQUE_INFO_PER_ID
,
678 sizeof(struct opaque_info_per_id
)))
680 zlog_warn("register_opaque_info_per_id: XMALLOC: %s",
681 safe_strerror(errno
));
684 oipi
->opaque_id
= GET_OPAQUE_ID(ntohl(new->data
->id
.s_addr
));
685 oipi
->t_opaque_lsa_self
= NULL
;
686 oipi
->opqctl_type
= oipt
;
687 oipi
->lsa
= ospf_lsa_lock(new);
689 listnode_add(oipt
->id_list
, oipi
);
695 static void free_opaque_info_per_id(void *val
)
697 struct opaque_info_per_id
*oipi
= (struct opaque_info_per_id
*)val
;
699 OSPF_TIMER_OFF(oipi
->t_opaque_lsa_self
);
700 if (oipi
->lsa
!= NULL
)
701 ospf_lsa_unlock(&oipi
->lsa
);
702 XFREE(MTYPE_OPAQUE_INFO_PER_ID
, oipi
);
706 static struct opaque_info_per_id
*
707 lookup_opaque_info_by_id(struct opaque_info_per_type
*oipt
,
708 struct ospf_lsa
*lsa
)
710 struct listnode
*node
, *nnode
;
711 struct opaque_info_per_id
*oipi
;
712 u_int32_t key
= GET_OPAQUE_ID(ntohl(lsa
->data
->id
.s_addr
));
714 for (ALL_LIST_ELEMENTS(oipt
->id_list
, node
, nnode
, oipi
))
715 if (oipi
->opaque_id
== key
)
721 static struct opaque_info_per_id
*register_opaque_lsa(struct ospf_lsa
*new)
723 struct ospf_opaque_functab
*functab
;
724 struct opaque_info_per_type
*oipt
;
725 struct opaque_info_per_id
*oipi
= NULL
;
727 if ((functab
= ospf_opaque_functab_lookup(new)) == NULL
)
730 if ((oipt
= lookup_opaque_info_by_type(new)) == NULL
731 && (oipt
= register_opaque_info_per_type(functab
, new)) == NULL
)
734 if ((oipi
= register_opaque_info_per_id(oipt
, new)) == NULL
)
741 /*------------------------------------------------------------------------*
742 * Followings are (vty) configuration functions for Opaque-LSAs handling.
743 *------------------------------------------------------------------------*/
745 DEFUN (capability_opaque
,
746 capability_opaque_cmd
,
748 "Enable specific OSPF feature\n"
751 VTY_DECLVAR_INSTANCE_CONTEXT(ospf
, ospf
);
753 /* Turn on the "master switch" of opaque-lsa capability. */
754 if (!CHECK_FLAG(ospf
->config
, OSPF_OPAQUE_CAPABLE
)) {
755 if (IS_DEBUG_OSPF_EVENT
)
756 zlog_debug("Opaque capability: OFF -> ON");
758 SET_FLAG(ospf
->config
, OSPF_OPAQUE_CAPABLE
);
759 ospf_renegotiate_optional_capabilities(ospf
);
767 "OSPF specific commands\n"
768 "Enable the Opaque-LSA capability (rfc2370)\n")
770 return capability_opaque(self
, vty
, argc
, argv
);
773 DEFUN (no_capability_opaque
,
774 no_capability_opaque_cmd
,
775 "no capability opaque",
777 "Enable specific OSPF feature\n"
780 VTY_DECLVAR_INSTANCE_CONTEXT(ospf
, ospf
);
782 /* Turn off the "master switch" of opaque-lsa capability. */
783 if (CHECK_FLAG(ospf
->config
, OSPF_OPAQUE_CAPABLE
)) {
784 if (IS_DEBUG_OSPF_EVENT
)
785 zlog_debug("Opaque capability: ON -> OFF");
787 UNSET_FLAG(ospf
->config
, OSPF_OPAQUE_CAPABLE
);
788 ospf_renegotiate_optional_capabilities(ospf
);
793 DEFUN (no_ospf_opaque
,
795 "no ospf opaque-lsa",
797 "OSPF specific commands\n"
798 "Enable the Opaque-LSA capability (rfc2370)\n")
800 return no_capability_opaque(self
, vty
, argc
, argv
);
803 static void ospf_opaque_register_vty(void)
805 install_element(OSPF_NODE
, &capability_opaque_cmd
);
806 install_element(OSPF_NODE
, &no_capability_opaque_cmd
);
807 install_element(OSPF_NODE
, &ospf_opaque_cmd
);
808 install_element(OSPF_NODE
, &no_ospf_opaque_cmd
);
812 /*------------------------------------------------------------------------*
813 * Followings are collection of user-registered function callers.
814 *------------------------------------------------------------------------*/
816 static int opaque_lsa_new_if_callback(struct list
*funclist
,
817 struct interface
*ifp
)
819 struct listnode
*node
, *nnode
;
820 struct ospf_opaque_functab
*functab
;
823 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
824 if (functab
->new_if_hook
!= NULL
)
825 if ((*functab
->new_if_hook
)(ifp
) != 0)
832 static int opaque_lsa_del_if_callback(struct list
*funclist
,
833 struct interface
*ifp
)
835 struct listnode
*node
, *nnode
;
836 struct ospf_opaque_functab
*functab
;
839 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
840 if (functab
->del_if_hook
!= NULL
)
841 if ((*functab
->del_if_hook
)(ifp
) != 0)
848 static void opaque_lsa_ism_change_callback(struct list
*funclist
,
849 struct ospf_interface
*oi
,
852 struct listnode
*node
, *nnode
;
853 struct ospf_opaque_functab
*functab
;
855 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
856 if (functab
->ism_change_hook
!= NULL
)
857 (*functab
->ism_change_hook
)(oi
, old_status
);
862 static void opaque_lsa_nsm_change_callback(struct list
*funclist
,
863 struct ospf_neighbor
*nbr
,
866 struct listnode
*node
, *nnode
;
867 struct ospf_opaque_functab
*functab
;
869 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
870 if (functab
->nsm_change_hook
!= NULL
)
871 (*functab
->nsm_change_hook
)(nbr
, old_status
);
875 static void opaque_lsa_config_write_router_callback(struct list
*funclist
,
878 struct listnode
*node
, *nnode
;
879 struct ospf_opaque_functab
*functab
;
881 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
882 if (functab
->config_write_router
!= NULL
)
883 (*functab
->config_write_router
)(vty
);
887 static void opaque_lsa_config_write_if_callback(struct list
*funclist
,
889 struct interface
*ifp
)
891 struct listnode
*node
, *nnode
;
892 struct ospf_opaque_functab
*functab
;
894 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
895 if (functab
->config_write_if
!= NULL
)
896 (*functab
->config_write_if
)(vty
, ifp
);
900 static void opaque_lsa_config_write_debug_callback(struct list
*funclist
,
903 struct listnode
*node
, *nnode
;
904 struct ospf_opaque_functab
*functab
;
906 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
907 if (functab
->config_write_debug
!= NULL
)
908 (*functab
->config_write_debug
)(vty
);
912 static int opaque_lsa_originate_callback(struct list
*funclist
,
913 void *lsa_type_dependent
)
915 struct listnode
*node
, *nnode
;
916 struct ospf_opaque_functab
*functab
;
919 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
920 if (functab
->lsa_originator
!= NULL
)
921 if ((*functab
->lsa_originator
)(lsa_type_dependent
) != 0)
928 static int new_lsa_callback(struct list
*funclist
, struct ospf_lsa
*lsa
)
930 struct listnode
*node
, *nnode
;
931 struct ospf_opaque_functab
*functab
;
934 /* This function handles ALL types of LSAs, not only opaque ones. */
935 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
936 if (functab
->new_lsa_hook
!= NULL
)
937 if ((*functab
->new_lsa_hook
)(lsa
) != 0)
944 static int del_lsa_callback(struct list
*funclist
, struct ospf_lsa
*lsa
)
946 struct listnode
*node
, *nnode
;
947 struct ospf_opaque_functab
*functab
;
950 /* This function handles ALL types of LSAs, not only opaque ones. */
951 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
952 if (functab
->del_lsa_hook
!= NULL
)
953 if ((*functab
->del_lsa_hook
)(lsa
) != 0)
960 /*------------------------------------------------------------------------*
961 * Followings are glue functions to call Opaque-LSA specific processing.
962 *------------------------------------------------------------------------*/
964 int ospf_opaque_new_if(struct interface
*ifp
)
966 struct list
*funclist
;
969 funclist
= ospf_opaque_wildcard_funclist
;
970 if (opaque_lsa_new_if_callback(funclist
, ifp
) != 0)
973 funclist
= ospf_opaque_type9_funclist
;
974 if (opaque_lsa_new_if_callback(funclist
, ifp
) != 0)
977 funclist
= ospf_opaque_type10_funclist
;
978 if (opaque_lsa_new_if_callback(funclist
, ifp
) != 0)
981 funclist
= ospf_opaque_type11_funclist
;
982 if (opaque_lsa_new_if_callback(funclist
, ifp
) != 0)
990 int ospf_opaque_del_if(struct interface
*ifp
)
992 struct list
*funclist
;
995 funclist
= ospf_opaque_wildcard_funclist
;
996 if (opaque_lsa_del_if_callback(funclist
, ifp
) != 0)
999 funclist
= ospf_opaque_type9_funclist
;
1000 if (opaque_lsa_del_if_callback(funclist
, ifp
) != 0)
1003 funclist
= ospf_opaque_type10_funclist
;
1004 if (opaque_lsa_del_if_callback(funclist
, ifp
) != 0)
1007 funclist
= ospf_opaque_type11_funclist
;
1008 if (opaque_lsa_del_if_callback(funclist
, ifp
) != 0)
1016 void ospf_opaque_ism_change(struct ospf_interface
*oi
, int old_status
)
1018 struct list
*funclist
;
1020 funclist
= ospf_opaque_wildcard_funclist
;
1021 opaque_lsa_ism_change_callback(funclist
, oi
, old_status
);
1023 funclist
= ospf_opaque_type9_funclist
;
1024 opaque_lsa_ism_change_callback(funclist
, oi
, old_status
);
1026 funclist
= ospf_opaque_type10_funclist
;
1027 opaque_lsa_ism_change_callback(funclist
, oi
, old_status
);
1029 funclist
= ospf_opaque_type11_funclist
;
1030 opaque_lsa_ism_change_callback(funclist
, oi
, old_status
);
1035 void ospf_opaque_nsm_change(struct ospf_neighbor
*nbr
, int old_state
)
1038 struct list
*funclist
;
1040 if ((top
= oi_to_top(nbr
->oi
)) == NULL
)
1043 if (old_state
!= NSM_Full
&& nbr
->state
== NSM_Full
) {
1044 if (CHECK_FLAG(nbr
->options
, OSPF_OPTION_O
)) {
1045 if (!CHECK_FLAG(top
->opaque
,
1046 OPAQUE_OPERATION_READY_BIT
)) {
1047 if (IS_DEBUG_OSPF_EVENT
)
1049 "Opaque-LSA: Now get operational!");
1051 SET_FLAG(top
->opaque
,
1052 OPAQUE_OPERATION_READY_BIT
);
1055 ospf_opaque_lsa_originate_schedule(nbr
->oi
, NULL
);
1057 } else if (old_state
== NSM_Full
&& nbr
->state
!= NSM_Full
) {
1060 * If no more opaque-capable full-state neighbor remains in the
1061 * flooding scope which corresponds to Opaque-LSA type, periodic
1062 * LS flooding should be stopped.
1068 funclist
= ospf_opaque_wildcard_funclist
;
1069 opaque_lsa_nsm_change_callback(funclist
, nbr
, old_state
);
1071 funclist
= ospf_opaque_type9_funclist
;
1072 opaque_lsa_nsm_change_callback(funclist
, nbr
, old_state
);
1074 funclist
= ospf_opaque_type10_funclist
;
1075 opaque_lsa_nsm_change_callback(funclist
, nbr
, old_state
);
1077 funclist
= ospf_opaque_type11_funclist
;
1078 opaque_lsa_nsm_change_callback(funclist
, nbr
, old_state
);
1084 void ospf_opaque_config_write_router(struct vty
*vty
, struct ospf
*ospf
)
1086 struct list
*funclist
;
1088 if (CHECK_FLAG(ospf
->config
, OSPF_OPAQUE_CAPABLE
))
1089 vty_out(vty
, " capability opaque\n");
1091 funclist
= ospf_opaque_wildcard_funclist
;
1092 opaque_lsa_config_write_router_callback(funclist
, vty
);
1094 funclist
= ospf_opaque_type9_funclist
;
1095 opaque_lsa_config_write_router_callback(funclist
, vty
);
1097 funclist
= ospf_opaque_type10_funclist
;
1098 opaque_lsa_config_write_router_callback(funclist
, vty
);
1100 funclist
= ospf_opaque_type11_funclist
;
1101 opaque_lsa_config_write_router_callback(funclist
, vty
);
1106 void ospf_opaque_config_write_if(struct vty
*vty
, struct interface
*ifp
)
1108 struct list
*funclist
;
1110 funclist
= ospf_opaque_wildcard_funclist
;
1111 opaque_lsa_config_write_if_callback(funclist
, vty
, ifp
);
1113 funclist
= ospf_opaque_type9_funclist
;
1114 opaque_lsa_config_write_if_callback(funclist
, vty
, ifp
);
1116 funclist
= ospf_opaque_type10_funclist
;
1117 opaque_lsa_config_write_if_callback(funclist
, vty
, ifp
);
1119 funclist
= ospf_opaque_type11_funclist
;
1120 opaque_lsa_config_write_if_callback(funclist
, vty
, ifp
);
1125 void ospf_opaque_config_write_debug(struct vty
*vty
)
1127 struct list
*funclist
;
1129 funclist
= ospf_opaque_wildcard_funclist
;
1130 opaque_lsa_config_write_debug_callback(funclist
, vty
);
1132 funclist
= ospf_opaque_type9_funclist
;
1133 opaque_lsa_config_write_debug_callback(funclist
, vty
);
1135 funclist
= ospf_opaque_type10_funclist
;
1136 opaque_lsa_config_write_debug_callback(funclist
, vty
);
1138 funclist
= ospf_opaque_type11_funclist
;
1139 opaque_lsa_config_write_debug_callback(funclist
, vty
);
1144 void show_opaque_info_detail(struct vty
*vty
, struct ospf_lsa
*lsa
)
1146 struct lsa_header
*lsah
= (struct lsa_header
*)lsa
->data
;
1147 u_int32_t lsid
= ntohl(lsah
->id
.s_addr
);
1148 u_char opaque_type
= GET_OPAQUE_TYPE(lsid
);
1149 u_int32_t opaque_id
= GET_OPAQUE_ID(lsid
);
1150 struct ospf_opaque_functab
*functab
;
1152 /* Switch output functionality by vty address. */
1154 vty_out(vty
, " Opaque-Type %u (%s)\n", opaque_type
,
1155 ospf_opaque_type_name(opaque_type
));
1156 vty_out(vty
, " Opaque-ID 0x%x\n", opaque_id
);
1158 vty_out(vty
, " Opaque-Info: %u octets of data%s\n",
1159 ntohs(lsah
->length
) - OSPF_LSA_HEADER_SIZE
,
1160 VALID_OPAQUE_INFO_LEN(lsah
) ? "" : "(Invalid length?)");
1162 zlog_debug(" Opaque-Type %u (%s)", opaque_type
,
1163 ospf_opaque_type_name(opaque_type
));
1164 zlog_debug(" Opaque-ID 0x%x", opaque_id
);
1166 zlog_debug(" Opaque-Info: %u octets of data%s",
1167 ntohs(lsah
->length
) - OSPF_LSA_HEADER_SIZE
,
1168 VALID_OPAQUE_INFO_LEN(lsah
) ? ""
1169 : "(Invalid length?)");
1172 /* Call individual output functions. */
1173 if ((functab
= ospf_opaque_functab_lookup(lsa
)) != NULL
)
1174 if (functab
->show_opaque_info
!= NULL
)
1175 (*functab
->show_opaque_info
)(vty
, lsa
);
1180 void ospf_opaque_lsa_dump(struct stream
*s
, u_int16_t length
)
1182 struct ospf_lsa lsa
;
1184 lsa
.data
= (struct lsa_header
*)STREAM_PNT(s
);
1185 show_opaque_info_detail(NULL
, &lsa
);
1189 static int ospf_opaque_lsa_install_hook(struct ospf_lsa
*lsa
)
1191 struct list
*funclist
;
1195 * Some Opaque-LSA user may want to monitor every LSA installation
1196 * into the LSDB, regardless with target LSA type.
1198 funclist
= ospf_opaque_wildcard_funclist
;
1199 if (new_lsa_callback(funclist
, lsa
) != 0)
1202 funclist
= ospf_opaque_type9_funclist
;
1203 if (new_lsa_callback(funclist
, lsa
) != 0)
1206 funclist
= ospf_opaque_type10_funclist
;
1207 if (new_lsa_callback(funclist
, lsa
) != 0)
1210 funclist
= ospf_opaque_type11_funclist
;
1211 if (new_lsa_callback(funclist
, lsa
) != 0)
1219 static int ospf_opaque_lsa_delete_hook(struct ospf_lsa
*lsa
)
1221 struct list
*funclist
;
1225 * Some Opaque-LSA user may want to monitor every LSA deletion
1226 * from the LSDB, regardless with target LSA type.
1228 funclist
= ospf_opaque_wildcard_funclist
;
1229 if (del_lsa_callback(funclist
, lsa
) != 0)
1232 funclist
= ospf_opaque_type9_funclist
;
1233 if (del_lsa_callback(funclist
, lsa
) != 0)
1236 funclist
= ospf_opaque_type10_funclist
;
1237 if (del_lsa_callback(funclist
, lsa
) != 0)
1240 funclist
= ospf_opaque_type11_funclist
;
1241 if (del_lsa_callback(funclist
, lsa
) != 0)
1249 /*------------------------------------------------------------------------*
1250 * Followings are Opaque-LSA origination/refresh management functions.
1251 *------------------------------------------------------------------------*/
1253 static int ospf_opaque_type9_lsa_originate(struct thread
*t
);
1254 static int ospf_opaque_type10_lsa_originate(struct thread
*t
);
1255 static int ospf_opaque_type11_lsa_originate(struct thread
*t
);
1256 static void ospf_opaque_lsa_reoriginate_resume(struct list
*listtop
, void *arg
);
1258 void ospf_opaque_lsa_originate_schedule(struct ospf_interface
*oi
, int *delay0
)
1261 struct ospf_area
*area
;
1262 struct listnode
*node
, *nnode
;
1263 struct opaque_info_per_type
*oipt
;
1266 if ((top
= oi_to_top(oi
)) == NULL
|| (area
= oi
->area
) == NULL
) {
1268 "ospf_opaque_lsa_originate_schedule: Invalid argument?");
1272 /* It may not a right time to schedule origination now. */
1273 if (!CHECK_FLAG(top
->opaque
, OPAQUE_OPERATION_READY_BIT
)) {
1274 if (IS_DEBUG_OSPF_EVENT
)
1276 "ospf_opaque_lsa_originate_schedule: Not operational.");
1277 goto out
; /* This is not an error. */
1284 * There might be some entries that have been waiting for triggering
1285 * of per opaque-type re-origination get resumed.
1287 ospf_opaque_lsa_reoriginate_resume(oi
->opaque_lsa_self
, (void *)oi
);
1288 ospf_opaque_lsa_reoriginate_resume(area
->opaque_lsa_self
, (void *)area
);
1289 ospf_opaque_lsa_reoriginate_resume(top
->opaque_lsa_self
, (void *)top
);
1292 * Now, schedule origination of all Opaque-LSAs per opaque-type.
1294 if (!list_isempty(ospf_opaque_type9_funclist
)
1295 && list_isempty(oi
->opaque_lsa_self
)
1296 && oi
->t_opaque_lsa_self
== NULL
) {
1297 if (IS_DEBUG_OSPF_EVENT
)
1299 "Schedule Type-9 Opaque-LSA origination in %d ms later.",
1301 oi
->t_opaque_lsa_self
= NULL
;
1302 thread_add_timer_msec(master
, ospf_opaque_type9_lsa_originate
,
1303 oi
, delay
, &oi
->t_opaque_lsa_self
);
1304 delay
+= top
->min_ls_interval
;
1307 if (!list_isempty(ospf_opaque_type10_funclist
)
1308 && list_isempty(area
->opaque_lsa_self
)
1309 && area
->t_opaque_lsa_self
== NULL
) {
1311 * One AREA may contain multiple OIs, but above 2nd and 3rd
1312 * conditions prevent from scheduling the originate function
1315 if (IS_DEBUG_OSPF_EVENT
)
1317 "Schedule Type-10 Opaque-LSA origination in %d ms later.",
1319 area
->t_opaque_lsa_self
= NULL
;
1320 thread_add_timer_msec(master
, ospf_opaque_type10_lsa_originate
,
1321 area
, delay
, &area
->t_opaque_lsa_self
);
1322 delay
+= top
->min_ls_interval
;
1325 if (!list_isempty(ospf_opaque_type11_funclist
)
1326 && list_isempty(top
->opaque_lsa_self
)
1327 && top
->t_opaque_lsa_self
== NULL
) {
1329 * One OSPF may contain multiple AREAs, but above 2nd and 3rd
1330 * conditions prevent from scheduling the originate function
1333 if (IS_DEBUG_OSPF_EVENT
)
1335 "Schedule Type-11 Opaque-LSA origination in %d ms later.",
1337 top
->t_opaque_lsa_self
= NULL
;
1338 thread_add_timer_msec(master
, ospf_opaque_type11_lsa_originate
,
1339 top
, delay
, &top
->t_opaque_lsa_self
);
1340 delay
+= top
->min_ls_interval
;
1344 * Following section treats a special situation that this node's
1345 * opaque capability has changed as "ON -> OFF -> ON".
1347 if (!list_isempty(ospf_opaque_type9_funclist
)
1348 && !list_isempty(oi
->opaque_lsa_self
)) {
1349 for (ALL_LIST_ELEMENTS(oi
->opaque_lsa_self
, node
, nnode
,
1352 * removed the test for
1353 * (! list_isempty (oipt->id_list)) * Handler is
1355 * because opaque cababilities ON -> OFF -> ON result in
1356 * list_isempty (oipt->id_list)
1360 oipt
->t_opaque_lsa_self
1361 != NULL
/* Waiting for a thread call. */
1362 || oipt
->status
== PROC_SUSPEND
) /* Cannot
1367 ospf_opaque_lsa_reoriginate_schedule(
1368 (void *)oi
, OSPF_OPAQUE_LINK_LSA
,
1373 if (!list_isempty(ospf_opaque_type10_funclist
)
1374 && !list_isempty(area
->opaque_lsa_self
)) {
1375 for (ALL_LIST_ELEMENTS(area
->opaque_lsa_self
, node
, nnode
,
1378 * removed the test for
1379 * (! list_isempty (oipt->id_list)) * Handler is
1381 * because opaque cababilities ON -> OFF -> ON result in
1382 * list_isempty (oipt->id_list)
1386 oipt
->t_opaque_lsa_self
1387 != NULL
/* Waiting for a thread call. */
1388 || oipt
->status
== PROC_SUSPEND
) /* Cannot
1393 ospf_opaque_lsa_reoriginate_schedule(
1394 (void *)area
, OSPF_OPAQUE_AREA_LSA
,
1399 if (!list_isempty(ospf_opaque_type11_funclist
)
1400 && !list_isempty(top
->opaque_lsa_self
)) {
1401 for (ALL_LIST_ELEMENTS(top
->opaque_lsa_self
, node
, nnode
,
1404 * removed the test for
1405 * (! list_isempty (oipt->id_list)) * Handler is
1407 * because opaque cababilities ON -> OFF -> ON result in
1408 * list_isempty (oipt->id_list)
1412 oipt
->t_opaque_lsa_self
1413 != NULL
/* Waiting for a thread call. */
1414 || oipt
->status
== PROC_SUSPEND
) /* Cannot
1419 ospf_opaque_lsa_reoriginate_schedule((void *)top
,
1432 static int ospf_opaque_type9_lsa_originate(struct thread
*t
)
1434 struct ospf_interface
*oi
;
1438 oi
->t_opaque_lsa_self
= NULL
;
1440 if (IS_DEBUG_OSPF_EVENT
)
1441 zlog_debug("Timer[Type9-LSA]: Originate Opaque-LSAs for OI %s",
1444 rc
= opaque_lsa_originate_callback(ospf_opaque_type9_funclist
, oi
);
1449 static int ospf_opaque_type10_lsa_originate(struct thread
*t
)
1451 struct ospf_area
*area
;
1454 area
= THREAD_ARG(t
);
1455 area
->t_opaque_lsa_self
= NULL
;
1457 if (IS_DEBUG_OSPF_EVENT
)
1459 "Timer[Type10-LSA]: Originate Opaque-LSAs for Area %s",
1460 inet_ntoa(area
->area_id
));
1462 rc
= opaque_lsa_originate_callback(ospf_opaque_type10_funclist
, area
);
1467 static int ospf_opaque_type11_lsa_originate(struct thread
*t
)
1472 top
= THREAD_ARG(t
);
1473 top
->t_opaque_lsa_self
= NULL
;
1475 if (IS_DEBUG_OSPF_EVENT
)
1477 "Timer[Type11-LSA]: Originate AS-External Opaque-LSAs");
1479 rc
= opaque_lsa_originate_callback(ospf_opaque_type11_funclist
, top
);
1484 static void ospf_opaque_lsa_reoriginate_resume(struct list
*listtop
, void *arg
)
1486 struct listnode
*node
, *nnode
;
1487 struct opaque_info_per_type
*oipt
;
1488 struct ospf_opaque_functab
*functab
;
1490 if (listtop
== NULL
)
1494 * Pickup oipt entries those which in SUSPEND status, and give
1495 * them a chance to start re-origination now.
1497 for (ALL_LIST_ELEMENTS(listtop
, node
, nnode
, oipt
)) {
1498 if (oipt
->status
!= PROC_SUSPEND
)
1501 oipt
->status
= PROC_NORMAL
;
1503 if ((functab
= oipt
->functab
) == NULL
1504 || functab
->lsa_originator
== NULL
)
1507 if ((*functab
->lsa_originator
)(arg
) != 0) {
1509 "ospf_opaque_lsa_reoriginate_resume: Failed (opaque-type=%u)",
1519 struct ospf_lsa
*ospf_opaque_lsa_install(struct ospf_lsa
*lsa
, int rt_recalc
)
1521 struct ospf_lsa
*new = NULL
;
1522 struct opaque_info_per_type
*oipt
;
1523 struct opaque_info_per_id
*oipi
;
1526 /* Don't take "rt_recalc" into consideration for now. */ /* XXX */
1528 if (!IS_LSA_SELF(lsa
)) {
1529 new = lsa
; /* Don't touch this LSA. */
1533 if (IS_DEBUG_OSPF(lsa
, LSA_INSTALL
))
1535 "Install Type-%u Opaque-LSA: [opaque-type=%u, opaque-id=%x]",
1537 GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
)),
1538 GET_OPAQUE_ID(ntohl(lsa
->data
->id
.s_addr
)));
1540 /* Replace the existing lsa with the new one. */
1541 if ((oipt
= lookup_opaque_info_by_type(lsa
)) != NULL
1542 && (oipi
= lookup_opaque_info_by_id(oipt
, lsa
)) != NULL
) {
1543 ospf_lsa_unlock(&oipi
->lsa
);
1544 oipi
->lsa
= ospf_lsa_lock(lsa
);
1546 /* Register the new lsa entry and get its control info. */
1547 else if ((oipi
= register_opaque_lsa(lsa
)) == NULL
) {
1548 zlog_warn("ospf_opaque_lsa_install: register_opaque_lsa() ?");
1553 * Make use of a common mechanism (ospf_lsa_refresh_walker)
1554 * for periodic refresh of self-originated Opaque-LSAs.
1556 switch (lsa
->data
->type
) {
1557 case OSPF_OPAQUE_LINK_LSA
:
1558 if ((top
= oi_to_top(lsa
->oi
)) == NULL
) {
1559 /* Above conditions must have passed. */
1560 zlog_warn("ospf_opaque_lsa_install: Sonmething wrong?");
1564 case OSPF_OPAQUE_AREA_LSA
:
1565 if (lsa
->area
== NULL
|| (top
= lsa
->area
->ospf
) == NULL
) {
1566 /* Above conditions must have passed. */
1567 zlog_warn("ospf_opaque_lsa_install: Sonmething wrong?");
1571 case OSPF_OPAQUE_AS_LSA
:
1572 top
= ospf_lookup_by_vrf_id(lsa
->vrf_id
);
1573 if (lsa
->area
!= NULL
&& (top
= lsa
->area
->ospf
) == NULL
) {
1574 /* Above conditions must have passed. */
1575 zlog_warn("ospf_opaque_lsa_install: Sonmething wrong?");
1580 zlog_warn("ospf_opaque_lsa_install: Unexpected LSA-type(%u)",
1585 ospf_refresher_register_lsa(top
, lsa
);
1592 struct ospf_lsa
*ospf_opaque_lsa_refresh(struct ospf_lsa
*lsa
)
1595 struct ospf_opaque_functab
*functab
;
1596 struct ospf_lsa
*new = NULL
;
1598 ospf
= ospf_lookup_by_vrf_id(lsa
->vrf_id
);
1600 if ((functab
= ospf_opaque_functab_lookup(lsa
)) == NULL
1601 || functab
->lsa_refresher
== NULL
) {
1603 * Though this LSA seems to have originated on this node, the
1604 * handling module for this "lsa-type and opaque-type" was
1605 * already deleted sometime ago.
1606 * Anyway, this node still has a responsibility to flush this
1607 * LSA from the routing domain.
1609 if (IS_DEBUG_OSPF_EVENT
)
1610 zlog_debug("LSA[Type%d:%s]: Flush stray Opaque-LSA",
1611 lsa
->data
->type
, inet_ntoa(lsa
->data
->id
));
1613 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
1614 ospf_lsa_flush(ospf
, lsa
);
1616 new = (*functab
->lsa_refresher
)(lsa
);
1621 /*------------------------------------------------------------------------*
1622 * Followings are re-origination/refresh/flush operations of Opaque-LSAs,
1623 * triggered by external interventions (vty session, signaling, etc).
1624 *------------------------------------------------------------------------*/
1626 #define OSPF_OPAQUE_TIMER_ON(T,F,L,V) thread_add_timer_msec (master, (F), (L), (V), &(T))
1628 static struct ospf_lsa
*pseudo_lsa(struct ospf_interface
*oi
,
1629 struct ospf_area
*area
, u_char lsa_type
,
1630 u_char opaque_type
);
1631 static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread
*t
);
1632 static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread
*t
);
1633 static int ospf_opaque_type11_lsa_reoriginate_timer(struct thread
*t
);
1634 static int ospf_opaque_lsa_refresh_timer(struct thread
*t
);
1636 void ospf_opaque_lsa_reoriginate_schedule(void *lsa_type_dependent
,
1637 u_char lsa_type
, u_char opaque_type
)
1639 struct ospf
*top
= NULL
;
1640 struct ospf_area dummy
, *area
= NULL
;
1641 struct ospf_interface
*oi
= NULL
;
1643 struct ospf_lsa
*lsa
;
1644 struct opaque_info_per_type
*oipt
;
1645 int (*func
)(struct thread
* t
) = NULL
;
1649 case OSPF_OPAQUE_LINK_LSA
:
1650 if ((oi
= (struct ospf_interface
*)lsa_type_dependent
)
1653 "ospf_opaque_lsa_reoriginate_schedule:"
1654 " Type-9 Opaque-LSA: Invalid parameter?");
1657 if ((top
= oi_to_top(oi
)) == NULL
) {
1659 "ospf_opaque_lsa_reoriginate_schedule: OI(%s) -> TOP?",
1663 if (!list_isempty(ospf_opaque_type9_funclist
)
1664 && list_isempty(oi
->opaque_lsa_self
)
1665 && oi
->t_opaque_lsa_self
!= NULL
) {
1667 "Type-9 Opaque-LSA (opaque_type=%u):"
1668 " Common origination for OI(%s) has already started",
1669 opaque_type
, IF_NAME(oi
));
1672 func
= ospf_opaque_type9_lsa_reoriginate_timer
;
1674 case OSPF_OPAQUE_AREA_LSA
:
1675 if ((area
= (struct ospf_area
*)lsa_type_dependent
) == NULL
) {
1677 "ospf_opaque_lsa_reoriginate_schedule:"
1678 " Type-10 Opaque-LSA: Invalid parameter?");
1681 if ((top
= area
->ospf
) == NULL
) {
1683 "ospf_opaque_lsa_reoriginate_schedule:"
1684 " AREA(%s) -> TOP?",
1685 inet_ntoa(area
->area_id
));
1688 if (!list_isempty(ospf_opaque_type10_funclist
)
1689 && list_isempty(area
->opaque_lsa_self
)
1690 && area
->t_opaque_lsa_self
!= NULL
) {
1692 "Type-10 Opaque-LSA (opaque_type=%u):"
1693 " Common origination for AREA(%s) has already started",
1694 opaque_type
, inet_ntoa(area
->area_id
));
1697 func
= ospf_opaque_type10_lsa_reoriginate_timer
;
1699 case OSPF_OPAQUE_AS_LSA
:
1700 if ((top
= (struct ospf
*)lsa_type_dependent
) == NULL
) {
1702 "ospf_opaque_lsa_reoriginate_schedule:"
1703 " Type-11 Opaque-LSA: Invalid parameter?");
1706 if (!list_isempty(ospf_opaque_type11_funclist
)
1707 && list_isempty(top
->opaque_lsa_self
)
1708 && top
->t_opaque_lsa_self
!= NULL
) {
1710 "Type-11 Opaque-LSA (opaque_type=%u):"
1711 " Common origination has already started",
1716 /* Fake "area" to pass "ospf" to a lookup function later. */
1720 func
= ospf_opaque_type11_lsa_reoriginate_timer
;
1724 "ospf_opaque_lsa_reoriginate_schedule:"
1725 " Unexpected LSA-type(%u)",
1730 /* It may not a right time to schedule reorigination now. */
1731 if (!CHECK_FLAG(top
->opaque
, OPAQUE_OPERATION_READY_BIT
)) {
1732 if (IS_DEBUG_OSPF_EVENT
)
1734 "ospf_opaque_lsa_reoriginate_schedule: Not operational.");
1735 goto out
; /* This is not an error. */
1738 /* Generate a dummy lsa to be passed for a lookup function. */
1739 lsa
= pseudo_lsa(oi
, area
, lsa_type
, opaque_type
);
1740 lsa
->vrf_id
= top
->vrf_id
;
1742 if ((oipt
= lookup_opaque_info_by_type(lsa
)) == NULL
) {
1743 struct ospf_opaque_functab
*functab
;
1744 if ((functab
= ospf_opaque_functab_lookup(lsa
)) == NULL
) {
1746 "ospf_opaque_lsa_reoriginate_schedule:"
1747 " No associated function?: lsa_type(%u),"
1749 lsa_type
, opaque_type
);
1752 if ((oipt
= register_opaque_info_per_type(functab
, lsa
))
1755 "ospf_opaque_lsa_reoriginate_schedule:"
1756 " Cannot get a control info?: lsa_type(%u),"
1758 lsa_type
, opaque_type
);
1763 if (oipt
->t_opaque_lsa_self
!= NULL
) {
1764 if (IS_DEBUG_OSPF_EVENT
)
1766 "Type-%u Opaque-LSA has already scheduled to"
1767 " RE-ORIGINATE: [opaque-type=%u]",
1769 GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
)));
1774 * Different from initial origination time, in which various conditions
1775 * (opaque capability, neighbor status etc) are assured by caller of
1776 * the originating function "ospf_opaque_lsa_originate_schedule ()",
1777 * it is highly possible that these conditions might not be satisfied
1778 * at the time of re-origination function is to be called.
1780 delay
= top
->min_ls_interval
; /* XXX */
1782 if (IS_DEBUG_OSPF_EVENT
)
1784 "Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d"
1785 " ms later: [opaque-type=%u]",
1787 GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
)));
1789 OSPF_OPAQUE_TIMER_ON(oipt
->t_opaque_lsa_self
, func
, oipt
, delay
* 1000);
1795 static struct ospf_lsa
*pseudo_lsa(struct ospf_interface
*oi
,
1796 struct ospf_area
*area
, u_char lsa_type
,
1799 static struct ospf_lsa lsa
= {0};
1800 static struct lsa_header lsah
= {0};
1806 lsa
.vrf_id
= VRF_DEFAULT
;
1808 lsah
.type
= lsa_type
;
1809 tmp
= SET_OPAQUE_LSID(opaque_type
, 0); /* Opaque-ID is unused here. */
1810 lsah
.id
.s_addr
= htonl(tmp
);
1815 static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread
*t
)
1817 struct opaque_info_per_type
*oipt
;
1818 struct ospf_opaque_functab
*functab
;
1820 struct ospf_interface
*oi
;
1823 oipt
= THREAD_ARG(t
);
1824 oipt
->t_opaque_lsa_self
= NULL
;
1826 if ((functab
= oipt
->functab
) == NULL
1827 || functab
->lsa_originator
== NULL
) {
1829 "ospf_opaque_type9_lsa_reoriginate_timer: No associated function?");
1833 oi
= (struct ospf_interface
*)oipt
->owner
;
1834 if ((top
= oi_to_top(oi
)) == NULL
) {
1836 "ospf_opaque_type9_lsa_reoriginate_timer: Something wrong?");
1840 if (!CHECK_FLAG(top
->config
, OSPF_OPAQUE_CAPABLE
)
1841 || !ospf_if_is_enable(oi
)
1842 || ospf_nbr_count_opaque_capable(oi
) == 0) {
1843 if (IS_DEBUG_OSPF_EVENT
)
1845 "Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...",
1848 oipt
->status
= PROC_SUSPEND
;
1853 if (IS_DEBUG_OSPF_EVENT
)
1855 "Timer[Type9-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for OI (%s)",
1856 oipt
->opaque_type
, IF_NAME(oi
));
1858 rc
= (*functab
->lsa_originator
)(oi
);
1863 static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread
*t
)
1865 struct opaque_info_per_type
*oipt
;
1866 struct ospf_opaque_functab
*functab
;
1867 struct listnode
*node
, *nnode
;
1869 struct ospf_area
*area
;
1870 struct ospf_interface
*oi
;
1873 oipt
= THREAD_ARG(t
);
1874 oipt
->t_opaque_lsa_self
= NULL
;
1876 if ((functab
= oipt
->functab
) == NULL
1877 || functab
->lsa_originator
== NULL
) {
1879 "ospf_opaque_type10_lsa_reoriginate_timer: No associated function?");
1883 area
= (struct ospf_area
*)oipt
->owner
;
1884 if (area
== NULL
|| (top
= area
->ospf
) == NULL
) {
1886 "ospf_opaque_type10_lsa_reoriginate_timer: Something wrong?");
1890 /* There must be at least one "opaque-capable, full-state" neighbor. */
1892 for (ALL_LIST_ELEMENTS(area
->oiflist
, node
, nnode
, oi
)) {
1893 if ((n
= ospf_nbr_count_opaque_capable(oi
)) > 0)
1897 if (n
== 0 || !CHECK_FLAG(top
->config
, OSPF_OPAQUE_CAPABLE
)) {
1898 if (IS_DEBUG_OSPF_EVENT
)
1900 "Suspend re-origination of Type-10 Opaque-LSAs"
1901 " (opaque-type=%u) for a while...",
1904 oipt
->status
= PROC_SUSPEND
;
1909 if (IS_DEBUG_OSPF_EVENT
)
1911 "Timer[Type10-LSA]: Re-originate Opaque-LSAs"
1912 " (opaque-type=%u) for Area %s",
1913 oipt
->opaque_type
, inet_ntoa(area
->area_id
));
1915 rc
= (*functab
->lsa_originator
)(area
);
1920 static int ospf_opaque_type11_lsa_reoriginate_timer(struct thread
*t
)
1922 struct opaque_info_per_type
*oipt
;
1923 struct ospf_opaque_functab
*functab
;
1927 oipt
= THREAD_ARG(t
);
1928 oipt
->t_opaque_lsa_self
= NULL
;
1930 if ((functab
= oipt
->functab
) == NULL
1931 || functab
->lsa_originator
== NULL
) {
1933 "ospf_opaque_type11_lsa_reoriginate_timer:"
1934 " No associated function?");
1938 if ((top
= (struct ospf
*)oipt
->owner
) == NULL
) {
1940 "ospf_opaque_type11_lsa_reoriginate_timer: Something wrong?");
1944 if (!CHECK_FLAG(top
->config
, OSPF_OPAQUE_CAPABLE
)) {
1945 if (IS_DEBUG_OSPF_EVENT
)
1947 "Suspend re-origination of Type-11 Opaque-LSAs (opaque-type=%u) for a while...",
1950 oipt
->status
= PROC_SUSPEND
;
1955 if (IS_DEBUG_OSPF_EVENT
)
1957 "Timer[Type11-LSA]: Re-originate Opaque-LSAs (opaque-type=%u).",
1960 rc
= (*functab
->lsa_originator
)(top
);
1965 void ospf_opaque_lsa_refresh_schedule(struct ospf_lsa
*lsa0
)
1967 struct opaque_info_per_type
*oipt
;
1968 struct opaque_info_per_id
*oipi
;
1969 struct ospf_lsa
*lsa
;
1973 if ((oipt
= lookup_opaque_info_by_type(lsa0
)) == NULL
1974 || (oipi
= lookup_opaque_info_by_id(oipt
, lsa0
)) == NULL
) {
1976 "ospf_opaque_lsa_refresh_schedule: Invalid parameter?");
1980 /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
1981 if ((lsa
= oipi
->lsa
) == NULL
) {
1982 zlog_warn("ospf_opaque_lsa_refresh_schedule: Something wrong?");
1986 if (oipi
->t_opaque_lsa_self
!= NULL
) {
1987 if (IS_DEBUG_OSPF_EVENT
)
1989 "Type-%u Opaque-LSA has already scheduled to REFRESH: [opaque-type=%u, opaque-id=%x]",
1991 GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
)),
1992 GET_OPAQUE_ID(ntohl(lsa
->data
->id
.s_addr
)));
1996 /* Delete this lsa from neighbor retransmit-list. */
1997 switch (lsa
->data
->type
) {
1998 case OSPF_OPAQUE_LINK_LSA
:
1999 case OSPF_OPAQUE_AREA_LSA
:
2000 ospf_ls_retransmit_delete_nbr_area(lsa
->area
, lsa
);
2002 case OSPF_OPAQUE_AS_LSA
:
2003 top
= ospf_lookup_by_vrf_id(lsa0
->vrf_id
);
2004 if ((lsa0
->area
!= NULL
) && (lsa0
->area
->ospf
!= NULL
))
2005 top
= lsa0
->area
->ospf
;
2006 ospf_ls_retransmit_delete_nbr_as(top
, lsa
);
2010 "ospf_opaque_lsa_refresh_schedule: Unexpected LSA-type(%u)",
2015 delay
= ospf_lsa_refresh_delay(lsa
);
2017 if (IS_DEBUG_OSPF_EVENT
)
2019 "Schedule Type-%u Opaque-LSA to REFRESH in %d sec later: [opaque-type=%u, opaque-id=%x]",
2020 lsa
->data
->type
, delay
,
2021 GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
)),
2022 GET_OPAQUE_ID(ntohl(lsa
->data
->id
.s_addr
)));
2024 OSPF_OPAQUE_TIMER_ON(oipi
->t_opaque_lsa_self
,
2025 ospf_opaque_lsa_refresh_timer
, oipi
, delay
* 1000);
2030 static int ospf_opaque_lsa_refresh_timer(struct thread
*t
)
2032 struct opaque_info_per_id
*oipi
;
2033 struct ospf_opaque_functab
*functab
;
2034 struct ospf_lsa
*lsa
;
2036 if (IS_DEBUG_OSPF_EVENT
)
2037 zlog_debug("Timer[Opaque-LSA]: (Opaque-LSA Refresh expire)");
2039 oipi
= THREAD_ARG(t
);
2040 oipi
->t_opaque_lsa_self
= NULL
;
2042 if ((lsa
= oipi
->lsa
) != NULL
)
2043 if ((functab
= oipi
->opqctl_type
->functab
) != NULL
)
2044 if (functab
->lsa_refresher
!= NULL
)
2045 (*functab
->lsa_refresher
)(lsa
);
2050 void ospf_opaque_lsa_flush_schedule(struct ospf_lsa
*lsa0
)
2052 struct opaque_info_per_type
*oipt
;
2053 struct opaque_info_per_id
*oipi
;
2054 struct ospf_lsa
*lsa
;
2057 top
= ospf_lookup_by_vrf_id(lsa0
->vrf_id
);
2059 if ((oipt
= lookup_opaque_info_by_type(lsa0
)) == NULL
2060 || (oipi
= lookup_opaque_info_by_id(oipt
, lsa0
)) == NULL
) {
2061 zlog_warn("ospf_opaque_lsa_flush_schedule: Invalid parameter?");
2065 /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
2066 if ((lsa
= oipi
->lsa
) == NULL
) {
2067 zlog_warn("ospf_opaque_lsa_flush_schedule: Something wrong?");
2071 /* Delete this lsa from neighbor retransmit-list. */
2072 switch (lsa
->data
->type
) {
2073 case OSPF_OPAQUE_LINK_LSA
:
2074 case OSPF_OPAQUE_AREA_LSA
:
2075 ospf_ls_retransmit_delete_nbr_area(lsa
->area
, lsa
);
2077 case OSPF_OPAQUE_AS_LSA
:
2078 if ((lsa0
->area
!= NULL
) && (lsa0
->area
->ospf
!= NULL
))
2079 top
= lsa0
->area
->ospf
;
2080 ospf_ls_retransmit_delete_nbr_as(top
, lsa
);
2084 "ospf_opaque_lsa_flush_schedule: Unexpected LSA-type(%u)",
2089 /* Dequeue listnode entry from the list. */
2090 listnode_delete(oipt
->id_list
, oipi
);
2092 /* Avoid misjudgement in the next lookup. */
2093 if (listcount(oipt
->id_list
) == 0)
2094 oipt
->id_list
->head
= oipt
->id_list
->tail
= NULL
;
2096 /* Disassociate internal control information with the given lsa. */
2097 free_opaque_info_per_id((void *)oipi
);
2099 /* Force given lsa's age to MaxAge. */
2100 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
2102 if (IS_DEBUG_OSPF_EVENT
)
2104 "Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]",
2106 GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
)),
2107 GET_OPAQUE_ID(ntohl(lsa
->data
->id
.s_addr
)));
2109 /* This lsa will be flushed and removed eventually. */
2110 ospf_lsa_flush(top
, lsa
);
2116 void ospf_opaque_self_originated_lsa_received(struct ospf_neighbor
*nbr
,
2117 struct ospf_lsa
*lsa
)
2121 if ((top
= oi_to_top(nbr
->oi
)) == NULL
)
2125 * Since these LSA entries are not yet installed into corresponding
2126 * LSDB, just flush them without calling ospf_ls_maxage() afterward.
2128 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
2129 switch (lsa
->data
->type
) {
2130 case OSPF_OPAQUE_LINK_LSA
:
2131 ospf_flood_through_area(nbr
->oi
->area
, NULL
/*inbr*/, lsa
);
2133 case OSPF_OPAQUE_AREA_LSA
:
2134 ospf_flood_through_area(nbr
->oi
->area
, NULL
/*inbr*/, lsa
);
2136 case OSPF_OPAQUE_AS_LSA
:
2137 ospf_flood_through_as(top
, NULL
/*inbr*/, lsa
);
2141 "ospf_opaque_self_originated_lsa_received: Unexpected LSA-type(%u)",
2145 ospf_lsa_discard(lsa
); /* List "lsas" will be deleted by caller. */
2148 /*------------------------------------------------------------------------*
2149 * Followings are util functions; probably be used by Opaque-LSAs only...
2150 *------------------------------------------------------------------------*/
2152 struct ospf
*oi_to_top(struct ospf_interface
*oi
)
2154 struct ospf
*top
= NULL
;
2155 struct ospf_area
*area
;
2157 if (oi
== NULL
|| (area
= oi
->area
) == NULL
2158 || (top
= area
->ospf
) == NULL
)
2159 zlog_warn("Broken relationship for \"OI -> AREA -> OSPF\"?");