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(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(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(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(area
->opaque_lsa_self
);
158 area
->opaque_lsa_self
= NULL
;
162 int ospf_opaque_type11_lsa_init(struct ospf
*top
)
164 if (top
->opaque_lsa_self
!= NULL
)
165 list_delete(top
->opaque_lsa_self
);
167 top
->opaque_lsa_self
= list_new();
168 top
->opaque_lsa_self
->del
= free_opaque_info_per_type
;
169 top
->t_opaque_lsa_self
= NULL
;
171 #ifdef MONITOR_LSDB_CHANGE
172 top
->lsdb
->new_lsa_hook
= ospf_opaque_lsa_install_hook
;
173 top
->lsdb
->del_lsa_hook
= ospf_opaque_lsa_delete_hook
;
174 #endif /* MONITOR_LSDB_CHANGE */
178 void ospf_opaque_type11_lsa_term(struct ospf
*top
)
180 #ifdef MONITOR_LSDB_CHANGE
181 top
->lsdb
->new_lsa_hook
= top
->lsdb
->del_lsa_hook
= NULL
;
182 #endif /* MONITOR_LSDB_CHANGE */
184 OSPF_TIMER_OFF(top
->t_opaque_lsa_self
);
185 if (top
->opaque_lsa_self
!= NULL
)
186 list_delete(top
->opaque_lsa_self
);
187 top
->opaque_lsa_self
= NULL
;
191 static const char *ospf_opaque_type_name(u_char opaque_type
)
193 const char *name
= "Unknown";
195 switch (opaque_type
) {
196 case OPAQUE_TYPE_WILDCARD
: /* This is a special assignment! */
199 case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA
:
200 name
= "Traffic Engineering LSA";
202 case OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC
:
203 name
= "Sycamore optical topology description";
205 case OPAQUE_TYPE_GRACE_LSA
:
208 case OPAQUE_TYPE_INTER_AS_LSA
:
209 name
= "Inter-AS TE-v2 LSA";
211 case OPAQUE_TYPE_ROUTER_INFORMATION_LSA
:
212 name
= "Router Information LSA";
215 if (OPAQUE_TYPE_RANGE_UNASSIGNED(opaque_type
))
218 u_int32_t bigger_range
= opaque_type
;
220 * Get around type-limits warning: comparison is always
221 * true due to limited range of data type
223 if (OPAQUE_TYPE_RANGE_RESERVED(bigger_range
))
224 name
= "Private/Experimental";
231 /*------------------------------------------------------------------------*
232 * Followings are management functions to store user specified callbacks.
233 *------------------------------------------------------------------------*/
235 struct opaque_info_per_type
; /* Forward declaration. */
237 struct ospf_opaque_functab
{
239 struct opaque_info_per_type
*oipt
;
241 int (*new_if_hook
)(struct interface
*ifp
);
242 int (*del_if_hook
)(struct interface
*ifp
);
243 void (*ism_change_hook
)(struct ospf_interface
*oi
, int old_status
);
244 void (*nsm_change_hook
)(struct ospf_neighbor
*nbr
, int old_status
);
245 void (*config_write_router
)(struct vty
*vty
);
246 void (*config_write_if
)(struct vty
*vty
, struct interface
*ifp
);
247 void (*config_write_debug
)(struct vty
*vty
);
248 void (*show_opaque_info
)(struct vty
*vty
, struct ospf_lsa
*lsa
);
249 int (*lsa_originator
)(void *arg
);
250 struct ospf_lsa
*(*lsa_refresher
)(struct ospf_lsa
*lsa
);
251 int (*new_lsa_hook
)(struct ospf_lsa
*lsa
);
252 int (*del_lsa_hook
)(struct ospf_lsa
*lsa
);
255 /* Handle LSA-9/10/11 altogether. */
256 static struct list
*ospf_opaque_wildcard_funclist
;
257 static struct list
*ospf_opaque_type9_funclist
;
258 static struct list
*ospf_opaque_type10_funclist
;
259 static struct list
*ospf_opaque_type11_funclist
;
261 static void ospf_opaque_del_functab(void *val
)
263 XFREE(MTYPE_OSPF_OPAQUE_FUNCTAB
, val
);
267 static void ospf_opaque_funclist_init(void)
269 struct list
*funclist
;
271 funclist
= ospf_opaque_wildcard_funclist
= list_new();
272 funclist
->del
= ospf_opaque_del_functab
;
274 funclist
= ospf_opaque_type9_funclist
= list_new();
275 funclist
->del
= ospf_opaque_del_functab
;
277 funclist
= ospf_opaque_type10_funclist
= list_new();
278 funclist
->del
= ospf_opaque_del_functab
;
280 funclist
= ospf_opaque_type11_funclist
= list_new();
281 funclist
->del
= ospf_opaque_del_functab
;
285 static void ospf_opaque_funclist_term(void)
287 struct list
*funclist
;
289 funclist
= ospf_opaque_wildcard_funclist
;
290 list_delete(funclist
);
292 funclist
= ospf_opaque_type9_funclist
;
293 list_delete(funclist
);
295 funclist
= ospf_opaque_type10_funclist
;
296 list_delete(funclist
);
298 funclist
= ospf_opaque_type11_funclist
;
299 list_delete(funclist
);
303 static struct list
*ospf_get_opaque_funclist(u_char lsa_type
)
305 struct list
*funclist
= NULL
;
308 case OPAQUE_TYPE_WILDCARD
:
310 * This is an ugly trick to handle type-9/10/11 LSA altogether.
311 * Yes, "OPAQUE_TYPE_WILDCARD (value 0)" is not an LSA-type, nor
312 * an officially assigned opaque-type.
313 * Though it is possible that the value might be officially used
314 * in the future, we use it internally as a special label, for
317 funclist
= ospf_opaque_wildcard_funclist
;
319 case OSPF_OPAQUE_LINK_LSA
:
320 funclist
= ospf_opaque_type9_funclist
;
322 case OSPF_OPAQUE_AREA_LSA
:
323 funclist
= ospf_opaque_type10_funclist
;
325 case OSPF_OPAQUE_AS_LSA
:
326 funclist
= ospf_opaque_type11_funclist
;
329 zlog_warn("ospf_get_opaque_funclist: Unexpected LSA-type(%u)",
336 /* XXX: such a huge argument list can /not/ be healthy... */
337 int ospf_register_opaque_functab(
338 u_char lsa_type
, u_char opaque_type
,
339 int (*new_if_hook
)(struct interface
*ifp
),
340 int (*del_if_hook
)(struct interface
*ifp
),
341 void (*ism_change_hook
)(struct ospf_interface
*oi
, int old_status
),
342 void (*nsm_change_hook
)(struct ospf_neighbor
*nbr
, int old_status
),
343 void (*config_write_router
)(struct vty
*vty
),
344 void (*config_write_if
)(struct vty
*vty
, struct interface
*ifp
),
345 void (*config_write_debug
)(struct vty
*vty
),
346 void (*show_opaque_info
)(struct vty
*vty
, struct ospf_lsa
*lsa
),
347 int (*lsa_originator
)(void *arg
),
348 struct ospf_lsa
*(*lsa_refresher
)(struct ospf_lsa
*lsa
),
349 int (*new_lsa_hook
)(struct ospf_lsa
*lsa
),
350 int (*del_lsa_hook
)(struct ospf_lsa
*lsa
))
352 struct list
*funclist
;
353 struct ospf_opaque_functab
*new;
356 if ((funclist
= ospf_get_opaque_funclist(lsa_type
)) == NULL
) {
358 "ospf_register_opaque_functab: Cannot get funclist"
359 " for Type-%u LSAs?",
363 struct listnode
*node
, *nnode
;
364 struct ospf_opaque_functab
*functab
;
366 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
367 if (functab
->opaque_type
== opaque_type
) {
369 "ospf_register_opaque_functab: Duplicated entry?:"
370 " lsa_type(%u), opaque_type(%u)",
371 lsa_type
, opaque_type
);
376 if ((new = XCALLOC(MTYPE_OSPF_OPAQUE_FUNCTAB
,
377 sizeof(struct ospf_opaque_functab
)))
379 zlog_warn("ospf_register_opaque_functab: XMALLOC: %s",
380 safe_strerror(errno
));
384 new->opaque_type
= opaque_type
;
386 new->new_if_hook
= new_if_hook
;
387 new->del_if_hook
= del_if_hook
;
388 new->ism_change_hook
= ism_change_hook
;
389 new->nsm_change_hook
= nsm_change_hook
;
390 new->config_write_router
= config_write_router
;
391 new->config_write_if
= config_write_if
;
392 new->config_write_debug
= config_write_debug
;
393 new->show_opaque_info
= show_opaque_info
;
394 new->lsa_originator
= lsa_originator
;
395 new->lsa_refresher
= lsa_refresher
;
396 new->new_lsa_hook
= new_lsa_hook
;
397 new->del_lsa_hook
= del_lsa_hook
;
399 listnode_add(funclist
, new);
406 void ospf_delete_opaque_functab(u_char lsa_type
, u_char opaque_type
)
408 struct list
*funclist
;
409 struct listnode
*node
, *nnode
;
410 struct ospf_opaque_functab
*functab
;
412 if ((funclist
= ospf_get_opaque_funclist(lsa_type
)) != NULL
)
413 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
)) {
414 if (functab
->opaque_type
== opaque_type
) {
415 /* Cleanup internal control information, if it
417 if (functab
->oipt
!= NULL
)
418 free_opaque_info_per_type(
421 /* Dequeue listnode entry from the list. */
422 listnode_delete(funclist
, functab
);
424 /* Avoid misjudgement in the next lookup. */
425 if (listcount(funclist
) == 0)
426 funclist
->head
= funclist
->tail
= NULL
;
428 XFREE(MTYPE_OSPF_OPAQUE_FUNCTAB
, functab
);
436 static struct ospf_opaque_functab
*
437 ospf_opaque_functab_lookup(struct ospf_lsa
*lsa
)
439 struct list
*funclist
;
440 struct listnode
*node
;
441 struct ospf_opaque_functab
*functab
;
442 u_char key
= GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
));
444 if ((funclist
= ospf_get_opaque_funclist(lsa
->data
->type
)) != NULL
)
445 for (ALL_LIST_ELEMENTS_RO(funclist
, node
, functab
))
446 if (functab
->opaque_type
== key
)
452 /*------------------------------------------------------------------------*
453 * Followings are management functions for self-originated LSA entries.
454 *------------------------------------------------------------------------*/
457 * Opaque-LSA control information per opaque-type.
458 * Single Opaque-Type may have multiple instances; each of them will be
459 * identified by their opaque-id.
461 struct opaque_info_per_type
{
465 enum { PROC_NORMAL
, PROC_SUSPEND
} status
;
468 * Thread for (re-)origination scheduling for this opaque-type.
470 * Initial origination of Opaque-LSAs is controlled by generic
471 * Opaque-LSA handling module so that same opaque-type entries are
472 * called all at once when certain conditions are met.
473 * However, there might be cases that some Opaque-LSA clients need
474 * to (re-)originate their own Opaque-LSAs out-of-sync with others.
475 * This thread is prepared for that specific purpose.
477 struct thread
*t_opaque_lsa_self
;
480 * Backpointer to an "owner" which is LSA-type dependent.
481 * type-9: struct ospf_interface
482 * type-10: struct ospf_area
483 * type-11: struct ospf
487 /* Collection of callback functions for this opaque-type. */
488 struct ospf_opaque_functab
*functab
;
490 /* List of Opaque-LSA control informations per opaque-id. */
491 struct list
*id_list
;
494 /* Opaque-LSA control information per opaque-id. */
495 struct opaque_info_per_id
{
498 /* Thread for refresh/flush scheduling for this opaque-type/id. */
499 struct thread
*t_opaque_lsa_self
;
501 /* Backpointer to Opaque-LSA control information per opaque-type. */
502 struct opaque_info_per_type
*opqctl_type
;
504 /* Here comes an actual Opaque-LSA entry for this opaque-type/id. */
505 struct ospf_lsa
*lsa
;
508 static struct opaque_info_per_type
*
509 register_opaque_info_per_type(struct ospf_opaque_functab
*functab
,
510 struct ospf_lsa
*new);
511 static struct opaque_info_per_type
*
512 lookup_opaque_info_by_type(struct ospf_lsa
*lsa
);
513 static struct opaque_info_per_id
*
514 register_opaque_info_per_id(struct opaque_info_per_type
*oipt
,
515 struct ospf_lsa
*new);
516 static struct opaque_info_per_id
*
517 lookup_opaque_info_by_id(struct opaque_info_per_type
*oipt
,
518 struct ospf_lsa
*lsa
);
519 static struct opaque_info_per_id
*register_opaque_lsa(struct ospf_lsa
*new);
522 static struct opaque_info_per_type
*
523 register_opaque_info_per_type(struct ospf_opaque_functab
*functab
,
524 struct ospf_lsa
*new)
527 struct opaque_info_per_type
*oipt
;
529 if ((oipt
= XCALLOC(MTYPE_OPAQUE_INFO_PER_TYPE
,
530 sizeof(struct opaque_info_per_type
)))
532 zlog_warn("register_opaque_info_per_type: XMALLOC: %s",
533 safe_strerror(errno
));
537 switch (new->data
->type
) {
538 case OSPF_OPAQUE_LINK_LSA
:
539 oipt
->owner
= new->oi
;
540 listnode_add(new->oi
->opaque_lsa_self
, oipt
);
542 case OSPF_OPAQUE_AREA_LSA
:
543 oipt
->owner
= new->area
;
544 listnode_add(new->area
->opaque_lsa_self
, oipt
);
546 case OSPF_OPAQUE_AS_LSA
:
547 top
= ospf_lookup_by_vrf_id(new->vrf_id
);
548 if (new->area
!= NULL
&& (top
= new->area
->ospf
) == NULL
) {
549 free_opaque_info_per_type((void *)oipt
);
551 goto out
; /* This case may not exist. */
554 listnode_add(top
->opaque_lsa_self
, oipt
);
558 "register_opaque_info_per_type: Unexpected LSA-type(%u)",
560 free_opaque_info_per_type((void *)oipt
);
562 goto out
; /* This case may not exist. */
565 oipt
->lsa_type
= new->data
->type
;
566 oipt
->opaque_type
= GET_OPAQUE_TYPE(ntohl(new->data
->id
.s_addr
));
567 oipt
->status
= PROC_NORMAL
;
568 oipt
->t_opaque_lsa_self
= NULL
;
569 oipt
->functab
= functab
;
570 functab
->oipt
= oipt
;
571 oipt
->id_list
= list_new();
572 oipt
->id_list
->del
= free_opaque_info_per_id
;
578 static void free_opaque_info_per_type(void *val
)
580 struct opaque_info_per_type
*oipt
= (struct opaque_info_per_type
*)val
;
581 struct opaque_info_per_id
*oipi
;
582 struct ospf_lsa
*lsa
;
583 struct listnode
*node
, *nnode
;
585 /* Control information per opaque-id may still exist. */
586 for (ALL_LIST_ELEMENTS(oipt
->id_list
, node
, nnode
, oipi
)) {
587 if ((lsa
= oipi
->lsa
) == NULL
)
589 if (IS_LSA_MAXAGE(lsa
))
591 ospf_opaque_lsa_flush_schedule(lsa
);
594 /* Remove "oipt" from its owner's self-originated LSA list. */
595 switch (oipt
->lsa_type
) {
596 case OSPF_OPAQUE_LINK_LSA
: {
597 struct ospf_interface
*oi
=
598 (struct ospf_interface
*)(oipt
->owner
);
599 listnode_delete(oi
->opaque_lsa_self
, oipt
);
602 case OSPF_OPAQUE_AREA_LSA
: {
603 struct ospf_area
*area
= (struct ospf_area
*)(oipt
->owner
);
604 listnode_delete(area
->opaque_lsa_self
, oipt
);
607 case OSPF_OPAQUE_AS_LSA
: {
608 struct ospf
*top
= (struct ospf
*)(oipt
->owner
);
609 listnode_delete(top
->opaque_lsa_self
, oipt
);
613 zlog_warn("free_opaque_info_per_type: Unexpected LSA-type(%u)",
615 break; /* This case may not exist. */
618 OSPF_TIMER_OFF(oipt
->t_opaque_lsa_self
);
619 list_delete(oipt
->id_list
);
620 XFREE(MTYPE_OPAQUE_INFO_PER_TYPE
, oipt
);
624 static struct opaque_info_per_type
*
625 lookup_opaque_info_by_type(struct ospf_lsa
*lsa
)
628 struct ospf_area
*area
;
629 struct ospf_interface
*oi
;
630 struct list
*listtop
= NULL
;
631 struct listnode
*node
, *nnode
;
632 struct opaque_info_per_type
*oipt
= NULL
;
633 u_char key
= GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
));
635 switch (lsa
->data
->type
) {
636 case OSPF_OPAQUE_LINK_LSA
:
637 if ((oi
= lsa
->oi
) != NULL
)
638 listtop
= oi
->opaque_lsa_self
;
641 "Type-9 Opaque-LSA: Reference to OI is missing?");
643 case OSPF_OPAQUE_AREA_LSA
:
644 if ((area
= lsa
->area
) != NULL
)
645 listtop
= area
->opaque_lsa_self
;
648 "Type-10 Opaque-LSA: Reference to AREA is missing?");
650 case OSPF_OPAQUE_AS_LSA
:
651 top
= ospf_lookup_by_vrf_id(lsa
->vrf_id
);
652 if ((area
= lsa
->area
) != NULL
&& (top
= area
->ospf
) == NULL
) {
654 "Type-11 Opaque-LSA: Reference to OSPF is missing?");
655 break; /* Unlikely to happen. */
657 listtop
= top
->opaque_lsa_self
;
660 zlog_warn("lookup_opaque_info_by_type: Unexpected LSA-type(%u)",
666 for (ALL_LIST_ELEMENTS(listtop
, node
, nnode
, oipt
))
667 if (oipt
->opaque_type
== key
)
673 static struct opaque_info_per_id
*
674 register_opaque_info_per_id(struct opaque_info_per_type
*oipt
,
675 struct ospf_lsa
*new)
677 struct opaque_info_per_id
*oipi
;
679 if ((oipi
= XCALLOC(MTYPE_OPAQUE_INFO_PER_ID
,
680 sizeof(struct opaque_info_per_id
)))
682 zlog_warn("register_opaque_info_per_id: XMALLOC: %s",
683 safe_strerror(errno
));
686 oipi
->opaque_id
= GET_OPAQUE_ID(ntohl(new->data
->id
.s_addr
));
687 oipi
->t_opaque_lsa_self
= NULL
;
688 oipi
->opqctl_type
= oipt
;
689 oipi
->lsa
= ospf_lsa_lock(new);
691 listnode_add(oipt
->id_list
, oipi
);
697 static void free_opaque_info_per_id(void *val
)
699 struct opaque_info_per_id
*oipi
= (struct opaque_info_per_id
*)val
;
701 OSPF_TIMER_OFF(oipi
->t_opaque_lsa_self
);
702 if (oipi
->lsa
!= NULL
)
703 ospf_lsa_unlock(&oipi
->lsa
);
704 XFREE(MTYPE_OPAQUE_INFO_PER_ID
, oipi
);
708 static struct opaque_info_per_id
*
709 lookup_opaque_info_by_id(struct opaque_info_per_type
*oipt
,
710 struct ospf_lsa
*lsa
)
712 struct listnode
*node
, *nnode
;
713 struct opaque_info_per_id
*oipi
;
714 u_int32_t key
= GET_OPAQUE_ID(ntohl(lsa
->data
->id
.s_addr
));
716 for (ALL_LIST_ELEMENTS(oipt
->id_list
, node
, nnode
, oipi
))
717 if (oipi
->opaque_id
== key
)
723 static struct opaque_info_per_id
*register_opaque_lsa(struct ospf_lsa
*new)
725 struct ospf_opaque_functab
*functab
;
726 struct opaque_info_per_type
*oipt
;
727 struct opaque_info_per_id
*oipi
= NULL
;
729 if ((functab
= ospf_opaque_functab_lookup(new)) == NULL
)
732 if ((oipt
= lookup_opaque_info_by_type(new)) == NULL
733 && (oipt
= register_opaque_info_per_type(functab
, new)) == NULL
)
736 if ((oipi
= register_opaque_info_per_id(oipt
, new)) == NULL
)
743 /*------------------------------------------------------------------------*
744 * Followings are (vty) configuration functions for Opaque-LSAs handling.
745 *------------------------------------------------------------------------*/
747 DEFUN (capability_opaque
,
748 capability_opaque_cmd
,
750 "Enable specific OSPF feature\n"
753 VTY_DECLVAR_INSTANCE_CONTEXT(ospf
, ospf
);
755 /* Turn on the "master switch" of opaque-lsa capability. */
756 if (!CHECK_FLAG(ospf
->config
, OSPF_OPAQUE_CAPABLE
)) {
757 if (IS_DEBUG_OSPF_EVENT
)
758 zlog_debug("Opaque capability: OFF -> ON");
760 SET_FLAG(ospf
->config
, OSPF_OPAQUE_CAPABLE
);
761 ospf_renegotiate_optional_capabilities(ospf
);
769 "OSPF specific commands\n"
770 "Enable the Opaque-LSA capability (rfc2370)\n")
772 return capability_opaque(self
, vty
, argc
, argv
);
775 DEFUN (no_capability_opaque
,
776 no_capability_opaque_cmd
,
777 "no capability opaque",
779 "Enable specific OSPF feature\n"
782 VTY_DECLVAR_INSTANCE_CONTEXT(ospf
, ospf
);
784 /* Turn off the "master switch" of opaque-lsa capability. */
785 if (CHECK_FLAG(ospf
->config
, OSPF_OPAQUE_CAPABLE
)) {
786 if (IS_DEBUG_OSPF_EVENT
)
787 zlog_debug("Opaque capability: ON -> OFF");
789 UNSET_FLAG(ospf
->config
, OSPF_OPAQUE_CAPABLE
);
790 ospf_renegotiate_optional_capabilities(ospf
);
795 DEFUN (no_ospf_opaque
,
797 "no ospf opaque-lsa",
799 "OSPF specific commands\n"
800 "Enable the Opaque-LSA capability (rfc2370)\n")
802 return no_capability_opaque(self
, vty
, argc
, argv
);
805 static void ospf_opaque_register_vty(void)
807 install_element(OSPF_NODE
, &capability_opaque_cmd
);
808 install_element(OSPF_NODE
, &no_capability_opaque_cmd
);
809 install_element(OSPF_NODE
, &ospf_opaque_cmd
);
810 install_element(OSPF_NODE
, &no_ospf_opaque_cmd
);
814 /*------------------------------------------------------------------------*
815 * Followings are collection of user-registered function callers.
816 *------------------------------------------------------------------------*/
818 static int opaque_lsa_new_if_callback(struct list
*funclist
,
819 struct interface
*ifp
)
821 struct listnode
*node
, *nnode
;
822 struct ospf_opaque_functab
*functab
;
825 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
826 if (functab
->new_if_hook
!= NULL
)
827 if ((*functab
->new_if_hook
)(ifp
) != 0)
834 static int opaque_lsa_del_if_callback(struct list
*funclist
,
835 struct interface
*ifp
)
837 struct listnode
*node
, *nnode
;
838 struct ospf_opaque_functab
*functab
;
841 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
842 if (functab
->del_if_hook
!= NULL
)
843 if ((*functab
->del_if_hook
)(ifp
) != 0)
850 static void opaque_lsa_ism_change_callback(struct list
*funclist
,
851 struct ospf_interface
*oi
,
854 struct listnode
*node
, *nnode
;
855 struct ospf_opaque_functab
*functab
;
857 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
858 if (functab
->ism_change_hook
!= NULL
)
859 (*functab
->ism_change_hook
)(oi
, old_status
);
864 static void opaque_lsa_nsm_change_callback(struct list
*funclist
,
865 struct ospf_neighbor
*nbr
,
868 struct listnode
*node
, *nnode
;
869 struct ospf_opaque_functab
*functab
;
871 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
872 if (functab
->nsm_change_hook
!= NULL
)
873 (*functab
->nsm_change_hook
)(nbr
, old_status
);
877 static void opaque_lsa_config_write_router_callback(struct list
*funclist
,
880 struct listnode
*node
, *nnode
;
881 struct ospf_opaque_functab
*functab
;
883 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
884 if (functab
->config_write_router
!= NULL
)
885 (*functab
->config_write_router
)(vty
);
889 static void opaque_lsa_config_write_if_callback(struct list
*funclist
,
891 struct interface
*ifp
)
893 struct listnode
*node
, *nnode
;
894 struct ospf_opaque_functab
*functab
;
896 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
897 if (functab
->config_write_if
!= NULL
)
898 (*functab
->config_write_if
)(vty
, ifp
);
902 static void opaque_lsa_config_write_debug_callback(struct list
*funclist
,
905 struct listnode
*node
, *nnode
;
906 struct ospf_opaque_functab
*functab
;
908 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
909 if (functab
->config_write_debug
!= NULL
)
910 (*functab
->config_write_debug
)(vty
);
914 static int opaque_lsa_originate_callback(struct list
*funclist
,
915 void *lsa_type_dependent
)
917 struct listnode
*node
, *nnode
;
918 struct ospf_opaque_functab
*functab
;
921 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
922 if (functab
->lsa_originator
!= NULL
)
923 if ((*functab
->lsa_originator
)(lsa_type_dependent
) != 0)
930 static int new_lsa_callback(struct list
*funclist
, struct ospf_lsa
*lsa
)
932 struct listnode
*node
, *nnode
;
933 struct ospf_opaque_functab
*functab
;
936 /* This function handles ALL types of LSAs, not only opaque ones. */
937 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
938 if (functab
->new_lsa_hook
!= NULL
)
939 if ((*functab
->new_lsa_hook
)(lsa
) != 0)
946 static int del_lsa_callback(struct list
*funclist
, struct ospf_lsa
*lsa
)
948 struct listnode
*node
, *nnode
;
949 struct ospf_opaque_functab
*functab
;
952 /* This function handles ALL types of LSAs, not only opaque ones. */
953 for (ALL_LIST_ELEMENTS(funclist
, node
, nnode
, functab
))
954 if (functab
->del_lsa_hook
!= NULL
)
955 if ((*functab
->del_lsa_hook
)(lsa
) != 0)
962 /*------------------------------------------------------------------------*
963 * Followings are glue functions to call Opaque-LSA specific processing.
964 *------------------------------------------------------------------------*/
966 int ospf_opaque_new_if(struct interface
*ifp
)
968 struct list
*funclist
;
971 funclist
= ospf_opaque_wildcard_funclist
;
972 if (opaque_lsa_new_if_callback(funclist
, ifp
) != 0)
975 funclist
= ospf_opaque_type9_funclist
;
976 if (opaque_lsa_new_if_callback(funclist
, ifp
) != 0)
979 funclist
= ospf_opaque_type10_funclist
;
980 if (opaque_lsa_new_if_callback(funclist
, ifp
) != 0)
983 funclist
= ospf_opaque_type11_funclist
;
984 if (opaque_lsa_new_if_callback(funclist
, ifp
) != 0)
992 int ospf_opaque_del_if(struct interface
*ifp
)
994 struct list
*funclist
;
997 funclist
= ospf_opaque_wildcard_funclist
;
998 if (opaque_lsa_del_if_callback(funclist
, ifp
) != 0)
1001 funclist
= ospf_opaque_type9_funclist
;
1002 if (opaque_lsa_del_if_callback(funclist
, ifp
) != 0)
1005 funclist
= ospf_opaque_type10_funclist
;
1006 if (opaque_lsa_del_if_callback(funclist
, ifp
) != 0)
1009 funclist
= ospf_opaque_type11_funclist
;
1010 if (opaque_lsa_del_if_callback(funclist
, ifp
) != 0)
1018 void ospf_opaque_ism_change(struct ospf_interface
*oi
, int old_status
)
1020 struct list
*funclist
;
1022 funclist
= ospf_opaque_wildcard_funclist
;
1023 opaque_lsa_ism_change_callback(funclist
, oi
, old_status
);
1025 funclist
= ospf_opaque_type9_funclist
;
1026 opaque_lsa_ism_change_callback(funclist
, oi
, old_status
);
1028 funclist
= ospf_opaque_type10_funclist
;
1029 opaque_lsa_ism_change_callback(funclist
, oi
, old_status
);
1031 funclist
= ospf_opaque_type11_funclist
;
1032 opaque_lsa_ism_change_callback(funclist
, oi
, old_status
);
1037 void ospf_opaque_nsm_change(struct ospf_neighbor
*nbr
, int old_state
)
1040 struct list
*funclist
;
1042 if ((top
= oi_to_top(nbr
->oi
)) == NULL
)
1045 if (old_state
!= NSM_Full
&& nbr
->state
== NSM_Full
) {
1046 if (CHECK_FLAG(nbr
->options
, OSPF_OPTION_O
)) {
1047 if (!CHECK_FLAG(top
->opaque
,
1048 OPAQUE_OPERATION_READY_BIT
)) {
1049 if (IS_DEBUG_OSPF_EVENT
)
1051 "Opaque-LSA: Now get operational!");
1053 SET_FLAG(top
->opaque
,
1054 OPAQUE_OPERATION_READY_BIT
);
1057 ospf_opaque_lsa_originate_schedule(nbr
->oi
, NULL
);
1059 } else if (old_state
== NSM_Full
&& nbr
->state
!= NSM_Full
) {
1062 * If no more opaque-capable full-state neighbor remains in the
1063 * flooding scope which corresponds to Opaque-LSA type, periodic
1064 * LS flooding should be stopped.
1070 funclist
= ospf_opaque_wildcard_funclist
;
1071 opaque_lsa_nsm_change_callback(funclist
, nbr
, old_state
);
1073 funclist
= ospf_opaque_type9_funclist
;
1074 opaque_lsa_nsm_change_callback(funclist
, nbr
, old_state
);
1076 funclist
= ospf_opaque_type10_funclist
;
1077 opaque_lsa_nsm_change_callback(funclist
, nbr
, old_state
);
1079 funclist
= ospf_opaque_type11_funclist
;
1080 opaque_lsa_nsm_change_callback(funclist
, nbr
, old_state
);
1086 void ospf_opaque_config_write_router(struct vty
*vty
, struct ospf
*ospf
)
1088 struct list
*funclist
;
1090 if (CHECK_FLAG(ospf
->config
, OSPF_OPAQUE_CAPABLE
))
1091 vty_out(vty
, " capability opaque\n");
1093 funclist
= ospf_opaque_wildcard_funclist
;
1094 opaque_lsa_config_write_router_callback(funclist
, vty
);
1096 funclist
= ospf_opaque_type9_funclist
;
1097 opaque_lsa_config_write_router_callback(funclist
, vty
);
1099 funclist
= ospf_opaque_type10_funclist
;
1100 opaque_lsa_config_write_router_callback(funclist
, vty
);
1102 funclist
= ospf_opaque_type11_funclist
;
1103 opaque_lsa_config_write_router_callback(funclist
, vty
);
1108 void ospf_opaque_config_write_if(struct vty
*vty
, struct interface
*ifp
)
1110 struct list
*funclist
;
1112 funclist
= ospf_opaque_wildcard_funclist
;
1113 opaque_lsa_config_write_if_callback(funclist
, vty
, ifp
);
1115 funclist
= ospf_opaque_type9_funclist
;
1116 opaque_lsa_config_write_if_callback(funclist
, vty
, ifp
);
1118 funclist
= ospf_opaque_type10_funclist
;
1119 opaque_lsa_config_write_if_callback(funclist
, vty
, ifp
);
1121 funclist
= ospf_opaque_type11_funclist
;
1122 opaque_lsa_config_write_if_callback(funclist
, vty
, ifp
);
1127 void ospf_opaque_config_write_debug(struct vty
*vty
)
1129 struct list
*funclist
;
1131 funclist
= ospf_opaque_wildcard_funclist
;
1132 opaque_lsa_config_write_debug_callback(funclist
, vty
);
1134 funclist
= ospf_opaque_type9_funclist
;
1135 opaque_lsa_config_write_debug_callback(funclist
, vty
);
1137 funclist
= ospf_opaque_type10_funclist
;
1138 opaque_lsa_config_write_debug_callback(funclist
, vty
);
1140 funclist
= ospf_opaque_type11_funclist
;
1141 opaque_lsa_config_write_debug_callback(funclist
, vty
);
1146 void show_opaque_info_detail(struct vty
*vty
, struct ospf_lsa
*lsa
)
1148 struct lsa_header
*lsah
= (struct lsa_header
*)lsa
->data
;
1149 u_int32_t lsid
= ntohl(lsah
->id
.s_addr
);
1150 u_char opaque_type
= GET_OPAQUE_TYPE(lsid
);
1151 u_int32_t opaque_id
= GET_OPAQUE_ID(lsid
);
1152 struct ospf_opaque_functab
*functab
;
1154 /* Switch output functionality by vty address. */
1156 vty_out(vty
, " Opaque-Type %u (%s)\n", opaque_type
,
1157 ospf_opaque_type_name(opaque_type
));
1158 vty_out(vty
, " Opaque-ID 0x%x\n", opaque_id
);
1160 vty_out(vty
, " Opaque-Info: %u octets of data%s\n",
1161 ntohs(lsah
->length
) - OSPF_LSA_HEADER_SIZE
,
1162 VALID_OPAQUE_INFO_LEN(lsah
) ? "" : "(Invalid length?)");
1164 zlog_debug(" Opaque-Type %u (%s)", opaque_type
,
1165 ospf_opaque_type_name(opaque_type
));
1166 zlog_debug(" Opaque-ID 0x%x", opaque_id
);
1168 zlog_debug(" Opaque-Info: %u octets of data%s",
1169 ntohs(lsah
->length
) - OSPF_LSA_HEADER_SIZE
,
1170 VALID_OPAQUE_INFO_LEN(lsah
) ? ""
1171 : "(Invalid length?)");
1174 /* Call individual output functions. */
1175 if ((functab
= ospf_opaque_functab_lookup(lsa
)) != NULL
)
1176 if (functab
->show_opaque_info
!= NULL
)
1177 (*functab
->show_opaque_info
)(vty
, lsa
);
1182 void ospf_opaque_lsa_dump(struct stream
*s
, u_int16_t length
)
1184 struct ospf_lsa lsa
;
1186 lsa
.data
= (struct lsa_header
*)STREAM_PNT(s
);
1187 show_opaque_info_detail(NULL
, &lsa
);
1191 static int ospf_opaque_lsa_install_hook(struct ospf_lsa
*lsa
)
1193 struct list
*funclist
;
1197 * Some Opaque-LSA user may want to monitor every LSA installation
1198 * into the LSDB, regardless with target LSA type.
1200 funclist
= ospf_opaque_wildcard_funclist
;
1201 if (new_lsa_callback(funclist
, lsa
) != 0)
1204 funclist
= ospf_opaque_type9_funclist
;
1205 if (new_lsa_callback(funclist
, lsa
) != 0)
1208 funclist
= ospf_opaque_type10_funclist
;
1209 if (new_lsa_callback(funclist
, lsa
) != 0)
1212 funclist
= ospf_opaque_type11_funclist
;
1213 if (new_lsa_callback(funclist
, lsa
) != 0)
1221 static int ospf_opaque_lsa_delete_hook(struct ospf_lsa
*lsa
)
1223 struct list
*funclist
;
1227 * Some Opaque-LSA user may want to monitor every LSA deletion
1228 * from the LSDB, regardless with target LSA type.
1230 funclist
= ospf_opaque_wildcard_funclist
;
1231 if (del_lsa_callback(funclist
, lsa
) != 0)
1234 funclist
= ospf_opaque_type9_funclist
;
1235 if (del_lsa_callback(funclist
, lsa
) != 0)
1238 funclist
= ospf_opaque_type10_funclist
;
1239 if (del_lsa_callback(funclist
, lsa
) != 0)
1242 funclist
= ospf_opaque_type11_funclist
;
1243 if (del_lsa_callback(funclist
, lsa
) != 0)
1251 /*------------------------------------------------------------------------*
1252 * Followings are Opaque-LSA origination/refresh management functions.
1253 *------------------------------------------------------------------------*/
1255 static int ospf_opaque_type9_lsa_originate(struct thread
*t
);
1256 static int ospf_opaque_type10_lsa_originate(struct thread
*t
);
1257 static int ospf_opaque_type11_lsa_originate(struct thread
*t
);
1258 static void ospf_opaque_lsa_reoriginate_resume(struct list
*listtop
, void *arg
);
1260 void ospf_opaque_lsa_originate_schedule(struct ospf_interface
*oi
, int *delay0
)
1263 struct ospf_area
*area
;
1264 struct listnode
*node
, *nnode
;
1265 struct opaque_info_per_type
*oipt
;
1268 if ((top
= oi_to_top(oi
)) == NULL
|| (area
= oi
->area
) == NULL
) {
1270 "ospf_opaque_lsa_originate_schedule: Invalid argument?");
1274 /* It may not a right time to schedule origination now. */
1275 if (!CHECK_FLAG(top
->opaque
, OPAQUE_OPERATION_READY_BIT
)) {
1276 if (IS_DEBUG_OSPF_EVENT
)
1278 "ospf_opaque_lsa_originate_schedule: Not operational.");
1279 goto out
; /* This is not an error. */
1286 * There might be some entries that have been waiting for triggering
1287 * of per opaque-type re-origination get resumed.
1289 ospf_opaque_lsa_reoriginate_resume(oi
->opaque_lsa_self
, (void *)oi
);
1290 ospf_opaque_lsa_reoriginate_resume(area
->opaque_lsa_self
, (void *)area
);
1291 ospf_opaque_lsa_reoriginate_resume(top
->opaque_lsa_self
, (void *)top
);
1294 * Now, schedule origination of all Opaque-LSAs per opaque-type.
1296 if (!list_isempty(ospf_opaque_type9_funclist
)
1297 && list_isempty(oi
->opaque_lsa_self
)
1298 && oi
->t_opaque_lsa_self
== NULL
) {
1299 if (IS_DEBUG_OSPF_EVENT
)
1301 "Schedule Type-9 Opaque-LSA origination in %d ms later.",
1303 oi
->t_opaque_lsa_self
= NULL
;
1304 thread_add_timer_msec(master
, ospf_opaque_type9_lsa_originate
,
1305 oi
, delay
, &oi
->t_opaque_lsa_self
);
1306 delay
+= top
->min_ls_interval
;
1309 if (!list_isempty(ospf_opaque_type10_funclist
)
1310 && list_isempty(area
->opaque_lsa_self
)
1311 && area
->t_opaque_lsa_self
== NULL
) {
1313 * One AREA may contain multiple OIs, but above 2nd and 3rd
1314 * conditions prevent from scheduling the originate function
1317 if (IS_DEBUG_OSPF_EVENT
)
1319 "Schedule Type-10 Opaque-LSA origination in %d ms later.",
1321 area
->t_opaque_lsa_self
= NULL
;
1322 thread_add_timer_msec(master
, ospf_opaque_type10_lsa_originate
,
1323 area
, delay
, &area
->t_opaque_lsa_self
);
1324 delay
+= top
->min_ls_interval
;
1327 if (!list_isempty(ospf_opaque_type11_funclist
)
1328 && list_isempty(top
->opaque_lsa_self
)
1329 && top
->t_opaque_lsa_self
== NULL
) {
1331 * One OSPF may contain multiple AREAs, but above 2nd and 3rd
1332 * conditions prevent from scheduling the originate function
1335 if (IS_DEBUG_OSPF_EVENT
)
1337 "Schedule Type-11 Opaque-LSA origination in %d ms later.",
1339 top
->t_opaque_lsa_self
= NULL
;
1340 thread_add_timer_msec(master
, ospf_opaque_type11_lsa_originate
,
1341 top
, delay
, &top
->t_opaque_lsa_self
);
1342 delay
+= top
->min_ls_interval
;
1346 * Following section treats a special situation that this node's
1347 * opaque capability has changed as "ON -> OFF -> ON".
1349 if (!list_isempty(ospf_opaque_type9_funclist
)
1350 && !list_isempty(oi
->opaque_lsa_self
)) {
1351 for (ALL_LIST_ELEMENTS(oi
->opaque_lsa_self
, node
, nnode
,
1354 * removed the test for
1355 * (! list_isempty (oipt->id_list)) * Handler is
1357 * because opaque cababilities ON -> OFF -> ON result in
1358 * list_isempty (oipt->id_list)
1362 oipt
->t_opaque_lsa_self
1363 != NULL
/* Waiting for a thread call. */
1364 || oipt
->status
== PROC_SUSPEND
) /* Cannot
1369 ospf_opaque_lsa_reoriginate_schedule(
1370 (void *)oi
, OSPF_OPAQUE_LINK_LSA
,
1375 if (!list_isempty(ospf_opaque_type10_funclist
)
1376 && !list_isempty(area
->opaque_lsa_self
)) {
1377 for (ALL_LIST_ELEMENTS(area
->opaque_lsa_self
, node
, nnode
,
1380 * removed the test for
1381 * (! list_isempty (oipt->id_list)) * Handler is
1383 * because opaque cababilities ON -> OFF -> ON result in
1384 * list_isempty (oipt->id_list)
1388 oipt
->t_opaque_lsa_self
1389 != NULL
/* Waiting for a thread call. */
1390 || oipt
->status
== PROC_SUSPEND
) /* Cannot
1395 ospf_opaque_lsa_reoriginate_schedule(
1396 (void *)area
, OSPF_OPAQUE_AREA_LSA
,
1401 if (!list_isempty(ospf_opaque_type11_funclist
)
1402 && !list_isempty(top
->opaque_lsa_self
)) {
1403 for (ALL_LIST_ELEMENTS(top
->opaque_lsa_self
, node
, nnode
,
1406 * removed the test for
1407 * (! list_isempty (oipt->id_list)) * Handler is
1409 * because opaque cababilities ON -> OFF -> ON result in
1410 * list_isempty (oipt->id_list)
1414 oipt
->t_opaque_lsa_self
1415 != NULL
/* Waiting for a thread call. */
1416 || oipt
->status
== PROC_SUSPEND
) /* Cannot
1421 ospf_opaque_lsa_reoriginate_schedule((void *)top
,
1434 static int ospf_opaque_type9_lsa_originate(struct thread
*t
)
1436 struct ospf_interface
*oi
;
1440 oi
->t_opaque_lsa_self
= NULL
;
1442 if (IS_DEBUG_OSPF_EVENT
)
1443 zlog_debug("Timer[Type9-LSA]: Originate Opaque-LSAs for OI %s",
1446 rc
= opaque_lsa_originate_callback(ospf_opaque_type9_funclist
, oi
);
1451 static int ospf_opaque_type10_lsa_originate(struct thread
*t
)
1453 struct ospf_area
*area
;
1456 area
= THREAD_ARG(t
);
1457 area
->t_opaque_lsa_self
= NULL
;
1459 if (IS_DEBUG_OSPF_EVENT
)
1461 "Timer[Type10-LSA]: Originate Opaque-LSAs for Area %s",
1462 inet_ntoa(area
->area_id
));
1464 rc
= opaque_lsa_originate_callback(ospf_opaque_type10_funclist
, area
);
1469 static int ospf_opaque_type11_lsa_originate(struct thread
*t
)
1474 top
= THREAD_ARG(t
);
1475 top
->t_opaque_lsa_self
= NULL
;
1477 if (IS_DEBUG_OSPF_EVENT
)
1479 "Timer[Type11-LSA]: Originate AS-External Opaque-LSAs");
1481 rc
= opaque_lsa_originate_callback(ospf_opaque_type11_funclist
, top
);
1486 static void ospf_opaque_lsa_reoriginate_resume(struct list
*listtop
, void *arg
)
1488 struct listnode
*node
, *nnode
;
1489 struct opaque_info_per_type
*oipt
;
1490 struct ospf_opaque_functab
*functab
;
1492 if (listtop
== NULL
)
1496 * Pickup oipt entries those which in SUSPEND status, and give
1497 * them a chance to start re-origination now.
1499 for (ALL_LIST_ELEMENTS(listtop
, node
, nnode
, oipt
)) {
1500 if (oipt
->status
!= PROC_SUSPEND
)
1503 oipt
->status
= PROC_NORMAL
;
1505 if ((functab
= oipt
->functab
) == NULL
1506 || functab
->lsa_originator
== NULL
)
1509 if ((*functab
->lsa_originator
)(arg
) != 0) {
1511 "ospf_opaque_lsa_reoriginate_resume: Failed (opaque-type=%u)",
1521 struct ospf_lsa
*ospf_opaque_lsa_install(struct ospf_lsa
*lsa
, int rt_recalc
)
1523 struct ospf_lsa
*new = NULL
;
1524 struct opaque_info_per_type
*oipt
;
1525 struct opaque_info_per_id
*oipi
;
1528 /* Don't take "rt_recalc" into consideration for now. */ /* XXX */
1530 if (!IS_LSA_SELF(lsa
)) {
1531 new = lsa
; /* Don't touch this LSA. */
1535 if (IS_DEBUG_OSPF(lsa
, LSA_INSTALL
))
1537 "Install Type-%u Opaque-LSA: [opaque-type=%u, opaque-id=%x]",
1539 GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
)),
1540 GET_OPAQUE_ID(ntohl(lsa
->data
->id
.s_addr
)));
1542 /* Replace the existing lsa with the new one. */
1543 if ((oipt
= lookup_opaque_info_by_type(lsa
)) != NULL
1544 && (oipi
= lookup_opaque_info_by_id(oipt
, lsa
)) != NULL
) {
1545 ospf_lsa_unlock(&oipi
->lsa
);
1546 oipi
->lsa
= ospf_lsa_lock(lsa
);
1548 /* Register the new lsa entry and get its control info. */
1549 else if ((oipi
= register_opaque_lsa(lsa
)) == NULL
) {
1550 zlog_warn("ospf_opaque_lsa_install: register_opaque_lsa() ?");
1555 * Make use of a common mechanism (ospf_lsa_refresh_walker)
1556 * for periodic refresh of self-originated Opaque-LSAs.
1558 switch (lsa
->data
->type
) {
1559 case OSPF_OPAQUE_LINK_LSA
:
1560 if ((top
= oi_to_top(lsa
->oi
)) == NULL
) {
1561 /* Above conditions must have passed. */
1562 zlog_warn("ospf_opaque_lsa_install: Sonmething wrong?");
1566 case OSPF_OPAQUE_AREA_LSA
:
1567 if (lsa
->area
== NULL
|| (top
= lsa
->area
->ospf
) == NULL
) {
1568 /* Above conditions must have passed. */
1569 zlog_warn("ospf_opaque_lsa_install: Sonmething wrong?");
1573 case OSPF_OPAQUE_AS_LSA
:
1574 top
= ospf_lookup_by_vrf_id(lsa
->vrf_id
);
1575 if (lsa
->area
!= NULL
&& (top
= lsa
->area
->ospf
) == NULL
) {
1576 /* Above conditions must have passed. */
1577 zlog_warn("ospf_opaque_lsa_install: Sonmething wrong?");
1582 zlog_warn("ospf_opaque_lsa_install: Unexpected LSA-type(%u)",
1587 ospf_refresher_register_lsa(top
, lsa
);
1594 struct ospf_lsa
*ospf_opaque_lsa_refresh(struct ospf_lsa
*lsa
)
1597 struct ospf_opaque_functab
*functab
;
1598 struct ospf_lsa
*new = NULL
;
1600 ospf
= ospf_lookup_by_vrf_id(lsa
->vrf_id
);
1602 if ((functab
= ospf_opaque_functab_lookup(lsa
)) == NULL
1603 || functab
->lsa_refresher
== NULL
) {
1605 * Though this LSA seems to have originated on this node, the
1606 * handling module for this "lsa-type and opaque-type" was
1607 * already deleted sometime ago.
1608 * Anyway, this node still has a responsibility to flush this
1609 * LSA from the routing domain.
1611 if (IS_DEBUG_OSPF_EVENT
)
1612 zlog_debug("LSA[Type%d:%s]: Flush stray Opaque-LSA",
1613 lsa
->data
->type
, inet_ntoa(lsa
->data
->id
));
1615 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
1616 ospf_lsa_flush(ospf
, lsa
);
1618 new = (*functab
->lsa_refresher
)(lsa
);
1623 /*------------------------------------------------------------------------*
1624 * Followings are re-origination/refresh/flush operations of Opaque-LSAs,
1625 * triggered by external interventions (vty session, signaling, etc).
1626 *------------------------------------------------------------------------*/
1628 #define OSPF_OPAQUE_TIMER_ON(T,F,L,V) thread_add_timer_msec (master, (F), (L), (V), &(T))
1630 static struct ospf_lsa
*pseudo_lsa(struct ospf_interface
*oi
,
1631 struct ospf_area
*area
, u_char lsa_type
,
1632 u_char opaque_type
);
1633 static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread
*t
);
1634 static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread
*t
);
1635 static int ospf_opaque_type11_lsa_reoriginate_timer(struct thread
*t
);
1636 static int ospf_opaque_lsa_refresh_timer(struct thread
*t
);
1638 void ospf_opaque_lsa_reoriginate_schedule(void *lsa_type_dependent
,
1639 u_char lsa_type
, u_char opaque_type
)
1641 struct ospf
*top
= NULL
;
1642 struct ospf_area dummy
, *area
= NULL
;
1643 struct ospf_interface
*oi
= NULL
;
1645 struct ospf_lsa
*lsa
;
1646 struct opaque_info_per_type
*oipt
;
1647 int (*func
)(struct thread
* t
) = NULL
;
1651 case OSPF_OPAQUE_LINK_LSA
:
1652 if ((oi
= (struct ospf_interface
*)lsa_type_dependent
)
1655 "ospf_opaque_lsa_reoriginate_schedule:"
1656 " Type-9 Opaque-LSA: Invalid parameter?");
1659 if ((top
= oi_to_top(oi
)) == NULL
) {
1661 "ospf_opaque_lsa_reoriginate_schedule: OI(%s) -> TOP?",
1665 if (!list_isempty(ospf_opaque_type9_funclist
)
1666 && list_isempty(oi
->opaque_lsa_self
)
1667 && oi
->t_opaque_lsa_self
!= NULL
) {
1669 "Type-9 Opaque-LSA (opaque_type=%u):"
1670 " Common origination for OI(%s) has already started",
1671 opaque_type
, IF_NAME(oi
));
1674 func
= ospf_opaque_type9_lsa_reoriginate_timer
;
1676 case OSPF_OPAQUE_AREA_LSA
:
1677 if ((area
= (struct ospf_area
*)lsa_type_dependent
) == NULL
) {
1679 "ospf_opaque_lsa_reoriginate_schedule:"
1680 " Type-10 Opaque-LSA: Invalid parameter?");
1683 if ((top
= area
->ospf
) == NULL
) {
1685 "ospf_opaque_lsa_reoriginate_schedule:"
1686 " AREA(%s) -> TOP?",
1687 inet_ntoa(area
->area_id
));
1690 if (!list_isempty(ospf_opaque_type10_funclist
)
1691 && list_isempty(area
->opaque_lsa_self
)
1692 && area
->t_opaque_lsa_self
!= NULL
) {
1694 "Type-10 Opaque-LSA (opaque_type=%u):"
1695 " Common origination for AREA(%s) has already started",
1696 opaque_type
, inet_ntoa(area
->area_id
));
1699 func
= ospf_opaque_type10_lsa_reoriginate_timer
;
1701 case OSPF_OPAQUE_AS_LSA
:
1702 if ((top
= (struct ospf
*)lsa_type_dependent
) == NULL
) {
1704 "ospf_opaque_lsa_reoriginate_schedule:"
1705 " Type-11 Opaque-LSA: Invalid parameter?");
1708 if (!list_isempty(ospf_opaque_type11_funclist
)
1709 && list_isempty(top
->opaque_lsa_self
)
1710 && top
->t_opaque_lsa_self
!= NULL
) {
1712 "Type-11 Opaque-LSA (opaque_type=%u):"
1713 " Common origination has already started",
1718 /* Fake "area" to pass "ospf" to a lookup function later. */
1722 func
= ospf_opaque_type11_lsa_reoriginate_timer
;
1726 "ospf_opaque_lsa_reoriginate_schedule:"
1727 " Unexpected LSA-type(%u)",
1732 /* It may not a right time to schedule reorigination now. */
1733 if (!CHECK_FLAG(top
->opaque
, OPAQUE_OPERATION_READY_BIT
)) {
1734 if (IS_DEBUG_OSPF_EVENT
)
1736 "ospf_opaque_lsa_reoriginate_schedule: Not operational.");
1737 goto out
; /* This is not an error. */
1740 /* Generate a dummy lsa to be passed for a lookup function. */
1741 lsa
= pseudo_lsa(oi
, area
, lsa_type
, opaque_type
);
1742 lsa
->vrf_id
= top
->vrf_id
;
1744 if ((oipt
= lookup_opaque_info_by_type(lsa
)) == NULL
) {
1745 struct ospf_opaque_functab
*functab
;
1746 if ((functab
= ospf_opaque_functab_lookup(lsa
)) == NULL
) {
1748 "ospf_opaque_lsa_reoriginate_schedule:"
1749 " No associated function?: lsa_type(%u),"
1751 lsa_type
, opaque_type
);
1754 if ((oipt
= register_opaque_info_per_type(functab
, lsa
))
1757 "ospf_opaque_lsa_reoriginate_schedule:"
1758 " Cannot get a control info?: lsa_type(%u),"
1760 lsa_type
, opaque_type
);
1765 if (oipt
->t_opaque_lsa_self
!= NULL
) {
1766 if (IS_DEBUG_OSPF_EVENT
)
1768 "Type-%u Opaque-LSA has already scheduled to"
1769 " RE-ORIGINATE: [opaque-type=%u]",
1771 GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
)));
1776 * Different from initial origination time, in which various conditions
1777 * (opaque capability, neighbor status etc) are assured by caller of
1778 * the originating function "ospf_opaque_lsa_originate_schedule ()",
1779 * it is highly possible that these conditions might not be satisfied
1780 * at the time of re-origination function is to be called.
1782 delay
= top
->min_ls_interval
; /* XXX */
1784 if (IS_DEBUG_OSPF_EVENT
)
1786 "Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d"
1787 " ms later: [opaque-type=%u]",
1789 GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
)));
1791 OSPF_OPAQUE_TIMER_ON(oipt
->t_opaque_lsa_self
, func
, oipt
, delay
* 1000);
1797 static struct ospf_lsa
*pseudo_lsa(struct ospf_interface
*oi
,
1798 struct ospf_area
*area
, u_char lsa_type
,
1801 static struct ospf_lsa lsa
= {0};
1802 static struct lsa_header lsah
= {0};
1808 lsa
.vrf_id
= VRF_DEFAULT
;
1810 lsah
.type
= lsa_type
;
1811 tmp
= SET_OPAQUE_LSID(opaque_type
, 0); /* Opaque-ID is unused here. */
1812 lsah
.id
.s_addr
= htonl(tmp
);
1817 static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread
*t
)
1819 struct opaque_info_per_type
*oipt
;
1820 struct ospf_opaque_functab
*functab
;
1822 struct ospf_interface
*oi
;
1825 oipt
= THREAD_ARG(t
);
1826 oipt
->t_opaque_lsa_self
= NULL
;
1828 if ((functab
= oipt
->functab
) == NULL
1829 || functab
->lsa_originator
== NULL
) {
1831 "ospf_opaque_type9_lsa_reoriginate_timer: No associated function?");
1835 oi
= (struct ospf_interface
*)oipt
->owner
;
1836 if ((top
= oi_to_top(oi
)) == NULL
) {
1838 "ospf_opaque_type9_lsa_reoriginate_timer: Something wrong?");
1842 if (!CHECK_FLAG(top
->config
, OSPF_OPAQUE_CAPABLE
)
1843 || !ospf_if_is_enable(oi
)
1844 || ospf_nbr_count_opaque_capable(oi
) == 0) {
1845 if (IS_DEBUG_OSPF_EVENT
)
1847 "Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...",
1850 oipt
->status
= PROC_SUSPEND
;
1855 if (IS_DEBUG_OSPF_EVENT
)
1857 "Timer[Type9-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for OI (%s)",
1858 oipt
->opaque_type
, IF_NAME(oi
));
1860 rc
= (*functab
->lsa_originator
)(oi
);
1865 static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread
*t
)
1867 struct opaque_info_per_type
*oipt
;
1868 struct ospf_opaque_functab
*functab
;
1869 struct listnode
*node
, *nnode
;
1871 struct ospf_area
*area
;
1872 struct ospf_interface
*oi
;
1875 oipt
= THREAD_ARG(t
);
1876 oipt
->t_opaque_lsa_self
= NULL
;
1878 if ((functab
= oipt
->functab
) == NULL
1879 || functab
->lsa_originator
== NULL
) {
1881 "ospf_opaque_type10_lsa_reoriginate_timer: No associated function?");
1885 area
= (struct ospf_area
*)oipt
->owner
;
1886 if (area
== NULL
|| (top
= area
->ospf
) == NULL
) {
1888 "ospf_opaque_type10_lsa_reoriginate_timer: Something wrong?");
1892 /* There must be at least one "opaque-capable, full-state" neighbor. */
1894 for (ALL_LIST_ELEMENTS(area
->oiflist
, node
, nnode
, oi
)) {
1895 if ((n
= ospf_nbr_count_opaque_capable(oi
)) > 0)
1899 if (n
== 0 || !CHECK_FLAG(top
->config
, OSPF_OPAQUE_CAPABLE
)) {
1900 if (IS_DEBUG_OSPF_EVENT
)
1902 "Suspend re-origination of Type-10 Opaque-LSAs"
1903 " (opaque-type=%u) for a while...",
1906 oipt
->status
= PROC_SUSPEND
;
1911 if (IS_DEBUG_OSPF_EVENT
)
1913 "Timer[Type10-LSA]: Re-originate Opaque-LSAs"
1914 " (opaque-type=%u) for Area %s",
1915 oipt
->opaque_type
, inet_ntoa(area
->area_id
));
1917 rc
= (*functab
->lsa_originator
)(area
);
1922 static int ospf_opaque_type11_lsa_reoriginate_timer(struct thread
*t
)
1924 struct opaque_info_per_type
*oipt
;
1925 struct ospf_opaque_functab
*functab
;
1929 oipt
= THREAD_ARG(t
);
1930 oipt
->t_opaque_lsa_self
= NULL
;
1932 if ((functab
= oipt
->functab
) == NULL
1933 || functab
->lsa_originator
== NULL
) {
1935 "ospf_opaque_type11_lsa_reoriginate_timer:"
1936 " No associated function?");
1940 if ((top
= (struct ospf
*)oipt
->owner
) == NULL
) {
1942 "ospf_opaque_type11_lsa_reoriginate_timer: Something wrong?");
1946 if (!CHECK_FLAG(top
->config
, OSPF_OPAQUE_CAPABLE
)) {
1947 if (IS_DEBUG_OSPF_EVENT
)
1949 "Suspend re-origination of Type-11 Opaque-LSAs (opaque-type=%u) for a while...",
1952 oipt
->status
= PROC_SUSPEND
;
1957 if (IS_DEBUG_OSPF_EVENT
)
1959 "Timer[Type11-LSA]: Re-originate Opaque-LSAs (opaque-type=%u).",
1962 rc
= (*functab
->lsa_originator
)(top
);
1967 void ospf_opaque_lsa_refresh_schedule(struct ospf_lsa
*lsa0
)
1969 struct opaque_info_per_type
*oipt
;
1970 struct opaque_info_per_id
*oipi
;
1971 struct ospf_lsa
*lsa
;
1975 if ((oipt
= lookup_opaque_info_by_type(lsa0
)) == NULL
1976 || (oipi
= lookup_opaque_info_by_id(oipt
, lsa0
)) == NULL
) {
1978 "ospf_opaque_lsa_refresh_schedule: Invalid parameter?");
1982 /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
1983 if ((lsa
= oipi
->lsa
) == NULL
) {
1984 zlog_warn("ospf_opaque_lsa_refresh_schedule: Something wrong?");
1988 if (oipi
->t_opaque_lsa_self
!= NULL
) {
1989 if (IS_DEBUG_OSPF_EVENT
)
1991 "Type-%u Opaque-LSA has already scheduled to REFRESH: [opaque-type=%u, opaque-id=%x]",
1993 GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
)),
1994 GET_OPAQUE_ID(ntohl(lsa
->data
->id
.s_addr
)));
1998 /* Delete this lsa from neighbor retransmit-list. */
1999 switch (lsa
->data
->type
) {
2000 case OSPF_OPAQUE_LINK_LSA
:
2001 case OSPF_OPAQUE_AREA_LSA
:
2002 ospf_ls_retransmit_delete_nbr_area(lsa
->area
, lsa
);
2004 case OSPF_OPAQUE_AS_LSA
:
2005 top
= ospf_lookup_by_vrf_id(lsa0
->vrf_id
);
2006 if ((lsa0
->area
!= NULL
) && (lsa0
->area
->ospf
!= NULL
))
2007 top
= lsa0
->area
->ospf
;
2008 ospf_ls_retransmit_delete_nbr_as(top
, lsa
);
2012 "ospf_opaque_lsa_refresh_schedule: Unexpected LSA-type(%u)",
2017 delay
= ospf_lsa_refresh_delay(lsa
);
2019 if (IS_DEBUG_OSPF_EVENT
)
2021 "Schedule Type-%u Opaque-LSA to REFRESH in %d sec later: [opaque-type=%u, opaque-id=%x]",
2022 lsa
->data
->type
, delay
,
2023 GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
)),
2024 GET_OPAQUE_ID(ntohl(lsa
->data
->id
.s_addr
)));
2026 OSPF_OPAQUE_TIMER_ON(oipi
->t_opaque_lsa_self
,
2027 ospf_opaque_lsa_refresh_timer
, oipi
, delay
* 1000);
2032 static int ospf_opaque_lsa_refresh_timer(struct thread
*t
)
2034 struct opaque_info_per_id
*oipi
;
2035 struct ospf_opaque_functab
*functab
;
2036 struct ospf_lsa
*lsa
;
2038 if (IS_DEBUG_OSPF_EVENT
)
2039 zlog_debug("Timer[Opaque-LSA]: (Opaque-LSA Refresh expire)");
2041 oipi
= THREAD_ARG(t
);
2042 oipi
->t_opaque_lsa_self
= NULL
;
2044 if ((lsa
= oipi
->lsa
) != NULL
)
2045 if ((functab
= oipi
->opqctl_type
->functab
) != NULL
)
2046 if (functab
->lsa_refresher
!= NULL
)
2047 (*functab
->lsa_refresher
)(lsa
);
2052 void ospf_opaque_lsa_flush_schedule(struct ospf_lsa
*lsa0
)
2054 struct opaque_info_per_type
*oipt
;
2055 struct opaque_info_per_id
*oipi
;
2056 struct ospf_lsa
*lsa
;
2059 top
= ospf_lookup_by_vrf_id(lsa0
->vrf_id
);
2061 if ((oipt
= lookup_opaque_info_by_type(lsa0
)) == NULL
2062 || (oipi
= lookup_opaque_info_by_id(oipt
, lsa0
)) == NULL
) {
2063 zlog_warn("ospf_opaque_lsa_flush_schedule: Invalid parameter?");
2067 /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */
2068 if ((lsa
= oipi
->lsa
) == NULL
) {
2069 zlog_warn("ospf_opaque_lsa_flush_schedule: Something wrong?");
2073 /* Delete this lsa from neighbor retransmit-list. */
2074 switch (lsa
->data
->type
) {
2075 case OSPF_OPAQUE_LINK_LSA
:
2076 case OSPF_OPAQUE_AREA_LSA
:
2077 ospf_ls_retransmit_delete_nbr_area(lsa
->area
, lsa
);
2079 case OSPF_OPAQUE_AS_LSA
:
2080 if ((lsa0
->area
!= NULL
) && (lsa0
->area
->ospf
!= NULL
))
2081 top
= lsa0
->area
->ospf
;
2082 ospf_ls_retransmit_delete_nbr_as(top
, lsa
);
2086 "ospf_opaque_lsa_flush_schedule: Unexpected LSA-type(%u)",
2091 /* Dequeue listnode entry from the list. */
2092 listnode_delete(oipt
->id_list
, oipi
);
2094 /* Avoid misjudgement in the next lookup. */
2095 if (listcount(oipt
->id_list
) == 0)
2096 oipt
->id_list
->head
= oipt
->id_list
->tail
= NULL
;
2098 /* Disassociate internal control information with the given lsa. */
2099 free_opaque_info_per_id((void *)oipi
);
2101 /* Force given lsa's age to MaxAge. */
2102 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
2104 if (IS_DEBUG_OSPF_EVENT
)
2106 "Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]",
2108 GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
)),
2109 GET_OPAQUE_ID(ntohl(lsa
->data
->id
.s_addr
)));
2111 /* This lsa will be flushed and removed eventually. */
2112 ospf_lsa_flush(top
, lsa
);
2118 void ospf_opaque_self_originated_lsa_received(struct ospf_neighbor
*nbr
,
2119 struct ospf_lsa
*lsa
)
2123 if ((top
= oi_to_top(nbr
->oi
)) == NULL
)
2127 * Since these LSA entries are not yet installed into corresponding
2128 * LSDB, just flush them without calling ospf_ls_maxage() afterward.
2130 lsa
->data
->ls_age
= htons(OSPF_LSA_MAXAGE
);
2131 switch (lsa
->data
->type
) {
2132 case OSPF_OPAQUE_LINK_LSA
:
2133 ospf_flood_through_area(nbr
->oi
->area
, NULL
/*inbr*/, lsa
);
2135 case OSPF_OPAQUE_AREA_LSA
:
2136 ospf_flood_through_area(nbr
->oi
->area
, NULL
/*inbr*/, lsa
);
2138 case OSPF_OPAQUE_AS_LSA
:
2139 ospf_flood_through_as(top
, NULL
/*inbr*/, lsa
);
2143 "ospf_opaque_self_originated_lsa_received: Unexpected LSA-type(%u)",
2147 ospf_lsa_discard(lsa
); /* List "lsas" will be deleted by caller. */
2150 /*------------------------------------------------------------------------*
2151 * Followings are util functions; probably be used by Opaque-LSAs only...
2152 *------------------------------------------------------------------------*/
2154 struct ospf
*oi_to_top(struct ospf_interface
*oi
)
2156 struct ospf
*top
= NULL
;
2157 struct ospf_area
*area
;
2159 if (oi
== NULL
|| (area
= oi
->area
) == NULL
2160 || (top
= area
->ospf
) == NULL
)
2161 zlog_warn("Broken relationship for \"OI -> AREA -> OSPF\"?");