2 * Server side of OSPF API.
3 * Copyright (C) 2001, 2002 Ralph Keller
5 * This file is part of GNU Zebra.
7 * GNU Zebra is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation; either version 2, or (at your
10 * option) any later version.
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #ifdef SUPPORT_OSPF_API
37 #include "sockunion.h" /* for inet_aton() */
40 #include <sys/types.h>
42 #include "ospfd/ospfd.h" /* for "struct thread_master" */
43 #include "ospfd/ospf_interface.h"
44 #include "ospfd/ospf_ism.h"
45 #include "ospfd/ospf_asbr.h"
46 #include "ospfd/ospf_lsa.h"
47 #include "ospfd/ospf_lsdb.h"
48 #include "ospfd/ospf_neighbor.h"
49 #include "ospfd/ospf_nsm.h"
50 #include "ospfd/ospf_flood.h"
51 #include "ospfd/ospf_packet.h"
52 #include "ospfd/ospf_spf.h"
53 #include "ospfd/ospf_dump.h"
54 #include "ospfd/ospf_route.h"
55 #include "ospfd/ospf_ase.h"
56 #include "ospfd/ospf_zebra.h"
58 #include "ospfd/ospf_api.h"
59 #include "ospfd/ospf_apiserver.h"
61 /* This is an implementation of an API to the OSPF daemon that allows
62 * external applications to access the OSPF daemon through socket
63 * connections. The application can use this API to inject its own
64 * opaque LSAs and flood them to other OSPF daemons. Other OSPF
65 * daemons then receive these LSAs and inform applications through the
66 * API by sending a corresponding message. The application can also
67 * register to receive all LSA types (in addition to opaque types) and
68 * use this information to reconstruct the OSPF's LSDB. The OSPF
69 * daemon supports multiple applications concurrently. */
71 /* List of all active connections. */
72 struct list
*apiserver_list
;
74 /* -----------------------------------------------------------
75 * Functions to lookup interfaces
76 * -----------------------------------------------------------
79 struct ospf_interface
*ospf_apiserver_if_lookup_by_addr(struct in_addr address
)
81 struct listnode
*node
, *nnode
;
82 struct ospf_interface
*oi
;
85 if (!(ospf
= ospf_lookup()))
88 for (ALL_LIST_ELEMENTS(ospf
->oiflist
, node
, nnode
, oi
))
89 if (oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
)
90 if (IPV4_ADDR_SAME(&address
, &oi
->address
->u
.prefix4
))
96 struct ospf_interface
*ospf_apiserver_if_lookup_by_ifp(struct interface
*ifp
)
98 struct listnode
*node
, *nnode
;
99 struct ospf_interface
*oi
;
102 if (!(ospf
= ospf_lookup()))
105 for (ALL_LIST_ELEMENTS(ospf
->oiflist
, node
, nnode
, oi
))
112 /* -----------------------------------------------------------
114 * -----------------------------------------------------------
117 unsigned short ospf_apiserver_getport(void)
119 struct servent
*sp
= getservbyname("ospfapi", "tcp");
121 return sp
? ntohs(sp
->s_port
) : OSPF_API_SYNC_PORT
;
124 /* Initialize OSPF API module. Invoked from ospf_opaque_init() */
125 int ospf_apiserver_init(void)
130 /* Create new socket for synchronous messages. */
131 fd
= ospf_apiserver_serv_sock_family(ospf_apiserver_getport(), AF_INET
);
136 /* Schedule new thread that handles accepted connections. */
137 ospf_apiserver_event(OSPF_APISERVER_ACCEPT
, fd
, NULL
);
139 /* Initialize list that keeps track of all connections. */
140 apiserver_list
= list_new();
142 /* Register opaque-independent call back functions. These functions
143 are invoked on ISM, NSM changes and LSA update and LSA deletes */
144 rc
= ospf_register_opaque_functab(
145 0 /* all LSAs */, 0 /* all opaque types */,
146 ospf_apiserver_new_if
, ospf_apiserver_del_if
,
147 ospf_apiserver_ism_change
, ospf_apiserver_nsm_change
, NULL
,
148 NULL
, NULL
, NULL
, /* ospf_apiserver_show_info */
149 NULL
, /* originator_func */
150 NULL
, /* ospf_apiserver_lsa_refresher */
151 ospf_apiserver_lsa_update
, ospf_apiserver_lsa_delete
);
154 "ospf_apiserver_init: Failed to register opaque type [0/0]");
163 /* Terminate OSPF API module. */
164 void ospf_apiserver_term(void)
166 struct ospf_apiserver
*apiserv
;
168 /* Unregister wildcard [0/0] type */
169 ospf_delete_opaque_functab(0 /* all LSAs */, 0 /* all opaque types */);
172 * Free all client instances. ospf_apiserver_free removes the node
173 * from the list, so we examine the head of the list anew each time.
175 while (apiserver_list
176 && (apiserv
= listgetdata(listhead(apiserver_list
))) != NULL
)
177 ospf_apiserver_free(apiserv
);
179 /* Free client list itself */
181 list_delete(apiserver_list
);
183 /* Free wildcard list */
187 static struct ospf_apiserver
*lookup_apiserver(u_char lsa_type
,
190 struct listnode
*n1
, *n2
;
191 struct registered_opaque_type
*r
;
192 struct ospf_apiserver
*apiserv
, *found
= NULL
;
194 /* XXX: this approaches O(n**2) */
195 for (ALL_LIST_ELEMENTS_RO(apiserver_list
, n1
, apiserv
)) {
196 for (ALL_LIST_ELEMENTS_RO(apiserv
->opaque_types
, n2
, r
))
197 if (r
->lsa_type
== lsa_type
198 && r
->opaque_type
== opaque_type
) {
207 static struct ospf_apiserver
*lookup_apiserver_by_lsa(struct ospf_lsa
*lsa
)
209 struct lsa_header
*lsah
= lsa
->data
;
210 struct ospf_apiserver
*found
= NULL
;
212 if (IS_OPAQUE_LSA(lsah
->type
)) {
213 found
= lookup_apiserver(
214 lsah
->type
, GET_OPAQUE_TYPE(ntohl(lsah
->id
.s_addr
)));
219 /* -----------------------------------------------------------
220 * Followings are functions to manage client connections.
221 * -----------------------------------------------------------
223 static int ospf_apiserver_new_lsa_hook(struct ospf_lsa
*lsa
)
225 if (IS_DEBUG_OSPF_EVENT
)
226 zlog_debug("API: Put LSA(%p)[%s] into reserve, total=%ld",
227 (void *)lsa
, dump_lsa_key(lsa
), lsa
->lsdb
->total
);
231 static int ospf_apiserver_del_lsa_hook(struct ospf_lsa
*lsa
)
233 if (IS_DEBUG_OSPF_EVENT
)
234 zlog_debug("API: Get LSA(%p)[%s] from reserve, total=%ld",
235 (void *)lsa
, dump_lsa_key(lsa
), lsa
->lsdb
->total
);
239 /* Allocate new connection structure. */
240 struct ospf_apiserver
*ospf_apiserver_new(int fd_sync
, int fd_async
)
242 struct ospf_apiserver
*new =
243 XMALLOC(MTYPE_OSPF_APISERVER
, sizeof(struct ospf_apiserver
));
245 new->filter
= XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER
,
246 sizeof(struct lsa_filter_type
));
248 new->fd_sync
= fd_sync
;
249 new->fd_async
= fd_async
;
251 /* list of registered opaque types that application uses */
252 new->opaque_types
= list_new();
254 /* Initialize temporary strage for LSA instances to be refreshed. */
255 memset(&new->reserve
, 0, sizeof(struct ospf_lsdb
));
256 ospf_lsdb_init(&new->reserve
);
258 new->reserve
.new_lsa_hook
= ospf_apiserver_new_lsa_hook
; /* debug */
259 new->reserve
.del_lsa_hook
= ospf_apiserver_del_lsa_hook
; /* debug */
261 new->out_sync_fifo
= msg_fifo_new();
262 new->out_async_fifo
= msg_fifo_new();
263 new->t_sync_read
= NULL
;
264 #ifdef USE_ASYNC_READ
265 new->t_async_read
= NULL
;
266 #endif /* USE_ASYNC_READ */
267 new->t_sync_write
= NULL
;
268 new->t_async_write
= NULL
;
270 new->filter
->typemask
= 0; /* filter all LSAs */
271 new->filter
->origin
= ANY_ORIGIN
;
272 new->filter
->num_areas
= 0;
277 void ospf_apiserver_event(enum event event
, int fd
,
278 struct ospf_apiserver
*apiserv
)
281 case OSPF_APISERVER_ACCEPT
:
282 (void)thread_add_read(master
, ospf_apiserver_accept
, apiserv
,
285 case OSPF_APISERVER_SYNC_READ
:
286 apiserv
->t_sync_read
= NULL
;
287 thread_add_read(master
, ospf_apiserver_read
, apiserv
, fd
,
288 &apiserv
->t_sync_read
);
290 #ifdef USE_ASYNC_READ
291 case OSPF_APISERVER_ASYNC_READ
:
292 apiserv
->t_async_read
= NULL
;
293 thread_add_read(master
, ospf_apiserver_read
, apiserv
, fd
,
294 &apiserv
->t_async_read
);
296 #endif /* USE_ASYNC_READ */
297 case OSPF_APISERVER_SYNC_WRITE
:
298 thread_add_write(master
, ospf_apiserver_sync_write
, apiserv
, fd
,
299 &apiserv
->t_sync_write
);
301 case OSPF_APISERVER_ASYNC_WRITE
:
302 thread_add_write(master
, ospf_apiserver_async_write
, apiserv
,
303 fd
, &apiserv
->t_async_write
);
308 /* Free instance. First unregister all opaque types used by
309 application, flush opaque LSAs injected by application
310 from network and close connection. */
311 void ospf_apiserver_free(struct ospf_apiserver
*apiserv
)
313 struct listnode
*node
;
315 /* Cancel read and write threads. */
316 if (apiserv
->t_sync_read
) {
317 thread_cancel(apiserv
->t_sync_read
);
319 #ifdef USE_ASYNC_READ
320 if (apiserv
->t_async_read
) {
321 thread_cancel(apiserv
->t_async_read
);
323 #endif /* USE_ASYNC_READ */
324 if (apiserv
->t_sync_write
) {
325 thread_cancel(apiserv
->t_sync_write
);
328 if (apiserv
->t_async_write
) {
329 thread_cancel(apiserv
->t_async_write
);
332 /* Unregister all opaque types that application registered
333 and flush opaque LSAs if still in LSDB. */
335 while ((node
= listhead(apiserv
->opaque_types
)) != NULL
) {
336 struct registered_opaque_type
*regtype
= listgetdata(node
);
338 ospf_apiserver_unregister_opaque_type(
339 apiserv
, regtype
->lsa_type
, regtype
->opaque_type
);
342 /* Close connections to OSPFd. */
343 if (apiserv
->fd_sync
> 0) {
344 close(apiserv
->fd_sync
);
347 if (apiserv
->fd_async
> 0) {
348 close(apiserv
->fd_async
);
352 msg_fifo_free(apiserv
->out_sync_fifo
);
353 msg_fifo_free(apiserv
->out_async_fifo
);
355 /* Clear temporary strage for LSA instances to be refreshed. */
356 ospf_lsdb_delete_all(&apiserv
->reserve
);
357 ospf_lsdb_cleanup(&apiserv
->reserve
);
359 /* Remove from the list of active clients. */
360 listnode_delete(apiserver_list
, apiserv
);
362 if (IS_DEBUG_OSPF_EVENT
)
363 zlog_debug("API: Delete apiserv(%p), total#(%d)",
364 (void *)apiserv
, apiserver_list
->count
);
366 /* And free instance. */
367 XFREE(MTYPE_OSPF_APISERVER
, apiserv
);
370 int ospf_apiserver_read(struct thread
*thread
)
372 struct ospf_apiserver
*apiserv
;
378 apiserv
= THREAD_ARG(thread
);
379 fd
= THREAD_FD(thread
);
381 if (fd
== apiserv
->fd_sync
) {
382 event
= OSPF_APISERVER_SYNC_READ
;
383 apiserv
->t_sync_read
= NULL
;
385 if (IS_DEBUG_OSPF_EVENT
)
386 zlog_debug("API: ospf_apiserver_read: Peer: %s/%u",
387 inet_ntoa(apiserv
->peer_sync
.sin_addr
),
388 ntohs(apiserv
->peer_sync
.sin_port
));
390 #ifdef USE_ASYNC_READ
391 else if (fd
== apiserv
->fd_async
) {
392 event
= OSPF_APISERVER_ASYNC_READ
;
393 apiserv
->t_async_read
= NULL
;
395 if (IS_DEBUG_OSPF_EVENT
)
396 zlog_debug("API: ospf_apiserver_read: Peer: %s/%u",
397 inet_ntoa(apiserv
->peer_async
.sin_addr
),
398 ntohs(apiserv
->peer_async
.sin_port
));
400 #endif /* USE_ASYNC_READ */
402 zlog_warn("ospf_apiserver_read: Unknown fd(%d)", fd
);
403 ospf_apiserver_free(apiserv
);
407 /* Read message from fd. */
411 "ospf_apiserver_read: read failed on fd=%d, closing connection",
414 /* Perform cleanup. */
415 ospf_apiserver_free(apiserv
);
419 if (IS_DEBUG_OSPF_EVENT
)
422 /* Dispatch to corresponding message handler. */
423 rc
= ospf_apiserver_handle_msg(apiserv
, msg
);
425 /* Prepare for next message, add read thread. */
426 ospf_apiserver_event(event
, fd
, apiserv
);
434 int ospf_apiserver_sync_write(struct thread
*thread
)
436 struct ospf_apiserver
*apiserv
;
441 apiserv
= THREAD_ARG(thread
);
443 fd
= THREAD_FD(thread
);
445 apiserv
->t_sync_write
= NULL
;
448 if (fd
!= apiserv
->fd_sync
) {
449 zlog_warn("ospf_apiserver_sync_write: Unknown fd=%d", fd
);
453 if (IS_DEBUG_OSPF_EVENT
)
454 zlog_debug("API: ospf_apiserver_sync_write: Peer: %s/%u",
455 inet_ntoa(apiserv
->peer_sync
.sin_addr
),
456 ntohs(apiserv
->peer_sync
.sin_port
));
458 /* Check whether there is really a message in the fifo. */
459 msg
= msg_fifo_pop(apiserv
->out_sync_fifo
);
462 "API: ospf_apiserver_sync_write: No message in Sync-FIFO?");
466 if (IS_DEBUG_OSPF_EVENT
)
469 rc
= msg_write(fd
, msg
);
471 /* Once a message is dequeued, it should be freed anyway. */
475 zlog_warn("ospf_apiserver_sync_write: write failed on fd=%d",
481 /* If more messages are in sync message fifo, schedule write thread. */
482 if (msg_fifo_head(apiserv
->out_sync_fifo
)) {
483 ospf_apiserver_event(OSPF_APISERVER_SYNC_WRITE
,
484 apiserv
->fd_sync
, apiserv
);
490 /* Perform cleanup and disconnect with peer */
491 ospf_apiserver_free(apiserv
);
498 int ospf_apiserver_async_write(struct thread
*thread
)
500 struct ospf_apiserver
*apiserv
;
505 apiserv
= THREAD_ARG(thread
);
507 fd
= THREAD_FD(thread
);
509 apiserv
->t_async_write
= NULL
;
512 if (fd
!= apiserv
->fd_async
) {
513 zlog_warn("ospf_apiserver_async_write: Unknown fd=%d", fd
);
517 if (IS_DEBUG_OSPF_EVENT
)
518 zlog_debug("API: ospf_apiserver_async_write: Peer: %s/%u",
519 inet_ntoa(apiserv
->peer_async
.sin_addr
),
520 ntohs(apiserv
->peer_async
.sin_port
));
522 /* Check whether there is really a message in the fifo. */
523 msg
= msg_fifo_pop(apiserv
->out_async_fifo
);
526 "API: ospf_apiserver_async_write: No message in Async-FIFO?");
530 if (IS_DEBUG_OSPF_EVENT
)
533 rc
= msg_write(fd
, msg
);
535 /* Once a message is dequeued, it should be freed anyway. */
539 zlog_warn("ospf_apiserver_async_write: write failed on fd=%d",
545 /* If more messages are in async message fifo, schedule write thread. */
546 if (msg_fifo_head(apiserv
->out_async_fifo
)) {
547 ospf_apiserver_event(OSPF_APISERVER_ASYNC_WRITE
,
548 apiserv
->fd_async
, apiserv
);
554 /* Perform cleanup and disconnect with peer */
555 ospf_apiserver_free(apiserv
);
562 int ospf_apiserver_serv_sock_family(unsigned short port
, int family
)
568 memset(&su
, 0, sizeof(union sockunion
));
569 su
.sa
.sa_family
= family
;
571 /* Make new socket */
572 accept_sock
= sockunion_stream_socket(&su
);
576 /* This is a server, so reuse address and port */
577 sockopt_reuseaddr(accept_sock
);
578 sockopt_reuseport(accept_sock
);
580 /* Bind socket to address and given port. */
581 rc
= sockunion_bind(accept_sock
, &su
, port
, NULL
);
583 close(accept_sock
); /* Close socket */
587 /* Listen socket under queue length 3. */
588 rc
= listen(accept_sock
, 3);
590 zlog_warn("ospf_apiserver_serv_sock_family: listen: %s",
591 safe_strerror(errno
));
592 close(accept_sock
); /* Close socket */
599 /* Accept connection request from external applications. For each
600 accepted connection allocate own connection instance. */
601 int ospf_apiserver_accept(struct thread
*thread
)
607 struct ospf_apiserver
*apiserv
;
608 struct sockaddr_in peer_async
;
609 struct sockaddr_in peer_sync
;
610 unsigned int peerlen
;
613 /* THREAD_ARG (thread) is NULL */
614 accept_sock
= THREAD_FD(thread
);
616 /* Keep hearing on socket for further connections. */
617 ospf_apiserver_event(OSPF_APISERVER_ACCEPT
, accept_sock
, NULL
);
619 memset(&su
, 0, sizeof(union sockunion
));
620 /* Accept connection for synchronous messages */
621 new_sync_sock
= sockunion_accept(accept_sock
, &su
);
622 if (new_sync_sock
< 0) {
623 zlog_warn("ospf_apiserver_accept: accept: %s",
624 safe_strerror(errno
));
628 /* Get port address and port number of peer to make reverse connection.
629 The reverse channel uses the port number of the peer port+1. */
631 memset(&peer_sync
, 0, sizeof(struct sockaddr_in
));
632 peerlen
= sizeof(struct sockaddr_in
);
634 ret
= getpeername(new_sync_sock
, (struct sockaddr
*)&peer_sync
,
637 zlog_warn("ospf_apiserver_accept: getpeername: %s",
638 safe_strerror(errno
));
639 close(new_sync_sock
);
643 if (IS_DEBUG_OSPF_EVENT
)
644 zlog_debug("API: ospf_apiserver_accept: New peer: %s/%u",
645 inet_ntoa(peer_sync
.sin_addr
),
646 ntohs(peer_sync
.sin_port
));
648 /* Create new socket for asynchronous messages. */
649 peer_async
= peer_sync
;
650 peer_async
.sin_port
= htons(ntohs(peer_sync
.sin_port
) + 1);
652 /* Check if remote port number to make reverse connection is valid one.
654 if (ntohs(peer_async
.sin_port
) == ospf_apiserver_getport()) {
656 "API: ospf_apiserver_accept: Peer(%s/%u): Invalid async port number?",
657 inet_ntoa(peer_async
.sin_addr
),
658 ntohs(peer_async
.sin_port
));
659 close(new_sync_sock
);
663 new_async_sock
= socket(AF_INET
, SOCK_STREAM
, 0);
664 if (new_async_sock
< 0) {
665 zlog_warn("ospf_apiserver_accept: socket: %s",
666 safe_strerror(errno
));
667 close(new_sync_sock
);
671 ret
= connect(new_async_sock
, (struct sockaddr
*)&peer_async
,
672 sizeof(struct sockaddr_in
));
675 zlog_warn("ospf_apiserver_accept: connect: %s",
676 safe_strerror(errno
));
677 close(new_sync_sock
);
678 close(new_async_sock
);
682 #ifdef USE_ASYNC_READ
683 #else /* USE_ASYNC_READ */
684 /* Make the asynchronous channel write-only. */
685 ret
= shutdown(new_async_sock
, SHUT_RD
);
687 zlog_warn("ospf_apiserver_accept: shutdown: %s",
688 safe_strerror(errno
));
689 close(new_sync_sock
);
690 close(new_async_sock
);
693 #endif /* USE_ASYNC_READ */
695 /* Allocate new server-side connection structure */
696 apiserv
= ospf_apiserver_new(new_sync_sock
, new_async_sock
);
698 /* Add to active connection list */
699 listnode_add(apiserver_list
, apiserv
);
700 apiserv
->peer_sync
= peer_sync
;
701 apiserv
->peer_async
= peer_async
;
703 /* And add read threads for new connection */
704 ospf_apiserver_event(OSPF_APISERVER_SYNC_READ
, new_sync_sock
, apiserv
);
705 #ifdef USE_ASYNC_READ
706 ospf_apiserver_event(OSPF_APISERVER_ASYNC_READ
, new_async_sock
,
708 #endif /* USE_ASYNC_READ */
710 if (IS_DEBUG_OSPF_EVENT
)
711 zlog_debug("API: New apiserv(%p), total#(%d)", (void *)apiserv
,
712 apiserver_list
->count
);
718 /* -----------------------------------------------------------
719 * Send reply with return code to client application
720 * -----------------------------------------------------------
723 static int ospf_apiserver_send_msg(struct ospf_apiserver
*apiserv
,
726 struct msg_fifo
*fifo
;
731 switch (msg
->hdr
.msgtype
) {
733 fifo
= apiserv
->out_sync_fifo
;
734 fd
= apiserv
->fd_sync
;
735 event
= OSPF_APISERVER_SYNC_WRITE
;
737 case MSG_READY_NOTIFY
:
738 case MSG_LSA_UPDATE_NOTIFY
:
739 case MSG_LSA_DELETE_NOTIFY
:
744 fifo
= apiserv
->out_async_fifo
;
745 fd
= apiserv
->fd_async
;
746 event
= OSPF_APISERVER_ASYNC_WRITE
;
749 zlog_warn("ospf_apiserver_send_msg: Unknown message type %d",
754 /* Make a copy of the message and put in the fifo. Once the fifo
755 gets drained by the write thread, the message will be freed. */
756 /* NB: Given "msg" is untouched in this function. */
759 /* Enqueue message into corresponding fifo queue */
760 msg_fifo_push(fifo
, msg2
);
762 /* Schedule write thread */
763 ospf_apiserver_event(event
, fd
, apiserv
);
767 int ospf_apiserver_send_reply(struct ospf_apiserver
*apiserv
, u_int32_t seqnr
,
770 struct msg
*msg
= new_msg_reply(seqnr
, rc
);
774 zlog_warn("ospf_apiserver_send_reply: msg_new failed");
776 /* Cannot allocate new message. What should we do? */
777 ospf_apiserver_free(apiserv
);
782 ret
= ospf_apiserver_send_msg(apiserv
, msg
);
788 /* -----------------------------------------------------------
789 * Generic message dispatching handler function
790 * -----------------------------------------------------------
793 int ospf_apiserver_handle_msg(struct ospf_apiserver
*apiserv
, struct msg
*msg
)
797 /* Call corresponding message handler function. */
798 switch (msg
->hdr
.msgtype
) {
799 case MSG_REGISTER_OPAQUETYPE
:
800 rc
= ospf_apiserver_handle_register_opaque_type(apiserv
, msg
);
802 case MSG_UNREGISTER_OPAQUETYPE
:
803 rc
= ospf_apiserver_handle_unregister_opaque_type(apiserv
, msg
);
805 case MSG_REGISTER_EVENT
:
806 rc
= ospf_apiserver_handle_register_event(apiserv
, msg
);
809 rc
= ospf_apiserver_handle_sync_lsdb(apiserv
, msg
);
811 case MSG_ORIGINATE_REQUEST
:
812 rc
= ospf_apiserver_handle_originate_request(apiserv
, msg
);
814 case MSG_DELETE_REQUEST
:
815 rc
= ospf_apiserver_handle_delete_request(apiserv
, msg
);
818 zlog_warn("ospf_apiserver_handle_msg: Unknown message type: %d",
826 /* -----------------------------------------------------------
827 * Following are functions for opaque type registration
828 * -----------------------------------------------------------
831 int ospf_apiserver_register_opaque_type(struct ospf_apiserver
*apiserv
,
832 u_char lsa_type
, u_char opaque_type
)
834 struct registered_opaque_type
*regtype
;
835 int (*originator_func
)(void *arg
);
839 case OSPF_OPAQUE_LINK_LSA
:
840 originator_func
= ospf_apiserver_lsa9_originator
;
842 case OSPF_OPAQUE_AREA_LSA
:
843 originator_func
= ospf_apiserver_lsa10_originator
;
845 case OSPF_OPAQUE_AS_LSA
:
846 originator_func
= ospf_apiserver_lsa11_originator
;
849 zlog_warn("ospf_apiserver_register_opaque_type: lsa_type(%d)",
851 return OSPF_API_ILLEGALLSATYPE
;
855 /* Register opaque function table */
856 /* NB: Duplicated registration will be detected inside the function. */
857 rc
= ospf_register_opaque_functab(
858 lsa_type
, opaque_type
, NULL
, /* ospf_apiserver_new_if */
859 NULL
, /* ospf_apiserver_del_if */
860 NULL
, /* ospf_apiserver_ism_change */
861 NULL
, /* ospf_apiserver_nsm_change */
862 NULL
, NULL
, NULL
, ospf_apiserver_show_info
, originator_func
,
863 ospf_apiserver_lsa_refresher
,
864 NULL
, /* ospf_apiserver_lsa_update */
865 NULL
/* ospf_apiserver_lsa_delete */);
868 zlog_warn("Failed to register opaque type [%d/%d]", lsa_type
,
870 return OSPF_API_OPAQUETYPEINUSE
;
873 /* Remember the opaque type that application registers so when
874 connection shuts down, we can flush all LSAs of this opaque
877 regtype
= XCALLOC(MTYPE_OSPF_APISERVER
,
878 sizeof(struct registered_opaque_type
));
879 regtype
->lsa_type
= lsa_type
;
880 regtype
->opaque_type
= opaque_type
;
882 /* Add to list of registered opaque types */
883 listnode_add(apiserv
->opaque_types
, regtype
);
885 if (IS_DEBUG_OSPF_EVENT
)
887 "API: Add LSA-type(%d)/Opaque-type(%d) into"
888 " apiserv(%p), total#(%d)",
889 lsa_type
, opaque_type
, (void *)apiserv
,
890 listcount(apiserv
->opaque_types
));
895 int ospf_apiserver_unregister_opaque_type(struct ospf_apiserver
*apiserv
,
896 u_char lsa_type
, u_char opaque_type
)
898 struct listnode
*node
, *nnode
;
899 struct registered_opaque_type
*regtype
;
901 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node
, nnode
, regtype
)) {
902 /* Check if we really registered this opaque type */
903 if (regtype
->lsa_type
== lsa_type
904 && regtype
->opaque_type
== opaque_type
) {
906 /* Yes, we registered this opaque type. Flush
907 all existing opaque LSAs of this type */
909 ospf_apiserver_flush_opaque_lsa(apiserv
, lsa_type
,
911 ospf_delete_opaque_functab(lsa_type
, opaque_type
);
913 /* Remove from list of registered opaque types */
914 listnode_delete(apiserv
->opaque_types
, regtype
);
916 if (IS_DEBUG_OSPF_EVENT
)
918 "API: Del LSA-type(%d)/Opaque-type(%d)"
919 " from apiserv(%p), total#(%d)",
920 lsa_type
, opaque_type
, (void *)apiserv
,
921 listcount(apiserv
->opaque_types
));
927 /* Opaque type is not registered */
928 zlog_warn("Failed to unregister opaque type [%d/%d]", lsa_type
,
930 return OSPF_API_OPAQUETYPENOTREGISTERED
;
934 static int apiserver_is_opaque_type_registered(struct ospf_apiserver
*apiserv
,
938 struct listnode
*node
, *nnode
;
939 struct registered_opaque_type
*regtype
;
941 /* XXX: how many types are there? if few, why not just a bitmap? */
942 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node
, nnode
, regtype
)) {
943 /* Check if we really registered this opaque type */
944 if (regtype
->lsa_type
== lsa_type
945 && regtype
->opaque_type
== opaque_type
) {
954 int ospf_apiserver_handle_register_opaque_type(struct ospf_apiserver
*apiserv
,
957 struct msg_register_opaque_type
*rmsg
;
962 /* Extract parameters from register opaque type message */
963 rmsg
= (struct msg_register_opaque_type
*)STREAM_DATA(msg
->s
);
965 lsa_type
= rmsg
->lsatype
;
966 opaque_type
= rmsg
->opaquetype
;
968 rc
= ospf_apiserver_register_opaque_type(apiserv
, lsa_type
,
971 /* Send a reply back to client including return code */
972 rc
= ospf_apiserver_send_reply(apiserv
, ntohl(msg
->hdr
.msgseq
), rc
);
976 /* Now inform application about opaque types that are ready */
978 case OSPF_OPAQUE_LINK_LSA
:
979 ospf_apiserver_notify_ready_type9(apiserv
);
981 case OSPF_OPAQUE_AREA_LSA
:
982 ospf_apiserver_notify_ready_type10(apiserv
);
984 case OSPF_OPAQUE_AS_LSA
:
985 ospf_apiserver_notify_ready_type11(apiserv
);
993 /* Notify specific client about all opaque types 9 that are ready. */
994 void ospf_apiserver_notify_ready_type9(struct ospf_apiserver
*apiserv
)
996 struct listnode
*node
, *nnode
;
997 struct listnode
*node2
, *nnode2
;
999 struct ospf_interface
*oi
;
1000 struct registered_opaque_type
*r
;
1002 ospf
= ospf_lookup();
1004 for (ALL_LIST_ELEMENTS(ospf
->oiflist
, node
, nnode
, oi
)) {
1005 /* Check if this interface is indeed ready for type 9 */
1006 if (!ospf_apiserver_is_ready_type9(oi
))
1009 /* Check for registered opaque type 9 types */
1010 /* XXX: loop-de-loop - optimise me */
1011 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node2
, nnode2
,
1015 if (r
->lsa_type
== OSPF_OPAQUE_LINK_LSA
) {
1017 /* Yes, this opaque type is ready */
1018 msg
= new_msg_ready_notify(
1019 0, OSPF_OPAQUE_LINK_LSA
, r
->opaque_type
,
1020 oi
->address
->u
.prefix4
);
1023 "apiserver_notify_ready_type9: msg_new failed");
1025 /* Cannot allocate new message. What
1027 ospf_apiserver_free(apiserv
);
1031 ospf_apiserver_send_msg(apiserv
, msg
);
1042 /* Notify specific client about all opaque types 10 that are ready. */
1043 void ospf_apiserver_notify_ready_type10(struct ospf_apiserver
*apiserv
)
1045 struct listnode
*node
, *nnode
;
1046 struct listnode
*node2
, *nnode2
;
1048 struct ospf_area
*area
;
1050 ospf
= ospf_lookup();
1052 for (ALL_LIST_ELEMENTS(ospf
->areas
, node
, nnode
, area
)) {
1053 struct registered_opaque_type
*r
;
1055 if (!ospf_apiserver_is_ready_type10(area
)) {
1059 /* Check for registered opaque type 10 types */
1060 /* XXX: loop in loop - optimise me */
1061 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node2
, nnode2
,
1065 if (r
->lsa_type
== OSPF_OPAQUE_AREA_LSA
) {
1066 /* Yes, this opaque type is ready */
1067 msg
= new_msg_ready_notify(
1068 0, OSPF_OPAQUE_AREA_LSA
, r
->opaque_type
,
1072 "apiserver_notify_ready_type10: msg_new failed");
1074 /* Cannot allocate new message. What
1076 ospf_apiserver_free(apiserv
);
1080 ospf_apiserver_send_msg(apiserv
, msg
);
1090 /* Notify specific client about all opaque types 11 that are ready */
1091 void ospf_apiserver_notify_ready_type11(struct ospf_apiserver
*apiserv
)
1093 struct listnode
*node
, *nnode
;
1095 struct registered_opaque_type
*r
;
1097 ospf
= ospf_lookup();
1099 /* Can type 11 be originated? */
1100 if (!ospf_apiserver_is_ready_type11(ospf
))
1103 /* Check for registered opaque type 11 types */
1104 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node
, nnode
, r
)) {
1106 struct in_addr noarea_id
= {.s_addr
= 0L};
1108 if (r
->lsa_type
== OSPF_OPAQUE_AS_LSA
) {
1109 /* Yes, this opaque type is ready */
1110 msg
= new_msg_ready_notify(0, OSPF_OPAQUE_AS_LSA
,
1111 r
->opaque_type
, noarea_id
);
1115 "apiserver_notify_ready_type11: msg_new failed");
1117 /* Cannot allocate new message. What should we
1119 ospf_apiserver_free(apiserv
);
1123 ospf_apiserver_send_msg(apiserv
, msg
);
1132 int ospf_apiserver_handle_unregister_opaque_type(struct ospf_apiserver
*apiserv
,
1135 struct msg_unregister_opaque_type
*umsg
;
1140 /* Extract parameters from unregister opaque type message */
1141 umsg
= (struct msg_unregister_opaque_type
*)STREAM_DATA(msg
->s
);
1143 ltype
= umsg
->lsatype
;
1144 otype
= umsg
->opaquetype
;
1146 rc
= ospf_apiserver_unregister_opaque_type(apiserv
, ltype
, otype
);
1148 /* Send a reply back to client including return code */
1149 rc
= ospf_apiserver_send_reply(apiserv
, ntohl(msg
->hdr
.msgseq
), rc
);
1155 /* -----------------------------------------------------------
1156 * Following are functions for event (filter) registration.
1157 * -----------------------------------------------------------
1159 int ospf_apiserver_handle_register_event(struct ospf_apiserver
*apiserv
,
1162 struct msg_register_event
*rmsg
;
1166 rmsg
= (struct msg_register_event
*)STREAM_DATA(msg
->s
);
1168 /* Get request sequence number */
1169 seqnum
= msg_get_seq(msg
);
1171 /* Free existing filter in apiserv. */
1172 XFREE(MTYPE_OSPF_APISERVER_MSGFILTER
, apiserv
->filter
);
1173 /* Alloc new space for filter. */
1176 XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER
, ntohs(msg
->hdr
.msglen
));
1177 if (apiserv
->filter
) {
1179 memcpy(apiserv
->filter
, &rmsg
->filter
, ntohs(msg
->hdr
.msglen
));
1182 rc
= OSPF_API_NOMEMORY
;
1184 /* Send a reply back to client with return code */
1185 rc
= ospf_apiserver_send_reply(apiserv
, seqnum
, rc
);
1190 /* -----------------------------------------------------------
1191 * Followings are functions for LSDB synchronization.
1192 * -----------------------------------------------------------
1195 static int apiserver_sync_callback(struct ospf_lsa
*lsa
, void *p_arg
,
1198 struct ospf_apiserver
*apiserv
;
1202 struct ospf_apiserver
*apiserv
;
1203 struct lsa_filter_type
*filter
;
1211 param
= (struct param_t
*)p_arg
;
1212 apiserv
= param
->apiserv
;
1213 seqnum
= (u_int32_t
)int_arg
;
1215 /* Check origin in filter. */
1216 if ((param
->filter
->origin
== ANY_ORIGIN
)
1217 || (param
->filter
->origin
== (lsa
->flags
& OSPF_LSA_SELF
))) {
1219 /* Default area for AS-External and Opaque11 LSAs */
1220 struct in_addr area_id
= {.s_addr
= 0L};
1222 /* Default interface for non Opaque9 LSAs */
1223 struct in_addr ifaddr
= {.s_addr
= 0L};
1226 area_id
= lsa
->area
->area_id
;
1228 if (lsa
->data
->type
== OSPF_OPAQUE_LINK_LSA
) {
1229 ifaddr
= lsa
->oi
->address
->u
.prefix4
;
1232 msg
= new_msg_lsa_change_notify(
1233 MSG_LSA_UPDATE_NOTIFY
, seqnum
, ifaddr
, area_id
,
1234 lsa
->flags
& OSPF_LSA_SELF
, lsa
->data
);
1237 "apiserver_sync_callback: new_msg_update failed");
1239 /* Cannot allocate new message. What should we do? */
1240 /* ospf_apiserver_free (apiserv);*/ /* Do nothing
1248 ospf_apiserver_send_msg(apiserv
, msg
);
1257 int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver
*apiserv
,
1260 struct listnode
*node
, *nnode
;
1263 struct msg_sync_lsdb
*smsg
;
1264 struct ospf_apiserver_param_t
{
1265 struct ospf_apiserver
*apiserv
;
1266 struct lsa_filter_type
*filter
;
1269 struct route_node
*rn
;
1270 struct ospf_lsa
*lsa
;
1272 struct ospf_area
*area
;
1274 ospf
= ospf_lookup();
1276 /* Get request sequence number */
1277 seqnum
= msg_get_seq(msg
);
1279 smsg
= (struct msg_sync_lsdb
*)STREAM_DATA(msg
->s
);
1281 /* Set parameter struct. */
1282 param
.apiserv
= apiserv
;
1283 param
.filter
= &smsg
->filter
;
1285 /* Remember mask. */
1286 mask
= ntohs(smsg
->filter
.typemask
);
1288 /* Iterate over all areas. */
1289 for (ALL_LIST_ELEMENTS(ospf
->areas
, node
, nnode
, area
)) {
1291 u_int32_t
*area_id
= NULL
;
1293 /* Compare area_id with area_ids in sync request. */
1294 if ((i
= smsg
->filter
.num_areas
) > 0) {
1295 /* Let area_id point to the list of area IDs,
1296 * which is at the end of smsg->filter. */
1297 area_id
= (u_int32_t
*)(&smsg
->filter
+ 1);
1299 if (*area_id
== area
->area_id
.s_addr
) {
1309 /* If area was found, then i>0 here. */
1311 /* Check msg type. */
1312 if (mask
& Power2
[OSPF_ROUTER_LSA
])
1313 LSDB_LOOP(ROUTER_LSDB(area
), rn
, lsa
)
1314 apiserver_sync_callback(lsa
, (void *)¶m
, seqnum
);
1315 if (mask
& Power2
[OSPF_NETWORK_LSA
])
1316 LSDB_LOOP(NETWORK_LSDB(area
), rn
, lsa
)
1317 apiserver_sync_callback(lsa
, (void *)¶m
, seqnum
);
1318 if (mask
& Power2
[OSPF_SUMMARY_LSA
])
1319 LSDB_LOOP(SUMMARY_LSDB(area
), rn
, lsa
)
1320 apiserver_sync_callback(lsa
, (void *)¶m
, seqnum
);
1321 if (mask
& Power2
[OSPF_ASBR_SUMMARY_LSA
])
1322 LSDB_LOOP(ASBR_SUMMARY_LSDB(area
), rn
, lsa
)
1323 apiserver_sync_callback(lsa
, (void *)¶m
, seqnum
);
1324 if (mask
& Power2
[OSPF_OPAQUE_LINK_LSA
])
1325 LSDB_LOOP(OPAQUE_LINK_LSDB(area
), rn
, lsa
)
1326 apiserver_sync_callback(lsa
, (void *)¶m
, seqnum
);
1327 if (mask
& Power2
[OSPF_OPAQUE_AREA_LSA
])
1328 LSDB_LOOP(OPAQUE_AREA_LSDB(area
), rn
, lsa
)
1329 apiserver_sync_callback(lsa
, (void *)¶m
, seqnum
);
1333 /* For AS-external LSAs */
1335 if (mask
& Power2
[OSPF_AS_EXTERNAL_LSA
])
1336 LSDB_LOOP(EXTERNAL_LSDB(ospf
), rn
, lsa
)
1337 apiserver_sync_callback(lsa
, (void *)¶m
, seqnum
);
1340 /* For AS-external opaque LSAs */
1342 if (mask
& Power2
[OSPF_OPAQUE_AS_LSA
])
1343 LSDB_LOOP(OPAQUE_AS_LSDB(ospf
), rn
, lsa
)
1344 apiserver_sync_callback(lsa
, (void *)¶m
, seqnum
);
1347 /* Send a reply back to client with return code */
1348 rc
= ospf_apiserver_send_reply(apiserv
, seqnum
, rc
);
1353 /* -----------------------------------------------------------
1354 * Followings are functions to originate or update LSA
1355 * from an application.
1356 * -----------------------------------------------------------
1359 /* Create a new internal opaque LSA by taking prototype and filling in
1360 missing fields such as age, sequence number, advertising router,
1361 checksum and so on. The interface parameter is used for type 9
1362 LSAs, area parameter for type 10. Type 11 LSAs do neither need area
1365 struct ospf_lsa
*ospf_apiserver_opaque_lsa_new(struct ospf_area
*area
,
1366 struct ospf_interface
*oi
,
1367 struct lsa_header
*protolsa
)
1370 struct lsa_header
*newlsa
;
1371 struct ospf_lsa
*new = NULL
;
1372 u_char options
= 0x0;
1377 ospf
= ospf_lookup();
1380 /* Create a stream for internal opaque LSA */
1381 if ((s
= stream_new(OSPF_MAX_LSA_SIZE
)) == NULL
) {
1382 zlog_warn("ospf_apiserver_opaque_lsa_new: stream_new failed");
1386 newlsa
= (struct lsa_header
*)STREAM_DATA(s
);
1388 /* XXX If this is a link-local LSA or an AS-external LSA, how do we
1389 have to set options? */
1392 options
= LSA_OPTIONS_GET(area
);
1393 options
|= LSA_OPTIONS_NSSA_GET(area
);
1396 options
|= OSPF_OPTION_O
; /* Don't forget to set option bit */
1398 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
)) {
1399 zlog_debug("LSA[Type%d:%s]: Creating an Opaque-LSA instance",
1400 protolsa
->type
, inet_ntoa(protolsa
->id
));
1403 /* Set opaque-LSA header fields. */
1404 lsa_header_set(s
, options
, protolsa
->type
, protolsa
->id
,
1407 /* Set opaque-LSA body fields. */
1408 stream_put(s
, ((u_char
*)protolsa
) + sizeof(struct lsa_header
),
1409 ntohs(protolsa
->length
) - sizeof(struct lsa_header
));
1411 /* Determine length of LSA. */
1412 length
= stream_get_endp(s
);
1413 newlsa
->length
= htons(length
);
1415 /* Create OSPF LSA. */
1416 if ((new = ospf_lsa_new()) == NULL
) {
1417 zlog_warn("ospf_apiserver_opaque_lsa_new: ospf_lsa_new() ?");
1422 if ((new->data
= ospf_lsa_data_new(length
)) == NULL
) {
1424 "ospf_apiserver_opaque_lsa_new: ospf_lsa_data_new() ?");
1425 ospf_lsa_unlock(&new);
1433 SET_FLAG(new->flags
, OSPF_LSA_SELF
);
1434 memcpy(new->data
, newlsa
, length
);
1441 int ospf_apiserver_is_ready_type9(struct ospf_interface
*oi
)
1443 /* Type 9 opaque LSA can be originated if there is at least one
1444 active opaque-capable neighbor attached to the outgoing
1447 return (ospf_nbr_count_opaque_capable(oi
) > 0);
1450 int ospf_apiserver_is_ready_type10(struct ospf_area
*area
)
1452 /* Type 10 opaque LSA can be originated if there is at least one
1453 interface belonging to the area that has an active opaque-capable
1455 struct listnode
*node
, *nnode
;
1456 struct ospf_interface
*oi
;
1458 for (ALL_LIST_ELEMENTS(area
->oiflist
, node
, nnode
, oi
))
1459 /* Is there an active neighbor attached to this interface? */
1460 if (ospf_apiserver_is_ready_type9(oi
))
1463 /* No active neighbor in area */
1467 int ospf_apiserver_is_ready_type11(struct ospf
*ospf
)
1469 /* Type 11 opaque LSA can be originated if there is at least one
1471 that has an active opaque-capable neighbor. */
1472 struct listnode
*node
, *nnode
;
1473 struct ospf_interface
*oi
;
1475 for (ALL_LIST_ELEMENTS(ospf
->oiflist
, node
, nnode
, oi
))
1476 /* Is there an active neighbor attached to this interface? */
1477 if (ospf_apiserver_is_ready_type9(oi
))
1480 /* No active neighbor at all */
1485 int ospf_apiserver_handle_originate_request(struct ospf_apiserver
*apiserv
,
1488 struct msg_originate_request
*omsg
;
1489 struct lsa_header
*data
;
1490 struct ospf_lsa
*new;
1491 struct ospf_lsa
*old
;
1492 struct ospf_area
*area
= NULL
;
1493 struct ospf_interface
*oi
= NULL
;
1494 struct ospf_lsdb
*lsdb
= NULL
;
1496 int lsa_type
, opaque_type
;
1500 ospf
= ospf_lookup();
1502 /* Extract opaque LSA data from message */
1503 omsg
= (struct msg_originate_request
*)STREAM_DATA(msg
->s
);
1506 /* Determine interface for type9 or area for type10 LSAs. */
1507 switch (data
->type
) {
1508 case OSPF_OPAQUE_LINK_LSA
:
1509 oi
= ospf_apiserver_if_lookup_by_addr(omsg
->ifaddr
);
1511 zlog_warn("apiserver_originate: unknown interface %s",
1512 inet_ntoa(omsg
->ifaddr
));
1513 rc
= OSPF_API_NOSUCHINTERFACE
;
1519 case OSPF_OPAQUE_AREA_LSA
:
1520 area
= ospf_area_lookup_by_area_id(ospf
, omsg
->area_id
);
1522 zlog_warn("apiserver_originate: unknown area %s",
1523 inet_ntoa(omsg
->area_id
));
1524 rc
= OSPF_API_NOSUCHAREA
;
1529 case OSPF_OPAQUE_AS_LSA
:
1533 /* We can only handle opaque types here */
1535 "apiserver_originate: Cannot originate non-opaque LSA type %d",
1537 rc
= OSPF_API_ILLEGALLSATYPE
;
1541 /* Check if we registered this opaque type */
1542 lsa_type
= data
->type
;
1543 opaque_type
= GET_OPAQUE_TYPE(ntohl(data
->id
.s_addr
));
1545 if (!apiserver_is_opaque_type_registered(apiserv
, lsa_type
,
1548 "apiserver_originate: LSA-type(%d)/Opaque-type(%d): Not registered",
1549 lsa_type
, opaque_type
);
1550 rc
= OSPF_API_OPAQUETYPENOTREGISTERED
;
1554 /* Make sure that the neighbors are ready before we can originate */
1555 switch (data
->type
) {
1556 case OSPF_OPAQUE_LINK_LSA
:
1557 ready
= ospf_apiserver_is_ready_type9(oi
);
1559 case OSPF_OPAQUE_AREA_LSA
:
1560 ready
= ospf_apiserver_is_ready_type10(area
);
1562 case OSPF_OPAQUE_AS_LSA
:
1563 ready
= ospf_apiserver_is_ready_type11(ospf
);
1570 zlog_warn("Neighbors not ready to originate type %d",
1572 rc
= OSPF_API_NOTREADY
;
1576 /* Create OSPF's internal opaque LSA representation */
1577 new = ospf_apiserver_opaque_lsa_new(area
, oi
, data
);
1579 rc
= OSPF_API_NOMEMORY
; /* XXX */
1583 /* Determine if LSA is new or an update for an existing one. */
1584 old
= ospf_lsdb_lookup(lsdb
, new);
1587 /* New LSA install in LSDB. */
1588 rc
= ospf_apiserver_originate1(new);
1591 * Keep the new LSA instance in the "waiting place" until the
1593 * refresh timing. If several LSA update requests for the same
1595 * have issued by peer, the last one takes effect.
1597 new->lsdb
= &apiserv
->reserve
;
1598 ospf_lsdb_add(&apiserv
->reserve
, new);
1600 /* Kick the scheduler function. */
1601 ospf_opaque_lsa_refresh_schedule(old
);
1606 /* Send a reply back to client with return code */
1607 rc
= ospf_apiserver_send_reply(apiserv
, ntohl(msg
->hdr
.msgseq
), rc
);
1612 /* -----------------------------------------------------------
1613 * Flood an LSA within its flooding scope.
1614 * -----------------------------------------------------------
1617 /* XXX We can probably use ospf_flood_through instead of this function
1618 but then we need the neighbor parameter. If we set nbr to
1619 NULL then ospf_flood_through crashes due to dereferencing NULL. */
1621 void ospf_apiserver_flood_opaque_lsa(struct ospf_lsa
*lsa
)
1625 switch (lsa
->data
->type
) {
1626 case OSPF_OPAQUE_LINK_LSA
:
1627 /* Increment counters? XXX */
1629 /* Flood LSA through local network. */
1630 ospf_flood_through_area(lsa
->area
, NULL
/*nbr */, lsa
);
1632 case OSPF_OPAQUE_AREA_LSA
:
1633 /* Update LSA origination count. */
1635 lsa
->area
->ospf
->lsa_originate_count
++;
1637 /* Flood LSA through area. */
1638 ospf_flood_through_area(lsa
->area
, NULL
/*nbr */, lsa
);
1640 case OSPF_OPAQUE_AS_LSA
: {
1643 ospf
= ospf_lookup();
1646 /* Increment counters? XXX */
1648 /* Flood LSA through AS. */
1649 ospf_flood_through_as(ospf
, NULL
/*nbr */, lsa
);
1655 int ospf_apiserver_originate1(struct ospf_lsa
*lsa
)
1659 ospf
= ospf_lookup();
1662 /* Install this LSA into LSDB. */
1663 if (ospf_lsa_install(ospf
, lsa
->oi
, lsa
) == NULL
) {
1664 zlog_warn("ospf_apiserver_originate1: ospf_lsa_install failed");
1668 /* Flood LSA within scope */
1672 * NB: Modified version of "ospf_flood_though ()" accepts NULL "inbr"
1673 * parameter, and thus it does not cause SIGSEGV error.
1675 ospf_flood_through(NULL
/*nbr */, lsa
);
1678 ospf_apiserver_flood_opaque_lsa(lsa
);
1685 /* Opaque LSAs of type 9 on a specific interface can now be
1686 originated. Tell clients that registered type 9. */
1687 int ospf_apiserver_lsa9_originator(void *arg
)
1689 struct ospf_interface
*oi
;
1691 oi
= (struct ospf_interface
*)arg
;
1692 if (listcount(apiserver_list
) > 0) {
1693 ospf_apiserver_clients_notify_ready_type9(oi
);
1698 int ospf_apiserver_lsa10_originator(void *arg
)
1700 struct ospf_area
*area
;
1702 area
= (struct ospf_area
*)arg
;
1703 if (listcount(apiserver_list
) > 0) {
1704 ospf_apiserver_clients_notify_ready_type10(area
);
1709 int ospf_apiserver_lsa11_originator(void *arg
)
1713 ospf
= (struct ospf
*)arg
;
1714 if (listcount(apiserver_list
) > 0) {
1715 ospf_apiserver_clients_notify_ready_type11(ospf
);
1721 /* Periodically refresh opaque LSAs so that they do not expire in
1723 struct ospf_lsa
*ospf_apiserver_lsa_refresher(struct ospf_lsa
*lsa
)
1725 struct ospf_apiserver
*apiserv
;
1726 struct ospf_lsa
*new = NULL
;
1729 ospf
= ospf_lookup();
1732 apiserv
= lookup_apiserver_by_lsa(lsa
);
1735 "ospf_apiserver_lsa_refresher: LSA[%s]: No apiserver?",
1738 htons(OSPF_LSA_MAXAGE
); /* Flush it anyway. */
1741 if (IS_LSA_MAXAGE(lsa
)) {
1742 ospf_opaque_lsa_flush_schedule(lsa
);
1746 /* Check if updated version of LSA instance has already prepared. */
1747 new = ospf_lsdb_lookup(&apiserv
->reserve
, lsa
);
1749 /* This is a periodic refresh, driven by core OSPF mechanism. */
1750 new = ospf_apiserver_opaque_lsa_new(lsa
->area
, lsa
->oi
,
1754 "ospf_apiserver_lsa_refresher: Cannot create a new LSA?");
1758 /* This is a forcible refresh, requested by OSPF-API client. */
1759 ospf_lsdb_delete(&apiserv
->reserve
, new);
1763 /* Increment sequence number */
1764 new->data
->ls_seqnum
= lsa_seqnum_increment(lsa
);
1766 /* New LSA is in same area. */
1767 new->area
= lsa
->area
;
1768 SET_FLAG(new->flags
, OSPF_LSA_SELF
);
1770 /* Install LSA into LSDB. */
1771 if (ospf_lsa_install(ospf
, new->oi
, new) == NULL
) {
1773 "ospf_apiserver_lsa_refresher: ospf_lsa_install failed");
1774 ospf_lsa_unlock(&new);
1778 /* Flood updated LSA through interface, area or AS */
1781 ospf_flood_through(NULL
/*nbr */, new);
1783 ospf_apiserver_flood_opaque_lsa(new);
1785 /* Debug logging. */
1786 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
)) {
1787 zlog_debug("LSA[Type%d:%s]: Refresh Opaque LSA",
1788 new->data
->type
, inet_ntoa(new->data
->id
));
1789 ospf_lsa_header_dump(new->data
);
1797 /* -----------------------------------------------------------
1798 * Followings are functions to delete LSAs
1799 * -----------------------------------------------------------
1802 int ospf_apiserver_handle_delete_request(struct ospf_apiserver
*apiserv
,
1805 struct msg_delete_request
*dmsg
;
1806 struct ospf_lsa
*old
;
1807 struct ospf_area
*area
= NULL
;
1809 int lsa_type
, opaque_type
;
1813 ospf
= ospf_lookup();
1816 /* Extract opaque LSA from message */
1817 dmsg
= (struct msg_delete_request
*)STREAM_DATA(msg
->s
);
1819 /* Lookup area for link-local and area-local opaque LSAs */
1820 switch (dmsg
->lsa_type
) {
1821 case OSPF_OPAQUE_LINK_LSA
:
1822 case OSPF_OPAQUE_AREA_LSA
:
1823 area
= ospf_area_lookup_by_area_id(ospf
, dmsg
->area_id
);
1825 zlog_warn("ospf_apiserver_lsa_delete: unknown area %s",
1826 inet_ntoa(dmsg
->area_id
));
1827 rc
= OSPF_API_NOSUCHAREA
;
1831 case OSPF_OPAQUE_AS_LSA
:
1832 /* AS-external opaque LSAs have no designated area */
1837 "ospf_apiserver_lsa_delete: Cannot delete non-opaque LSA type %d",
1839 rc
= OSPF_API_ILLEGALLSATYPE
;
1843 /* Check if we registered this opaque type */
1844 lsa_type
= dmsg
->lsa_type
;
1845 opaque_type
= dmsg
->opaque_type
;
1847 if (!apiserver_is_opaque_type_registered(apiserv
, lsa_type
,
1850 "ospf_apiserver_lsa_delete: LSA-type(%d)/Opaque-type(%d): Not registered",
1851 lsa_type
, opaque_type
);
1852 rc
= OSPF_API_OPAQUETYPENOTREGISTERED
;
1856 /* opaque_id is in network byte order */
1858 SET_OPAQUE_LSID(dmsg
->opaque_type
, ntohl(dmsg
->opaque_id
)));
1861 * Even if the target LSA has once scheduled to flush, it remains in
1862 * the LSDB until it is finally handled by the maxage remover thread.
1863 * Therefore, the lookup function below may return non-NULL result.
1865 old
= ospf_lsa_lookup(area
, dmsg
->lsa_type
, id
, ospf
->router_id
);
1868 "ospf_apiserver_lsa_delete: LSA[Type%d:%s] not in LSDB",
1869 dmsg
->lsa_type
, inet_ntoa(id
));
1870 rc
= OSPF_API_NOSUCHLSA
;
1874 /* Schedule flushing of LSA from LSDB */
1875 /* NB: Multiple scheduling will produce a warning message, but harmless.
1877 ospf_opaque_lsa_flush_schedule(old
);
1881 /* Send reply back to client including return code */
1882 rc
= ospf_apiserver_send_reply(apiserv
, ntohl(msg
->hdr
.msgseq
), rc
);
1886 /* Flush self-originated opaque LSA */
1887 static int apiserver_flush_opaque_type_callback(struct ospf_lsa
*lsa
,
1888 void *p_arg
, int int_arg
)
1891 struct ospf_apiserver
*apiserv
;
1899 param
= (struct param_t
*)p_arg
;
1901 /* If LSA matches type and opaque type then delete it */
1902 if (IS_LSA_SELF(lsa
) && lsa
->data
->type
== param
->lsa_type
1903 && GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
))
1904 == param
->opaque_type
) {
1905 ospf_opaque_lsa_flush_schedule(lsa
);
1910 /* Delete self-originated opaque LSAs of a given opaque type. This
1911 function is called when an application unregisters a given opaque
1912 type or a connection to an application closes and all those opaque
1913 LSAs need to be flushed the LSDB. */
1914 void ospf_apiserver_flush_opaque_lsa(struct ospf_apiserver
*apiserv
,
1915 u_char lsa_type
, u_char opaque_type
)
1918 struct ospf_apiserver
*apiserv
;
1922 struct listnode
*node
, *nnode
;
1924 struct ospf_area
*area
;
1926 ospf
= ospf_lookup();
1929 /* Set parameter struct. */
1930 param
.apiserv
= apiserv
;
1931 param
.lsa_type
= lsa_type
;
1932 param
.opaque_type
= opaque_type
;
1935 struct route_node
*rn
;
1936 struct ospf_lsa
*lsa
;
1938 case OSPF_OPAQUE_LINK_LSA
:
1939 for (ALL_LIST_ELEMENTS(ospf
->areas
, node
, nnode
, area
))
1940 LSDB_LOOP(OPAQUE_LINK_LSDB(area
), rn
, lsa
)
1941 apiserver_flush_opaque_type_callback(lsa
, (void *)¶m
, 0);
1943 case OSPF_OPAQUE_AREA_LSA
:
1944 for (ALL_LIST_ELEMENTS(ospf
->areas
, node
, nnode
, area
))
1945 LSDB_LOOP(OPAQUE_AREA_LSDB(area
), rn
, lsa
)
1946 apiserver_flush_opaque_type_callback(lsa
, (void *)¶m
, 0);
1948 case OSPF_OPAQUE_AS_LSA
:
1949 LSDB_LOOP(OPAQUE_LINK_LSDB(ospf
), rn
, lsa
)
1950 apiserver_flush_opaque_type_callback(lsa
, (void *)¶m
, 0);
1959 /* -----------------------------------------------------------
1960 * Followings are callback functions to handle opaque types
1961 * -----------------------------------------------------------
1964 int ospf_apiserver_new_if(struct interface
*ifp
)
1966 struct ospf_interface
*oi
;
1968 /* For some strange reason it seems possible that we are invoked
1969 with an interface that has no name. This seems to happen during
1970 initialization. Return if this happens */
1972 if (ifp
->name
[0] == '\0') {
1973 /* interface has empty name */
1974 zlog_warn("ospf_apiserver_new_if: interface has no name?");
1978 /* zlog_warn for debugging */
1979 zlog_warn("ospf_apiserver_new_if");
1980 zlog_warn("ifp name=%s status=%d index=%d", ifp
->name
, ifp
->status
,
1983 if (ifp
->name
[0] == '\0') {
1984 /* interface has empty name */
1985 zlog_warn("ospf_apiserver_new_if: interface has no name?");
1989 oi
= ospf_apiserver_if_lookup_by_ifp(ifp
);
1992 /* This interface is known to Zebra but not to OSPF daemon yet.
1995 "ospf_apiserver_new_if: interface %s not known to OSPFd?",
2002 /* New interface added to OSPF, tell clients about it */
2003 if (listcount(apiserver_list
) > 0) {
2004 ospf_apiserver_clients_notify_new_if(oi
);
2009 int ospf_apiserver_del_if(struct interface
*ifp
)
2011 struct ospf_interface
*oi
;
2013 /* zlog_warn for debugging */
2014 zlog_warn("ospf_apiserver_del_if");
2015 zlog_warn("ifp name=%s status=%d index=%d\n", ifp
->name
, ifp
->status
,
2018 oi
= ospf_apiserver_if_lookup_by_ifp(ifp
);
2021 /* This interface is known to Zebra but not to OSPF daemon
2022 anymore. No need to tell clients about it */
2026 /* Interface deleted, tell clients about it */
2027 if (listcount(apiserver_list
) > 0) {
2028 ospf_apiserver_clients_notify_del_if(oi
);
2033 void ospf_apiserver_ism_change(struct ospf_interface
*oi
, int old_state
)
2035 /* Tell clients about interface change */
2037 /* zlog_warn for debugging */
2038 zlog_warn("ospf_apiserver_ism_change");
2039 if (listcount(apiserver_list
) > 0) {
2040 ospf_apiserver_clients_notify_ism_change(oi
);
2043 zlog_warn("oi->ifp->name=%s", oi
->ifp
->name
);
2044 zlog_warn("old_state=%d", old_state
);
2045 zlog_warn("oi->state=%d", oi
->state
);
2048 void ospf_apiserver_nsm_change(struct ospf_neighbor
*nbr
, int old_status
)
2050 /* Neighbor status changed, tell clients about it */
2051 zlog_warn("ospf_apiserver_nsm_change");
2052 if (listcount(apiserver_list
) > 0) {
2053 ospf_apiserver_clients_notify_nsm_change(nbr
);
2057 void ospf_apiserver_show_info(struct vty
*vty
, struct ospf_lsa
*lsa
)
2060 struct lsa_header header
;
2061 u_char data
[1]; /* opaque data have variable length. This is
2065 struct opaque_lsa
*olsa
;
2068 olsa
= (struct opaque_lsa
*)lsa
->data
;
2070 if (VALID_OPAQUE_INFO_LEN(lsa
->data
))
2071 opaquelen
= ntohs(lsa
->data
->length
) - OSPF_LSA_HEADER_SIZE
;
2075 /* Output information about opaque LSAs */
2079 " Added using OSPF API: %u octets of opaque data %s\n",
2081 VALID_OPAQUE_INFO_LEN(lsa
->data
) ? ""
2082 : "(Invalid length?)");
2083 vty_out(vty
, " Opaque data: ");
2085 for (i
= 0; i
< opaquelen
; i
++) {
2086 vty_out(vty
, "0x%x ", olsa
->data
[i
]);
2092 " Added using OSPF API: %u octets of opaque data %s",
2094 VALID_OPAQUE_INFO_LEN(lsa
->data
) ? ""
2095 : "(Invalid length?)");
2096 zlog_debug(" Opaque data: ");
2098 for (i
= 0; i
< opaquelen
; i
++) {
2099 zlog_debug("0x%x ", olsa
->data
[i
]);
2106 /* -----------------------------------------------------------
2107 * Followings are functions to notify clients about events
2108 * -----------------------------------------------------------
2111 /* Send a message to all clients. This is useful for messages
2112 that need to be notified to all clients (such as interface
2115 void ospf_apiserver_clients_notify_all(struct msg
*msg
)
2117 struct listnode
*node
, *nnode
;
2118 struct ospf_apiserver
*apiserv
;
2120 /* Send message to all clients */
2121 for (ALL_LIST_ELEMENTS(apiserver_list
, node
, nnode
, apiserv
))
2122 ospf_apiserver_send_msg(apiserv
, msg
);
2125 /* An interface is now ready to accept opaque LSAs. Notify all
2126 clients that registered to use this opaque type */
2127 void ospf_apiserver_clients_notify_ready_type9(struct ospf_interface
*oi
)
2129 struct listnode
*node
, *nnode
;
2131 struct ospf_apiserver
*apiserv
;
2135 zlog_warn("Interface has no address?");
2139 if (!ospf_apiserver_is_ready_type9(oi
)) {
2140 zlog_warn("Interface not ready for type 9?");
2144 for (ALL_LIST_ELEMENTS(apiserver_list
, node
, nnode
, apiserv
)) {
2145 struct listnode
*node2
, *nnode2
;
2146 struct registered_opaque_type
*r
;
2148 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node2
, nnode2
,
2150 if (r
->lsa_type
== OSPF_OPAQUE_LINK_LSA
) {
2151 msg
= new_msg_ready_notify(
2152 0, OSPF_OPAQUE_LINK_LSA
, r
->opaque_type
,
2153 oi
->address
->u
.prefix4
);
2156 "ospf_apiserver_clients_notify_ready_type9: new_msg_ready_notify failed");
2158 /* Cannot allocate new message. What
2160 ospf_apiserver_free(apiserv
);
2165 ospf_apiserver_send_msg(apiserv
, msg
);
2175 void ospf_apiserver_clients_notify_ready_type10(struct ospf_area
*area
)
2177 struct listnode
*node
, *nnode
;
2179 struct ospf_apiserver
*apiserv
;
2183 if (!ospf_apiserver_is_ready_type10(area
)) {
2184 zlog_warn("Area not ready for type 10?");
2188 for (ALL_LIST_ELEMENTS(apiserver_list
, node
, nnode
, apiserv
)) {
2189 struct listnode
*node2
, *nnode2
;
2190 struct registered_opaque_type
*r
;
2192 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node2
, nnode2
,
2194 if (r
->lsa_type
== OSPF_OPAQUE_AREA_LSA
) {
2195 msg
= new_msg_ready_notify(
2196 0, OSPF_OPAQUE_AREA_LSA
, r
->opaque_type
,
2200 "ospf_apiserver_clients_notify_ready_type10: new_msg_ready_nofity failed");
2202 /* Cannot allocate new message. What
2204 ospf_apiserver_free(apiserv
);
2209 ospf_apiserver_send_msg(apiserv
, msg
);
2220 void ospf_apiserver_clients_notify_ready_type11(struct ospf
*top
)
2222 struct listnode
*node
, *nnode
;
2224 struct in_addr id_null
= {.s_addr
= 0L};
2225 struct ospf_apiserver
*apiserv
;
2229 if (!ospf_apiserver_is_ready_type11(top
)) {
2230 zlog_warn("AS not ready for type 11?");
2234 for (ALL_LIST_ELEMENTS(apiserver_list
, node
, nnode
, apiserv
)) {
2235 struct listnode
*node2
, *nnode2
;
2236 struct registered_opaque_type
*r
;
2238 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node2
, nnode2
,
2240 if (r
->lsa_type
== OSPF_OPAQUE_AS_LSA
) {
2241 msg
= new_msg_ready_notify(
2242 0, OSPF_OPAQUE_AS_LSA
, r
->opaque_type
,
2246 "ospf_apiserver_clients_notify_ready_type11: new_msg_ready_notify failed");
2248 /* Cannot allocate new message. What
2250 ospf_apiserver_free(apiserv
);
2255 ospf_apiserver_send_msg(apiserv
, msg
);
2265 void ospf_apiserver_clients_notify_new_if(struct ospf_interface
*oi
)
2269 msg
= new_msg_new_if(0, oi
->address
->u
.prefix4
, oi
->area
->area_id
);
2271 ospf_apiserver_clients_notify_all(msg
);
2276 void ospf_apiserver_clients_notify_del_if(struct ospf_interface
*oi
)
2280 msg
= new_msg_del_if(0, oi
->address
->u
.prefix4
);
2282 ospf_apiserver_clients_notify_all(msg
);
2287 void ospf_apiserver_clients_notify_ism_change(struct ospf_interface
*oi
)
2290 struct in_addr ifaddr
= {.s_addr
= 0L};
2291 struct in_addr area_id
= {.s_addr
= 0L};
2297 ifaddr
= oi
->address
->u
.prefix4
;
2300 area_id
= oi
->area
->area_id
;
2303 msg
= new_msg_ism_change(0, ifaddr
, area_id
, oi
->state
);
2306 "apiserver_clients_notify_ism_change: msg_new failed");
2310 ospf_apiserver_clients_notify_all(msg
);
2314 void ospf_apiserver_clients_notify_nsm_change(struct ospf_neighbor
*nbr
)
2317 struct in_addr ifaddr
= {.s_addr
= 0L};
2318 struct in_addr nbraddr
= {.s_addr
= 0L};
2323 ifaddr
= nbr
->oi
->address
->u
.prefix4
;
2326 nbraddr
= nbr
->address
.u
.prefix4
;
2328 msg
= new_msg_nsm_change(0, ifaddr
, nbraddr
, nbr
->router_id
,
2332 "apiserver_clients_notify_nsm_change: msg_new failed");
2336 ospf_apiserver_clients_notify_all(msg
);
2340 static void apiserver_clients_lsa_change_notify(u_char msgtype
,
2341 struct ospf_lsa
*lsa
)
2344 struct listnode
*node
, *nnode
;
2345 struct ospf_apiserver
*apiserv
;
2347 /* Default area for AS-External and Opaque11 LSAs */
2348 struct in_addr area_id
= {.s_addr
= 0L};
2350 /* Default interface for non Opaque9 LSAs */
2351 struct in_addr ifaddr
= {.s_addr
= 0L};
2354 area_id
= lsa
->area
->area_id
;
2356 if (lsa
->data
->type
== OSPF_OPAQUE_LINK_LSA
) {
2358 ifaddr
= lsa
->oi
->address
->u
.prefix4
;
2361 /* Prepare message that can be sent to clients that have a matching
2363 msg
= new_msg_lsa_change_notify(msgtype
, 0L, /* no sequence number */
2365 lsa
->flags
& OSPF_LSA_SELF
, lsa
->data
);
2368 "apiserver_clients_lsa_change_notify: msg_new failed");
2372 /* Now send message to all clients with a matching filter */
2373 for (ALL_LIST_ELEMENTS(apiserver_list
, node
, nnode
, apiserv
)) {
2374 struct lsa_filter_type
*filter
;
2379 /* Check filter for this client. */
2380 filter
= apiserv
->filter
;
2382 /* Check area IDs in case of non AS-E LSAs.
2383 * If filter has areas (num_areas > 0),
2384 * then one of the areas must match the area ID of this LSA. */
2386 i
= filter
->num_areas
;
2387 if ((lsa
->data
->type
== OSPF_AS_EXTERNAL_LSA
)
2388 || (lsa
->data
->type
== OSPF_OPAQUE_AS_LSA
)) {
2393 area
= (u_int32_t
*)(filter
+ 1);
2395 if (*area
== area_id
.s_addr
) {
2406 /* Area match. Check LSA type. */
2407 mask
= ntohs(filter
->typemask
);
2409 if (mask
& Power2
[lsa
->data
->type
]) {
2410 /* Type also matches. Check origin. */
2411 if ((filter
->origin
== ANY_ORIGIN
)
2412 || (filter
->origin
== IS_LSA_SELF(lsa
))) {
2413 ospf_apiserver_send_msg(apiserv
, msg
);
2418 /* Free message since it is not used anymore */
2423 /* -------------------------------------------------------------
2424 * Followings are hooks invoked when LSAs are updated or deleted
2425 * -------------------------------------------------------------
2429 static int apiserver_notify_clients_lsa(u_char msgtype
, struct ospf_lsa
*lsa
)
2432 /* default area for AS-External and Opaque11 LSAs */
2433 struct in_addr area_id
= {.s_addr
= 0L};
2435 /* default interface for non Opaque9 LSAs */
2436 struct in_addr ifaddr
= {.s_addr
= 0L};
2438 /* Only notify this update if the LSA's age is smaller than
2439 MAXAGE. Otherwise clients would see LSA updates with max age just
2440 before they are deleted from the LSDB. LSA delete messages have
2441 MAXAGE too but should not be filtered. */
2442 if (IS_LSA_MAXAGE(lsa
) && (msgtype
== MSG_LSA_UPDATE_NOTIFY
)) {
2447 area_id
= lsa
->area
->area_id
;
2449 if (lsa
->data
->type
== OSPF_OPAQUE_LINK_LSA
) {
2450 ifaddr
= lsa
->oi
->address
->u
.prefix4
;
2452 msg
= new_msg_lsa_change_notify(msgtype
, 0L, /* no sequence number */
2454 lsa
->flags
& OSPF_LSA_SELF
, lsa
->data
);
2456 zlog_warn("notify_clients_lsa: msg_new failed");
2459 /* Notify all clients that new LSA is added/updated */
2460 apiserver_clients_lsa_change_notify(msgtype
, lsa
);
2462 /* Clients made their own copies of msg so we can free msg here */
2468 int ospf_apiserver_lsa_update(struct ospf_lsa
*lsa
)
2470 return apiserver_notify_clients_lsa(MSG_LSA_UPDATE_NOTIFY
, lsa
);
2473 int ospf_apiserver_lsa_delete(struct ospf_lsa
*lsa
)
2475 return apiserver_notify_clients_lsa(MSG_LSA_DELETE_NOTIFY
, lsa
);
2478 #endif /* SUPPORT_OSPF_API */