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"
57 #include "ospfd/ospf_errors.h"
59 #include "ospfd/ospf_api.h"
60 #include "ospfd/ospf_apiserver.h"
62 /* This is an implementation of an API to the OSPF daemon that allows
63 * external applications to access the OSPF daemon through socket
64 * connections. The application can use this API to inject its own
65 * opaque LSAs and flood them to other OSPF daemons. Other OSPF
66 * daemons then receive these LSAs and inform applications through the
67 * API by sending a corresponding message. The application can also
68 * register to receive all LSA types (in addition to opaque types) and
69 * use this information to reconstruct the OSPF's LSDB. The OSPF
70 * daemon supports multiple applications concurrently. */
72 /* List of all active connections. */
73 struct list
*apiserver_list
;
75 /* -----------------------------------------------------------
76 * Functions to lookup interfaces
77 * -----------------------------------------------------------
80 struct ospf_interface
*ospf_apiserver_if_lookup_by_addr(struct in_addr address
)
82 struct listnode
*node
, *nnode
;
83 struct ospf_interface
*oi
;
84 struct ospf
*ospf
= NULL
;
86 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
90 for (ALL_LIST_ELEMENTS(ospf
->oiflist
, node
, nnode
, oi
))
91 if (oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
)
92 if (IPV4_ADDR_SAME(&address
, &oi
->address
->u
.prefix4
))
98 struct ospf_interface
*ospf_apiserver_if_lookup_by_ifp(struct interface
*ifp
)
100 struct listnode
*node
, *nnode
;
101 struct ospf_interface
*oi
;
102 struct ospf
*ospf
= NULL
;
104 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
108 for (ALL_LIST_ELEMENTS(ospf
->oiflist
, node
, nnode
, oi
))
115 /* -----------------------------------------------------------
117 * -----------------------------------------------------------
120 unsigned short ospf_apiserver_getport(void)
122 struct servent
*sp
= getservbyname("ospfapi", "tcp");
124 return sp
? ntohs(sp
->s_port
) : OSPF_API_SYNC_PORT
;
127 /* Initialize OSPF API module. Invoked from ospf_opaque_init() */
128 int ospf_apiserver_init(void)
133 /* Create new socket for synchronous messages. */
134 fd
= ospf_apiserver_serv_sock_family(ospf_apiserver_getport(), AF_INET
);
139 /* Schedule new thread that handles accepted connections. */
140 ospf_apiserver_event(OSPF_APISERVER_ACCEPT
, fd
, NULL
);
142 /* Initialize list that keeps track of all connections. */
143 apiserver_list
= list_new();
145 /* Register opaque-independent call back functions. These functions
146 are invoked on ISM, NSM changes and LSA update and LSA deletes */
147 rc
= ospf_register_opaque_functab(
148 0 /* all LSAs */, 0 /* all opaque types */,
149 ospf_apiserver_new_if
, ospf_apiserver_del_if
,
150 ospf_apiserver_ism_change
, ospf_apiserver_nsm_change
, NULL
,
151 NULL
, NULL
, NULL
, /* ospf_apiserver_show_info */
152 NULL
, /* originator_func */
153 NULL
, /* ospf_apiserver_lsa_refresher */
154 ospf_apiserver_lsa_update
, ospf_apiserver_lsa_delete
);
157 EC_OSPF_OPAQUE_REGISTRATION
,
158 "ospf_apiserver_init: Failed to register opaque type [0/0]");
167 /* Terminate OSPF API module. */
168 void ospf_apiserver_term(void)
170 struct ospf_apiserver
*apiserv
;
172 /* Unregister wildcard [0/0] type */
173 ospf_delete_opaque_functab(0 /* all LSAs */, 0 /* all opaque types */);
176 * Free all client instances. ospf_apiserver_free removes the node
177 * from the list, so we examine the head of the list anew each time.
179 while (apiserver_list
180 && (apiserv
= listgetdata(listhead(apiserver_list
))) != NULL
)
181 ospf_apiserver_free(apiserv
);
183 /* Free client list itself */
185 list_delete(&apiserver_list
);
187 /* Free wildcard list */
191 static struct ospf_apiserver
*lookup_apiserver(uint8_t lsa_type
,
194 struct listnode
*n1
, *n2
;
195 struct registered_opaque_type
*r
;
196 struct ospf_apiserver
*apiserv
, *found
= NULL
;
198 /* XXX: this approaches O(n**2) */
199 for (ALL_LIST_ELEMENTS_RO(apiserver_list
, n1
, apiserv
)) {
200 for (ALL_LIST_ELEMENTS_RO(apiserv
->opaque_types
, n2
, r
))
201 if (r
->lsa_type
== lsa_type
202 && r
->opaque_type
== opaque_type
) {
211 static struct ospf_apiserver
*lookup_apiserver_by_lsa(struct ospf_lsa
*lsa
)
213 struct lsa_header
*lsah
= lsa
->data
;
214 struct ospf_apiserver
*found
= NULL
;
216 if (IS_OPAQUE_LSA(lsah
->type
)) {
217 found
= lookup_apiserver(
218 lsah
->type
, GET_OPAQUE_TYPE(ntohl(lsah
->id
.s_addr
)));
223 /* -----------------------------------------------------------
224 * Followings are functions to manage client connections.
225 * -----------------------------------------------------------
227 static int ospf_apiserver_new_lsa_hook(struct ospf_lsa
*lsa
)
229 if (IS_DEBUG_OSPF_EVENT
)
230 zlog_debug("API: Put LSA(%p)[%s] into reserve, total=%ld",
231 (void *)lsa
, dump_lsa_key(lsa
), lsa
->lsdb
->total
);
235 static int ospf_apiserver_del_lsa_hook(struct ospf_lsa
*lsa
)
237 if (IS_DEBUG_OSPF_EVENT
)
238 zlog_debug("API: Get LSA(%p)[%s] from reserve, total=%ld",
239 (void *)lsa
, dump_lsa_key(lsa
), lsa
->lsdb
->total
);
243 /* Allocate new connection structure. */
244 struct ospf_apiserver
*ospf_apiserver_new(int fd_sync
, int fd_async
)
246 struct ospf_apiserver
*new =
247 XMALLOC(MTYPE_OSPF_APISERVER
, sizeof(struct ospf_apiserver
));
249 new->filter
= XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER
,
250 sizeof(struct lsa_filter_type
));
252 new->fd_sync
= fd_sync
;
253 new->fd_async
= fd_async
;
255 /* list of registered opaque types that application uses */
256 new->opaque_types
= list_new();
258 /* Initialize temporary strage for LSA instances to be refreshed. */
259 memset(&new->reserve
, 0, sizeof(struct ospf_lsdb
));
260 ospf_lsdb_init(&new->reserve
);
262 new->reserve
.new_lsa_hook
= ospf_apiserver_new_lsa_hook
; /* debug */
263 new->reserve
.del_lsa_hook
= ospf_apiserver_del_lsa_hook
; /* debug */
265 new->out_sync_fifo
= msg_fifo_new();
266 new->out_async_fifo
= msg_fifo_new();
267 new->t_sync_read
= NULL
;
268 #ifdef USE_ASYNC_READ
269 new->t_async_read
= NULL
;
270 #endif /* USE_ASYNC_READ */
271 new->t_sync_write
= NULL
;
272 new->t_async_write
= NULL
;
274 new->filter
->typemask
= 0; /* filter all LSAs */
275 new->filter
->origin
= ANY_ORIGIN
;
276 new->filter
->num_areas
= 0;
281 void ospf_apiserver_event(enum event event
, int fd
,
282 struct ospf_apiserver
*apiserv
)
285 case OSPF_APISERVER_ACCEPT
:
286 (void)thread_add_read(master
, ospf_apiserver_accept
, apiserv
,
289 case OSPF_APISERVER_SYNC_READ
:
290 apiserv
->t_sync_read
= NULL
;
291 thread_add_read(master
, ospf_apiserver_read
, apiserv
, fd
,
292 &apiserv
->t_sync_read
);
294 #ifdef USE_ASYNC_READ
295 case OSPF_APISERVER_ASYNC_READ
:
296 apiserv
->t_async_read
= NULL
;
297 thread_add_read(master
, ospf_apiserver_read
, apiserv
, fd
,
298 &apiserv
->t_async_read
);
300 #endif /* USE_ASYNC_READ */
301 case OSPF_APISERVER_SYNC_WRITE
:
302 thread_add_write(master
, ospf_apiserver_sync_write
, apiserv
, fd
,
303 &apiserv
->t_sync_write
);
305 case OSPF_APISERVER_ASYNC_WRITE
:
306 thread_add_write(master
, ospf_apiserver_async_write
, apiserv
,
307 fd
, &apiserv
->t_async_write
);
312 /* Free instance. First unregister all opaque types used by
313 application, flush opaque LSAs injected by application
314 from network and close connection. */
315 void ospf_apiserver_free(struct ospf_apiserver
*apiserv
)
317 struct listnode
*node
;
319 /* Cancel read and write threads. */
320 thread_cancel(&apiserv
->t_sync_read
);
321 #ifdef USE_ASYNC_READ
322 thread_cancel(&apiserv
->t_async_read
);
323 #endif /* USE_ASYNC_READ */
324 thread_cancel(&apiserv
->t_sync_write
);
325 thread_cancel(&apiserv
->t_async_write
);
327 /* Unregister all opaque types that application registered
328 and flush opaque LSAs if still in LSDB. */
330 while ((node
= listhead(apiserv
->opaque_types
)) != NULL
) {
331 struct registered_opaque_type
*regtype
= listgetdata(node
);
333 ospf_apiserver_unregister_opaque_type(
334 apiserv
, regtype
->lsa_type
, regtype
->opaque_type
);
337 /* Close connections to OSPFd. */
338 if (apiserv
->fd_sync
> 0) {
339 close(apiserv
->fd_sync
);
342 if (apiserv
->fd_async
> 0) {
343 close(apiserv
->fd_async
);
347 msg_fifo_free(apiserv
->out_sync_fifo
);
348 msg_fifo_free(apiserv
->out_async_fifo
);
350 /* Clear temporary strage for LSA instances to be refreshed. */
351 ospf_lsdb_delete_all(&apiserv
->reserve
);
352 ospf_lsdb_cleanup(&apiserv
->reserve
);
354 /* Remove from the list of active clients. */
355 listnode_delete(apiserver_list
, apiserv
);
357 if (IS_DEBUG_OSPF_EVENT
)
358 zlog_debug("API: Delete apiserv(%p), total#(%d)",
359 (void *)apiserv
, apiserver_list
->count
);
361 /* And free instance. */
362 XFREE(MTYPE_OSPF_APISERVER
, apiserv
);
365 int ospf_apiserver_read(struct thread
*thread
)
367 struct ospf_apiserver
*apiserv
;
373 apiserv
= THREAD_ARG(thread
);
374 fd
= THREAD_FD(thread
);
376 if (fd
== apiserv
->fd_sync
) {
377 event
= OSPF_APISERVER_SYNC_READ
;
378 apiserv
->t_sync_read
= NULL
;
380 if (IS_DEBUG_OSPF_EVENT
)
381 zlog_debug("API: ospf_apiserver_read: Peer: %pI4/%u",
382 &apiserv
->peer_sync
.sin_addr
,
383 ntohs(apiserv
->peer_sync
.sin_port
));
385 #ifdef USE_ASYNC_READ
386 else if (fd
== apiserv
->fd_async
) {
387 event
= OSPF_APISERVER_ASYNC_READ
;
388 apiserv
->t_async_read
= NULL
;
390 if (IS_DEBUG_OSPF_EVENT
)
391 zlog_debug("API: ospf_apiserver_read: Peer: %pI4/%u",
392 &apiserv
->peer_async
.sin_addr
,
393 ntohs(apiserv
->peer_async
.sin_port
));
395 #endif /* USE_ASYNC_READ */
397 zlog_warn("ospf_apiserver_read: Unknown fd(%d)", fd
);
398 ospf_apiserver_free(apiserv
);
402 /* Read message from fd. */
406 "ospf_apiserver_read: read failed on fd=%d, closing connection",
409 /* Perform cleanup. */
410 ospf_apiserver_free(apiserv
);
414 if (IS_DEBUG_OSPF_EVENT
)
417 /* Dispatch to corresponding message handler. */
418 rc
= ospf_apiserver_handle_msg(apiserv
, msg
);
420 /* Prepare for next message, add read thread. */
421 ospf_apiserver_event(event
, fd
, apiserv
);
429 int ospf_apiserver_sync_write(struct thread
*thread
)
431 struct ospf_apiserver
*apiserv
;
436 apiserv
= THREAD_ARG(thread
);
438 fd
= THREAD_FD(thread
);
440 apiserv
->t_sync_write
= NULL
;
443 if (fd
!= apiserv
->fd_sync
) {
444 zlog_warn("ospf_apiserver_sync_write: Unknown fd=%d", fd
);
448 if (IS_DEBUG_OSPF_EVENT
)
449 zlog_debug("API: ospf_apiserver_sync_write: Peer: %pI4/%u",
450 &apiserv
->peer_sync
.sin_addr
,
451 ntohs(apiserv
->peer_sync
.sin_port
));
453 /* Check whether there is really a message in the fifo. */
454 msg
= msg_fifo_pop(apiserv
->out_sync_fifo
);
457 "API: ospf_apiserver_sync_write: No message in Sync-FIFO?");
461 if (IS_DEBUG_OSPF_EVENT
)
464 rc
= msg_write(fd
, msg
);
466 /* Once a message is dequeued, it should be freed anyway. */
470 zlog_warn("ospf_apiserver_sync_write: write failed on fd=%d",
476 /* If more messages are in sync message fifo, schedule write thread. */
477 if (msg_fifo_head(apiserv
->out_sync_fifo
)) {
478 ospf_apiserver_event(OSPF_APISERVER_SYNC_WRITE
,
479 apiserv
->fd_sync
, apiserv
);
485 /* Perform cleanup and disconnect with peer */
486 ospf_apiserver_free(apiserv
);
493 int ospf_apiserver_async_write(struct thread
*thread
)
495 struct ospf_apiserver
*apiserv
;
500 apiserv
= THREAD_ARG(thread
);
502 fd
= THREAD_FD(thread
);
504 apiserv
->t_async_write
= NULL
;
507 if (fd
!= apiserv
->fd_async
) {
508 zlog_warn("ospf_apiserver_async_write: Unknown fd=%d", fd
);
512 if (IS_DEBUG_OSPF_EVENT
)
513 zlog_debug("API: ospf_apiserver_async_write: Peer: %pI4/%u",
514 &apiserv
->peer_async
.sin_addr
,
515 ntohs(apiserv
->peer_async
.sin_port
));
517 /* Check whether there is really a message in the fifo. */
518 msg
= msg_fifo_pop(apiserv
->out_async_fifo
);
521 "API: ospf_apiserver_async_write: No message in Async-FIFO?");
525 if (IS_DEBUG_OSPF_EVENT
)
528 rc
= msg_write(fd
, msg
);
530 /* Once a message is dequeued, it should be freed anyway. */
534 zlog_warn("ospf_apiserver_async_write: write failed on fd=%d",
540 /* If more messages are in async message fifo, schedule write thread. */
541 if (msg_fifo_head(apiserv
->out_async_fifo
)) {
542 ospf_apiserver_event(OSPF_APISERVER_ASYNC_WRITE
,
543 apiserv
->fd_async
, apiserv
);
549 /* Perform cleanup and disconnect with peer */
550 ospf_apiserver_free(apiserv
);
557 int ospf_apiserver_serv_sock_family(unsigned short port
, int family
)
563 memset(&su
, 0, sizeof(union sockunion
));
564 su
.sa
.sa_family
= family
;
566 /* Make new socket */
567 accept_sock
= sockunion_stream_socket(&su
);
571 /* This is a server, so reuse address and port */
572 sockopt_reuseaddr(accept_sock
);
573 sockopt_reuseport(accept_sock
);
575 /* Bind socket to address and given port. */
576 rc
= sockunion_bind(accept_sock
, &su
, port
, NULL
);
578 close(accept_sock
); /* Close socket */
582 /* Listen socket under queue length 3. */
583 rc
= listen(accept_sock
, 3);
585 zlog_warn("ospf_apiserver_serv_sock_family: listen: %s",
586 safe_strerror(errno
));
587 close(accept_sock
); /* Close socket */
594 /* Accept connection request from external applications. For each
595 accepted connection allocate own connection instance. */
596 int ospf_apiserver_accept(struct thread
*thread
)
602 struct ospf_apiserver
*apiserv
;
603 struct sockaddr_in peer_async
;
604 struct sockaddr_in peer_sync
;
605 unsigned int peerlen
;
608 /* THREAD_ARG (thread) is NULL */
609 accept_sock
= THREAD_FD(thread
);
611 /* Keep hearing on socket for further connections. */
612 ospf_apiserver_event(OSPF_APISERVER_ACCEPT
, accept_sock
, NULL
);
614 memset(&su
, 0, sizeof(union sockunion
));
615 /* Accept connection for synchronous messages */
616 new_sync_sock
= sockunion_accept(accept_sock
, &su
);
617 if (new_sync_sock
< 0) {
618 zlog_warn("ospf_apiserver_accept: accept: %s",
619 safe_strerror(errno
));
623 /* Get port address and port number of peer to make reverse connection.
624 The reverse channel uses the port number of the peer port+1. */
626 memset(&peer_sync
, 0, sizeof(struct sockaddr_in
));
627 peerlen
= sizeof(struct sockaddr_in
);
629 ret
= getpeername(new_sync_sock
, (struct sockaddr
*)&peer_sync
,
632 zlog_warn("ospf_apiserver_accept: getpeername: %s",
633 safe_strerror(errno
));
634 close(new_sync_sock
);
638 if (IS_DEBUG_OSPF_EVENT
)
639 zlog_debug("API: ospf_apiserver_accept: New peer: %pI4/%u",
641 ntohs(peer_sync
.sin_port
));
643 /* Create new socket for asynchronous messages. */
644 peer_async
= peer_sync
;
645 peer_async
.sin_port
= htons(ntohs(peer_sync
.sin_port
) + 1);
647 /* Check if remote port number to make reverse connection is valid one.
649 if (ntohs(peer_async
.sin_port
) == ospf_apiserver_getport()) {
651 "API: ospf_apiserver_accept: Peer(%pI4/%u): Invalid async port number?",
652 &peer_async
.sin_addr
,
653 ntohs(peer_async
.sin_port
));
654 close(new_sync_sock
);
658 new_async_sock
= socket(AF_INET
, SOCK_STREAM
, 0);
659 if (new_async_sock
< 0) {
660 zlog_warn("ospf_apiserver_accept: socket: %s",
661 safe_strerror(errno
));
662 close(new_sync_sock
);
666 ret
= connect(new_async_sock
, (struct sockaddr
*)&peer_async
,
667 sizeof(struct sockaddr_in
));
670 zlog_warn("ospf_apiserver_accept: connect: %s",
671 safe_strerror(errno
));
672 close(new_sync_sock
);
673 close(new_async_sock
);
677 #ifdef USE_ASYNC_READ
678 #else /* USE_ASYNC_READ */
679 /* Make the asynchronous channel write-only. */
680 ret
= shutdown(new_async_sock
, SHUT_RD
);
682 zlog_warn("ospf_apiserver_accept: shutdown: %s",
683 safe_strerror(errno
));
684 close(new_sync_sock
);
685 close(new_async_sock
);
688 #endif /* USE_ASYNC_READ */
690 /* Allocate new server-side connection structure */
691 apiserv
= ospf_apiserver_new(new_sync_sock
, new_async_sock
);
693 /* Add to active connection list */
694 listnode_add(apiserver_list
, apiserv
);
695 apiserv
->peer_sync
= peer_sync
;
696 apiserv
->peer_async
= peer_async
;
698 /* And add read threads for new connection */
699 ospf_apiserver_event(OSPF_APISERVER_SYNC_READ
, new_sync_sock
, apiserv
);
700 #ifdef USE_ASYNC_READ
701 ospf_apiserver_event(OSPF_APISERVER_ASYNC_READ
, new_async_sock
,
703 #endif /* USE_ASYNC_READ */
705 if (IS_DEBUG_OSPF_EVENT
)
706 zlog_debug("API: New apiserv(%p), total#(%d)", (void *)apiserv
,
707 apiserver_list
->count
);
713 /* -----------------------------------------------------------
714 * Send reply with return code to client application
715 * -----------------------------------------------------------
718 static int ospf_apiserver_send_msg(struct ospf_apiserver
*apiserv
,
721 struct msg_fifo
*fifo
;
726 switch (msg
->hdr
.msgtype
) {
728 fifo
= apiserv
->out_sync_fifo
;
729 fd
= apiserv
->fd_sync
;
730 event
= OSPF_APISERVER_SYNC_WRITE
;
732 case MSG_READY_NOTIFY
:
733 case MSG_LSA_UPDATE_NOTIFY
:
734 case MSG_LSA_DELETE_NOTIFY
:
739 fifo
= apiserv
->out_async_fifo
;
740 fd
= apiserv
->fd_async
;
741 event
= OSPF_APISERVER_ASYNC_WRITE
;
744 zlog_warn("ospf_apiserver_send_msg: Unknown message type %d",
749 /* Make a copy of the message and put in the fifo. Once the fifo
750 gets drained by the write thread, the message will be freed. */
751 /* NB: Given "msg" is untouched in this function. */
754 /* Enqueue message into corresponding fifo queue */
755 msg_fifo_push(fifo
, msg2
);
757 /* Schedule write thread */
758 ospf_apiserver_event(event
, fd
, apiserv
);
762 int ospf_apiserver_send_reply(struct ospf_apiserver
*apiserv
, uint32_t seqnr
,
765 struct msg
*msg
= new_msg_reply(seqnr
, rc
);
769 zlog_warn("ospf_apiserver_send_reply: msg_new failed");
771 /* Cannot allocate new message. What should we do? */
772 ospf_apiserver_free(apiserv
);
777 ret
= ospf_apiserver_send_msg(apiserv
, msg
);
783 /* -----------------------------------------------------------
784 * Generic message dispatching handler function
785 * -----------------------------------------------------------
788 int ospf_apiserver_handle_msg(struct ospf_apiserver
*apiserv
, struct msg
*msg
)
792 /* Call corresponding message handler function. */
793 switch (msg
->hdr
.msgtype
) {
794 case MSG_REGISTER_OPAQUETYPE
:
795 rc
= ospf_apiserver_handle_register_opaque_type(apiserv
, msg
);
797 case MSG_UNREGISTER_OPAQUETYPE
:
798 rc
= ospf_apiserver_handle_unregister_opaque_type(apiserv
, msg
);
800 case MSG_REGISTER_EVENT
:
801 rc
= ospf_apiserver_handle_register_event(apiserv
, msg
);
804 rc
= ospf_apiserver_handle_sync_lsdb(apiserv
, msg
);
806 case MSG_ORIGINATE_REQUEST
:
807 rc
= ospf_apiserver_handle_originate_request(apiserv
, msg
);
809 case MSG_DELETE_REQUEST
:
810 rc
= ospf_apiserver_handle_delete_request(apiserv
, msg
);
813 zlog_warn("ospf_apiserver_handle_msg: Unknown message type: %d",
821 /* -----------------------------------------------------------
822 * Following are functions for opaque type registration
823 * -----------------------------------------------------------
826 int ospf_apiserver_register_opaque_type(struct ospf_apiserver
*apiserv
,
827 uint8_t lsa_type
, uint8_t opaque_type
)
829 struct registered_opaque_type
*regtype
;
830 int (*originator_func
)(void *arg
);
834 case OSPF_OPAQUE_LINK_LSA
:
835 originator_func
= ospf_apiserver_lsa9_originator
;
837 case OSPF_OPAQUE_AREA_LSA
:
838 originator_func
= ospf_apiserver_lsa10_originator
;
840 case OSPF_OPAQUE_AS_LSA
:
841 originator_func
= ospf_apiserver_lsa11_originator
;
844 zlog_warn("ospf_apiserver_register_opaque_type: lsa_type(%d)",
846 return OSPF_API_ILLEGALLSATYPE
;
850 /* Register opaque function table */
851 /* NB: Duplicated registration will be detected inside the function. */
852 rc
= ospf_register_opaque_functab(
853 lsa_type
, opaque_type
, NULL
, /* ospf_apiserver_new_if */
854 NULL
, /* ospf_apiserver_del_if */
855 NULL
, /* ospf_apiserver_ism_change */
856 NULL
, /* ospf_apiserver_nsm_change */
857 NULL
, NULL
, NULL
, ospf_apiserver_show_info
, originator_func
,
858 ospf_apiserver_lsa_refresher
,
859 NULL
, /* ospf_apiserver_lsa_update */
860 NULL
/* ospf_apiserver_lsa_delete */);
863 flog_warn(EC_OSPF_OPAQUE_REGISTRATION
,
864 "Failed to register opaque type [%d/%d]", lsa_type
,
866 return OSPF_API_OPAQUETYPEINUSE
;
869 /* Remember the opaque type that application registers so when
870 connection shuts down, we can flush all LSAs of this opaque
873 regtype
= XCALLOC(MTYPE_OSPF_APISERVER
,
874 sizeof(struct registered_opaque_type
));
875 regtype
->lsa_type
= lsa_type
;
876 regtype
->opaque_type
= opaque_type
;
878 /* Add to list of registered opaque types */
879 listnode_add(apiserv
->opaque_types
, regtype
);
881 if (IS_DEBUG_OSPF_EVENT
)
883 "API: Add LSA-type(%d)/Opaque-type(%d) into apiserv(%p), total#(%d)",
884 lsa_type
, opaque_type
, (void *)apiserv
,
885 listcount(apiserv
->opaque_types
));
890 int ospf_apiserver_unregister_opaque_type(struct ospf_apiserver
*apiserv
,
891 uint8_t lsa_type
, uint8_t opaque_type
)
893 struct listnode
*node
, *nnode
;
894 struct registered_opaque_type
*regtype
;
896 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node
, nnode
, regtype
)) {
897 /* Check if we really registered this opaque type */
898 if (regtype
->lsa_type
== lsa_type
899 && regtype
->opaque_type
== opaque_type
) {
901 /* Yes, we registered this opaque type. Flush
902 all existing opaque LSAs of this type */
904 ospf_apiserver_flush_opaque_lsa(apiserv
, lsa_type
,
906 ospf_delete_opaque_functab(lsa_type
, opaque_type
);
908 /* Remove from list of registered opaque types */
909 listnode_delete(apiserv
->opaque_types
, regtype
);
911 if (IS_DEBUG_OSPF_EVENT
)
913 "API: Del LSA-type(%d)/Opaque-type(%d) from apiserv(%p), total#(%d)",
914 lsa_type
, opaque_type
, (void *)apiserv
,
915 listcount(apiserv
->opaque_types
));
921 /* Opaque type is not registered */
922 zlog_warn("Failed to unregister opaque type [%d/%d]", lsa_type
,
924 return OSPF_API_OPAQUETYPENOTREGISTERED
;
928 static int apiserver_is_opaque_type_registered(struct ospf_apiserver
*apiserv
,
932 struct listnode
*node
, *nnode
;
933 struct registered_opaque_type
*regtype
;
935 /* XXX: how many types are there? if few, why not just a bitmap? */
936 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node
, nnode
, regtype
)) {
937 /* Check if we really registered this opaque type */
938 if (regtype
->lsa_type
== lsa_type
939 && regtype
->opaque_type
== opaque_type
) {
948 int ospf_apiserver_handle_register_opaque_type(struct ospf_apiserver
*apiserv
,
951 struct msg_register_opaque_type
*rmsg
;
956 /* Extract parameters from register opaque type message */
957 rmsg
= (struct msg_register_opaque_type
*)STREAM_DATA(msg
->s
);
959 lsa_type
= rmsg
->lsatype
;
960 opaque_type
= rmsg
->opaquetype
;
962 rc
= ospf_apiserver_register_opaque_type(apiserv
, lsa_type
,
965 /* Send a reply back to client including return code */
966 rc
= ospf_apiserver_send_reply(apiserv
, ntohl(msg
->hdr
.msgseq
), rc
);
970 /* Now inform application about opaque types that are ready */
972 case OSPF_OPAQUE_LINK_LSA
:
973 ospf_apiserver_notify_ready_type9(apiserv
);
975 case OSPF_OPAQUE_AREA_LSA
:
976 ospf_apiserver_notify_ready_type10(apiserv
);
978 case OSPF_OPAQUE_AS_LSA
:
979 ospf_apiserver_notify_ready_type11(apiserv
);
987 /* Notify specific client about all opaque types 9 that are ready. */
988 void ospf_apiserver_notify_ready_type9(struct ospf_apiserver
*apiserv
)
990 struct listnode
*node
, *nnode
;
991 struct listnode
*node2
, *nnode2
;
993 struct ospf_interface
*oi
;
994 struct registered_opaque_type
*r
;
996 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
998 for (ALL_LIST_ELEMENTS(ospf
->oiflist
, node
, nnode
, oi
)) {
999 /* Check if this interface is indeed ready for type 9 */
1000 if (!ospf_apiserver_is_ready_type9(oi
))
1003 /* Check for registered opaque type 9 types */
1004 /* XXX: loop-de-loop - optimise me */
1005 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node2
, nnode2
,
1009 if (r
->lsa_type
== OSPF_OPAQUE_LINK_LSA
) {
1011 /* Yes, this opaque type is ready */
1012 msg
= new_msg_ready_notify(
1013 0, OSPF_OPAQUE_LINK_LSA
, r
->opaque_type
,
1014 oi
->address
->u
.prefix4
);
1017 "apiserver_notify_ready_type9: msg_new failed");
1019 /* Cannot allocate new message. What
1021 ospf_apiserver_free(apiserv
);
1025 ospf_apiserver_send_msg(apiserv
, msg
);
1036 /* Notify specific client about all opaque types 10 that are ready. */
1037 void ospf_apiserver_notify_ready_type10(struct ospf_apiserver
*apiserv
)
1039 struct listnode
*node
, *nnode
;
1040 struct listnode
*node2
, *nnode2
;
1042 struct ospf_area
*area
;
1044 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1046 for (ALL_LIST_ELEMENTS(ospf
->areas
, node
, nnode
, area
)) {
1047 struct registered_opaque_type
*r
;
1049 if (!ospf_apiserver_is_ready_type10(area
)) {
1053 /* Check for registered opaque type 10 types */
1054 /* XXX: loop in loop - optimise me */
1055 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node2
, nnode2
,
1059 if (r
->lsa_type
== OSPF_OPAQUE_AREA_LSA
) {
1060 /* Yes, this opaque type is ready */
1061 msg
= new_msg_ready_notify(
1062 0, OSPF_OPAQUE_AREA_LSA
, r
->opaque_type
,
1066 "apiserver_notify_ready_type10: msg_new failed");
1068 /* Cannot allocate new message. What
1070 ospf_apiserver_free(apiserv
);
1074 ospf_apiserver_send_msg(apiserv
, msg
);
1084 /* Notify specific client about all opaque types 11 that are ready */
1085 void ospf_apiserver_notify_ready_type11(struct ospf_apiserver
*apiserv
)
1087 struct listnode
*node
, *nnode
;
1089 struct registered_opaque_type
*r
;
1091 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1093 /* Can type 11 be originated? */
1094 if (!ospf_apiserver_is_ready_type11(ospf
))
1097 /* Check for registered opaque type 11 types */
1098 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node
, nnode
, r
)) {
1100 struct in_addr noarea_id
= {.s_addr
= 0L};
1102 if (r
->lsa_type
== OSPF_OPAQUE_AS_LSA
) {
1103 /* Yes, this opaque type is ready */
1104 msg
= new_msg_ready_notify(0, OSPF_OPAQUE_AS_LSA
,
1105 r
->opaque_type
, noarea_id
);
1109 "apiserver_notify_ready_type11: msg_new failed");
1111 /* Cannot allocate new message. What should we
1113 ospf_apiserver_free(apiserv
);
1117 ospf_apiserver_send_msg(apiserv
, msg
);
1126 int ospf_apiserver_handle_unregister_opaque_type(struct ospf_apiserver
*apiserv
,
1129 struct msg_unregister_opaque_type
*umsg
;
1134 /* Extract parameters from unregister opaque type message */
1135 umsg
= (struct msg_unregister_opaque_type
*)STREAM_DATA(msg
->s
);
1137 ltype
= umsg
->lsatype
;
1138 otype
= umsg
->opaquetype
;
1140 rc
= ospf_apiserver_unregister_opaque_type(apiserv
, ltype
, otype
);
1142 /* Send a reply back to client including return code */
1143 rc
= ospf_apiserver_send_reply(apiserv
, ntohl(msg
->hdr
.msgseq
), rc
);
1149 /* -----------------------------------------------------------
1150 * Following are functions for event (filter) registration.
1151 * -----------------------------------------------------------
1153 int ospf_apiserver_handle_register_event(struct ospf_apiserver
*apiserv
,
1156 struct msg_register_event
*rmsg
;
1161 rmsg
= (struct msg_register_event
*)STREAM_DATA(msg
->s
);
1163 /* Get request sequence number */
1164 seqnum
= msg_get_seq(msg
);
1166 /* Free existing filter in apiserv. */
1167 XFREE(MTYPE_OSPF_APISERVER_MSGFILTER
, apiserv
->filter
);
1168 /* Alloc new space for filter. */
1169 size
= ntohs(msg
->hdr
.msglen
);
1170 if (size
< OSPF_MAX_LSA_SIZE
) {
1172 apiserv
->filter
= XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER
, size
);
1175 memcpy(apiserv
->filter
, &rmsg
->filter
, size
);
1178 rc
= OSPF_API_NOMEMORY
;
1180 /* Send a reply back to client with return code */
1181 rc
= ospf_apiserver_send_reply(apiserv
, seqnum
, rc
);
1186 /* -----------------------------------------------------------
1187 * Followings are functions for LSDB synchronization.
1188 * -----------------------------------------------------------
1191 static int apiserver_sync_callback(struct ospf_lsa
*lsa
, void *p_arg
,
1194 struct ospf_apiserver
*apiserv
;
1198 struct ospf_apiserver
*apiserv
;
1199 struct lsa_filter_type
*filter
;
1207 param
= (struct param_t
*)p_arg
;
1208 apiserv
= param
->apiserv
;
1209 seqnum
= (uint32_t)int_arg
;
1211 /* Check origin in filter. */
1212 if ((param
->filter
->origin
== ANY_ORIGIN
)
1213 || (param
->filter
->origin
== (lsa
->flags
& OSPF_LSA_SELF
))) {
1215 /* Default area for AS-External and Opaque11 LSAs */
1216 struct in_addr area_id
= {.s_addr
= 0L};
1218 /* Default interface for non Opaque9 LSAs */
1219 struct in_addr ifaddr
= {.s_addr
= 0L};
1222 area_id
= lsa
->area
->area_id
;
1224 if (lsa
->data
->type
== OSPF_OPAQUE_LINK_LSA
) {
1225 ifaddr
= lsa
->oi
->address
->u
.prefix4
;
1228 msg
= new_msg_lsa_change_notify(
1229 MSG_LSA_UPDATE_NOTIFY
, seqnum
, ifaddr
, area_id
,
1230 lsa
->flags
& OSPF_LSA_SELF
, lsa
->data
);
1233 "apiserver_sync_callback: new_msg_update failed");
1235 /* Cannot allocate new message. What should we do? */
1236 /* ospf_apiserver_free (apiserv);*/ /* Do nothing
1244 ospf_apiserver_send_msg(apiserv
, msg
);
1253 int ospf_apiserver_handle_sync_lsdb(struct ospf_apiserver
*apiserv
,
1256 struct listnode
*node
, *nnode
;
1259 struct msg_sync_lsdb
*smsg
;
1260 struct ospf_apiserver_param_t
{
1261 struct ospf_apiserver
*apiserv
;
1262 struct lsa_filter_type
*filter
;
1265 struct route_node
*rn
;
1266 struct ospf_lsa
*lsa
;
1268 struct ospf_area
*area
;
1270 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1272 /* Get request sequence number */
1273 seqnum
= msg_get_seq(msg
);
1275 smsg
= (struct msg_sync_lsdb
*)STREAM_DATA(msg
->s
);
1277 /* Set parameter struct. */
1278 param
.apiserv
= apiserv
;
1279 param
.filter
= &smsg
->filter
;
1281 /* Remember mask. */
1282 mask
= ntohs(smsg
->filter
.typemask
);
1284 /* Iterate over all areas. */
1285 for (ALL_LIST_ELEMENTS(ospf
->areas
, node
, nnode
, area
)) {
1287 uint32_t *area_id
= NULL
;
1289 /* Compare area_id with area_ids in sync request. */
1290 if ((i
= smsg
->filter
.num_areas
) > 0) {
1291 /* Let area_id point to the list of area IDs,
1292 * which is at the end of smsg->filter. */
1293 area_id
= (uint32_t *)(&smsg
->filter
+ 1);
1295 if (*area_id
== area
->area_id
.s_addr
) {
1305 /* If area was found, then i>0 here. */
1307 /* Check msg type. */
1308 if (mask
& Power2
[OSPF_ROUTER_LSA
])
1309 LSDB_LOOP (ROUTER_LSDB(area
), rn
, lsa
)
1310 apiserver_sync_callback(
1311 lsa
, (void *)¶m
, seqnum
);
1312 if (mask
& Power2
[OSPF_NETWORK_LSA
])
1313 LSDB_LOOP (NETWORK_LSDB(area
), rn
, lsa
)
1314 apiserver_sync_callback(
1315 lsa
, (void *)¶m
, seqnum
);
1316 if (mask
& Power2
[OSPF_SUMMARY_LSA
])
1317 LSDB_LOOP (SUMMARY_LSDB(area
), rn
, lsa
)
1318 apiserver_sync_callback(
1319 lsa
, (void *)¶m
, seqnum
);
1320 if (mask
& Power2
[OSPF_ASBR_SUMMARY_LSA
])
1321 LSDB_LOOP (ASBR_SUMMARY_LSDB(area
), rn
, lsa
)
1322 apiserver_sync_callback(
1323 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(
1327 lsa
, (void *)¶m
, seqnum
);
1328 if (mask
& Power2
[OSPF_OPAQUE_AREA_LSA
])
1329 LSDB_LOOP (OPAQUE_AREA_LSDB(area
), rn
, lsa
)
1330 apiserver_sync_callback(
1331 lsa
, (void *)¶m
, seqnum
);
1335 /* For AS-external LSAs */
1337 if (mask
& Power2
[OSPF_AS_EXTERNAL_LSA
])
1338 LSDB_LOOP (EXTERNAL_LSDB(ospf
), rn
, lsa
)
1339 apiserver_sync_callback(lsa
, (void *)¶m
,
1343 /* For AS-external opaque LSAs */
1345 if (mask
& Power2
[OSPF_OPAQUE_AS_LSA
])
1346 LSDB_LOOP (OPAQUE_AS_LSDB(ospf
), rn
, lsa
)
1347 apiserver_sync_callback(lsa
, (void *)¶m
,
1351 /* Send a reply back to client with return code */
1352 rc
= ospf_apiserver_send_reply(apiserv
, seqnum
, rc
);
1357 /* -----------------------------------------------------------
1358 * Followings are functions to originate or update LSA
1359 * from an application.
1360 * -----------------------------------------------------------
1363 /* Create a new internal opaque LSA by taking prototype and filling in
1364 missing fields such as age, sequence number, advertising router,
1365 checksum and so on. The interface parameter is used for type 9
1366 LSAs, area parameter for type 10. Type 11 LSAs do neither need area
1369 struct ospf_lsa
*ospf_apiserver_opaque_lsa_new(struct ospf_area
*area
,
1370 struct ospf_interface
*oi
,
1371 struct lsa_header
*protolsa
)
1374 struct lsa_header
*newlsa
;
1375 struct ospf_lsa
*new = NULL
;
1376 uint8_t options
= 0x0;
1384 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1388 /* Create a stream for internal opaque LSA */
1389 if ((s
= stream_new(OSPF_MAX_LSA_SIZE
)) == NULL
) {
1390 zlog_warn("ospf_apiserver_opaque_lsa_new: stream_new failed");
1394 newlsa
= (struct lsa_header
*)STREAM_DATA(s
);
1396 /* XXX If this is a link-local LSA or an AS-external LSA, how do we
1397 have to set options? */
1400 options
= LSA_OPTIONS_GET(area
);
1401 options
|= LSA_OPTIONS_NSSA_GET(area
);
1404 options
|= OSPF_OPTION_O
; /* Don't forget to set option bit */
1406 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
)) {
1407 zlog_debug("LSA[Type%d:%pI4]: Creating an Opaque-LSA instance",
1408 protolsa
->type
, &protolsa
->id
);
1411 /* Set opaque-LSA header fields. */
1412 lsa_header_set(s
, options
, protolsa
->type
, protolsa
->id
,
1415 /* Set opaque-LSA body fields. */
1416 stream_put(s
, ((uint8_t *)protolsa
) + sizeof(struct lsa_header
),
1417 ntohs(protolsa
->length
) - sizeof(struct lsa_header
));
1419 /* Determine length of LSA. */
1420 length
= stream_get_endp(s
);
1421 newlsa
->length
= htons(length
);
1423 /* Create OSPF LSA. */
1424 new = ospf_lsa_new_and_data(length
);
1428 new->vrf_id
= ospf
->vrf_id
;
1430 SET_FLAG(new->flags
, OSPF_LSA_SELF
);
1431 memcpy(new->data
, newlsa
, length
);
1438 int ospf_apiserver_is_ready_type9(struct ospf_interface
*oi
)
1440 /* Type 9 opaque LSA can be originated if there is at least one
1441 active opaque-capable neighbor attached to the outgoing
1444 return (ospf_nbr_count_opaque_capable(oi
) > 0);
1447 int ospf_apiserver_is_ready_type10(struct ospf_area
*area
)
1449 /* Type 10 opaque LSA can be originated if there is at least one
1450 interface belonging to the area that has an active opaque-capable
1452 struct listnode
*node
, *nnode
;
1453 struct ospf_interface
*oi
;
1455 for (ALL_LIST_ELEMENTS(area
->oiflist
, node
, nnode
, oi
))
1456 /* Is there an active neighbor attached to this interface? */
1457 if (ospf_apiserver_is_ready_type9(oi
))
1460 /* No active neighbor in area */
1464 int ospf_apiserver_is_ready_type11(struct ospf
*ospf
)
1466 /* Type 11 opaque LSA can be originated if there is at least one
1468 that has an active opaque-capable neighbor. */
1469 struct listnode
*node
, *nnode
;
1470 struct ospf_interface
*oi
;
1472 for (ALL_LIST_ELEMENTS(ospf
->oiflist
, node
, nnode
, oi
))
1473 /* Is there an active neighbor attached to this interface? */
1474 if (ospf_apiserver_is_ready_type9(oi
))
1477 /* No active neighbor at all */
1482 int ospf_apiserver_handle_originate_request(struct ospf_apiserver
*apiserv
,
1485 struct msg_originate_request
*omsg
;
1486 struct lsa_header
*data
;
1487 struct ospf_lsa
*new;
1488 struct ospf_lsa
*old
;
1489 struct ospf_area
*area
= NULL
;
1490 struct ospf_interface
*oi
= NULL
;
1491 struct ospf_lsdb
*lsdb
= NULL
;
1493 int lsa_type
, opaque_type
;
1497 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1499 /* Extract opaque LSA data from message */
1500 omsg
= (struct msg_originate_request
*)STREAM_DATA(msg
->s
);
1503 /* Determine interface for type9 or area for type10 LSAs. */
1504 switch (data
->type
) {
1505 case OSPF_OPAQUE_LINK_LSA
:
1506 oi
= ospf_apiserver_if_lookup_by_addr(omsg
->ifaddr
);
1508 zlog_warn("apiserver_originate: unknown interface %pI4",
1510 rc
= OSPF_API_NOSUCHINTERFACE
;
1516 case OSPF_OPAQUE_AREA_LSA
:
1517 area
= ospf_area_lookup_by_area_id(ospf
, omsg
->area_id
);
1519 zlog_warn("apiserver_originate: unknown area %pI4",
1521 rc
= OSPF_API_NOSUCHAREA
;
1526 case OSPF_OPAQUE_AS_LSA
:
1530 /* We can only handle opaque types here */
1532 "apiserver_originate: Cannot originate non-opaque LSA type %d",
1534 rc
= OSPF_API_ILLEGALLSATYPE
;
1538 /* Check if we registered this opaque type */
1539 lsa_type
= data
->type
;
1540 opaque_type
= GET_OPAQUE_TYPE(ntohl(data
->id
.s_addr
));
1542 if (!apiserver_is_opaque_type_registered(apiserv
, lsa_type
,
1545 "apiserver_originate: LSA-type(%d)/Opaque-type(%d): Not registered",
1546 lsa_type
, opaque_type
);
1547 rc
= OSPF_API_OPAQUETYPENOTREGISTERED
;
1551 /* Make sure that the neighbors are ready before we can originate */
1552 switch (data
->type
) {
1553 case OSPF_OPAQUE_LINK_LSA
:
1554 ready
= ospf_apiserver_is_ready_type9(oi
);
1556 case OSPF_OPAQUE_AREA_LSA
:
1557 ready
= ospf_apiserver_is_ready_type10(area
);
1559 case OSPF_OPAQUE_AS_LSA
:
1560 ready
= ospf_apiserver_is_ready_type11(ospf
);
1567 zlog_warn("Neighbors not ready to originate type %d",
1569 rc
= OSPF_API_NOTREADY
;
1573 /* Create OSPF's internal opaque LSA representation */
1574 new = ospf_apiserver_opaque_lsa_new(area
, oi
, data
);
1576 rc
= OSPF_API_NOMEMORY
; /* XXX */
1580 /* Determine if LSA is new or an update for an existing one. */
1581 old
= ospf_lsdb_lookup(lsdb
, new);
1584 /* New LSA install in LSDB. */
1585 rc
= ospf_apiserver_originate1(new);
1588 * Keep the new LSA instance in the "waiting place" until the
1590 * refresh timing. If several LSA update requests for the same
1592 * have issued by peer, the last one takes effect.
1594 new->lsdb
= &apiserv
->reserve
;
1595 ospf_lsdb_add(&apiserv
->reserve
, new);
1597 /* Kick the scheduler function. */
1598 ospf_opaque_lsa_refresh_schedule(old
);
1603 /* Send a reply back to client with return code */
1604 rc
= ospf_apiserver_send_reply(apiserv
, ntohl(msg
->hdr
.msgseq
), rc
);
1609 /* -----------------------------------------------------------
1610 * Flood an LSA within its flooding scope.
1611 * -----------------------------------------------------------
1614 /* XXX We can probably use ospf_flood_through instead of this function
1615 but then we need the neighbor parameter. If we set nbr to
1616 NULL then ospf_flood_through crashes due to dereferencing NULL. */
1618 void ospf_apiserver_flood_opaque_lsa(struct ospf_lsa
*lsa
)
1622 switch (lsa
->data
->type
) {
1623 case OSPF_OPAQUE_LINK_LSA
:
1624 /* Increment counters? XXX */
1626 /* Flood LSA through local network. */
1627 ospf_flood_through_area(lsa
->area
, NULL
/*nbr */, lsa
);
1629 case OSPF_OPAQUE_AREA_LSA
:
1630 /* Update LSA origination count. */
1632 lsa
->area
->ospf
->lsa_originate_count
++;
1634 /* Flood LSA through area. */
1635 ospf_flood_through_area(lsa
->area
, NULL
/*nbr */, lsa
);
1637 case OSPF_OPAQUE_AS_LSA
: {
1640 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1643 /* Increment counters? XXX */
1645 /* Flood LSA through AS. */
1646 ospf_flood_through_as(ospf
, NULL
/*nbr */, lsa
);
1652 int ospf_apiserver_originate1(struct ospf_lsa
*lsa
)
1656 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1659 /* Install this LSA into LSDB. */
1660 if (ospf_lsa_install(ospf
, lsa
->oi
, lsa
) == NULL
) {
1661 flog_warn(EC_OSPF_LSA_INSTALL_FAILURE
,
1662 "ospf_apiserver_originate1: ospf_lsa_install failed");
1666 /* Flood LSA within scope */
1670 * NB: Modified version of "ospf_flood_though ()" accepts NULL "inbr"
1671 * parameter, and thus it does not cause SIGSEGV error.
1673 ospf_flood_through(NULL
/*nbr */, lsa
);
1676 ospf_apiserver_flood_opaque_lsa(lsa
);
1683 /* Opaque LSAs of type 9 on a specific interface can now be
1684 originated. Tell clients that registered type 9. */
1685 int ospf_apiserver_lsa9_originator(void *arg
)
1687 struct ospf_interface
*oi
;
1689 oi
= (struct ospf_interface
*)arg
;
1690 if (listcount(apiserver_list
) > 0) {
1691 ospf_apiserver_clients_notify_ready_type9(oi
);
1696 int ospf_apiserver_lsa10_originator(void *arg
)
1698 struct ospf_area
*area
;
1700 area
= (struct ospf_area
*)arg
;
1701 if (listcount(apiserver_list
) > 0) {
1702 ospf_apiserver_clients_notify_ready_type10(area
);
1707 int ospf_apiserver_lsa11_originator(void *arg
)
1711 ospf
= (struct ospf
*)arg
;
1712 if (listcount(apiserver_list
) > 0) {
1713 ospf_apiserver_clients_notify_ready_type11(ospf
);
1719 /* Periodically refresh opaque LSAs so that they do not expire in
1721 struct ospf_lsa
*ospf_apiserver_lsa_refresher(struct ospf_lsa
*lsa
)
1723 struct ospf_apiserver
*apiserv
;
1724 struct ospf_lsa
*new = NULL
;
1729 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1732 apiserv
= lookup_apiserver_by_lsa(lsa
);
1735 "ospf_apiserver_lsa_refresher: LSA[%s]: No apiserver?",
1738 htons(OSPF_LSA_MAXAGE
); /* Flush it anyway. */
1742 if (IS_LSA_MAXAGE(lsa
)) {
1743 ospf_opaque_lsa_flush_schedule(lsa
);
1747 /* Check if updated version of LSA instance has already prepared. */
1748 new = ospf_lsdb_lookup(&apiserv
->reserve
, lsa
);
1750 /* This is a periodic refresh, driven by core OSPF mechanism. */
1751 new = ospf_apiserver_opaque_lsa_new(lsa
->area
, lsa
->oi
,
1755 "ospf_apiserver_lsa_refresher: Cannot create a new LSA?");
1759 /* This is a forcible refresh, requested by OSPF-API client. */
1760 ospf_lsdb_delete(&apiserv
->reserve
, new);
1764 /* Increment sequence number */
1765 new->data
->ls_seqnum
= lsa_seqnum_increment(lsa
);
1767 /* New LSA is in same area. */
1768 new->area
= lsa
->area
;
1769 SET_FLAG(new->flags
, OSPF_LSA_SELF
);
1771 /* Install LSA into LSDB. */
1772 if (ospf_lsa_install(ospf
, new->oi
, new) == NULL
) {
1774 EC_OSPF_LSA_INSTALL_FAILURE
,
1775 "ospf_apiserver_lsa_refresher: ospf_lsa_install failed");
1776 ospf_lsa_unlock(&new);
1780 /* Flood updated LSA through interface, area or AS */
1783 ospf_flood_through(NULL
/*nbr */, new);
1785 ospf_apiserver_flood_opaque_lsa(new);
1787 /* Debug logging. */
1788 if (IS_DEBUG_OSPF(lsa
, LSA_GENERATE
)) {
1789 zlog_debug("LSA[Type%d:%pI4]: Refresh Opaque LSA",
1790 new->data
->type
, &new->data
->id
);
1791 ospf_lsa_header_dump(new->data
);
1799 /* -----------------------------------------------------------
1800 * Followings are functions to delete LSAs
1801 * -----------------------------------------------------------
1804 int ospf_apiserver_handle_delete_request(struct ospf_apiserver
*apiserv
,
1807 struct msg_delete_request
*dmsg
;
1808 struct ospf_lsa
*old
;
1809 struct ospf_area
*area
= NULL
;
1811 int lsa_type
, opaque_type
;
1815 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1818 /* Extract opaque LSA from message */
1819 dmsg
= (struct msg_delete_request
*)STREAM_DATA(msg
->s
);
1821 /* Lookup area for link-local and area-local opaque LSAs */
1822 switch (dmsg
->lsa_type
) {
1823 case OSPF_OPAQUE_LINK_LSA
:
1824 case OSPF_OPAQUE_AREA_LSA
:
1825 area
= ospf_area_lookup_by_area_id(ospf
, dmsg
->area_id
);
1827 zlog_warn("ospf_apiserver_lsa_delete: unknown area %pI4",
1829 rc
= OSPF_API_NOSUCHAREA
;
1833 case OSPF_OPAQUE_AS_LSA
:
1834 /* AS-external opaque LSAs have no designated area */
1839 "ospf_apiserver_lsa_delete: Cannot delete non-opaque LSA type %d",
1841 rc
= OSPF_API_ILLEGALLSATYPE
;
1845 /* Check if we registered this opaque type */
1846 lsa_type
= dmsg
->lsa_type
;
1847 opaque_type
= dmsg
->opaque_type
;
1849 if (!apiserver_is_opaque_type_registered(apiserv
, lsa_type
,
1852 "ospf_apiserver_lsa_delete: LSA-type(%d)/Opaque-type(%d): Not registered",
1853 lsa_type
, opaque_type
);
1854 rc
= OSPF_API_OPAQUETYPENOTREGISTERED
;
1858 /* opaque_id is in network byte order */
1860 SET_OPAQUE_LSID(dmsg
->opaque_type
, ntohl(dmsg
->opaque_id
)));
1863 * Even if the target LSA has once scheduled to flush, it remains in
1864 * the LSDB until it is finally handled by the maxage remover thread.
1865 * Therefore, the lookup function below may return non-NULL result.
1867 old
= ospf_lsa_lookup(ospf
, area
, dmsg
->lsa_type
, id
, ospf
->router_id
);
1870 "ospf_apiserver_lsa_delete: LSA[Type%d:%pI4] not in LSDB",
1871 dmsg
->lsa_type
, &id
);
1872 rc
= OSPF_API_NOSUCHLSA
;
1876 /* Schedule flushing of LSA from LSDB */
1877 /* NB: Multiple scheduling will produce a warning message, but harmless.
1879 ospf_opaque_lsa_flush_schedule(old
);
1883 /* Send reply back to client including return code */
1884 rc
= ospf_apiserver_send_reply(apiserv
, ntohl(msg
->hdr
.msgseq
), rc
);
1888 /* Flush self-originated opaque LSA */
1889 static int apiserver_flush_opaque_type_callback(struct ospf_lsa
*lsa
,
1890 void *p_arg
, int int_arg
)
1893 struct ospf_apiserver
*apiserv
;
1895 uint8_t opaque_type
;
1901 param
= (struct param_t
*)p_arg
;
1903 /* If LSA matches type and opaque type then delete it */
1904 if (IS_LSA_SELF(lsa
) && lsa
->data
->type
== param
->lsa_type
1905 && GET_OPAQUE_TYPE(ntohl(lsa
->data
->id
.s_addr
))
1906 == param
->opaque_type
) {
1907 ospf_opaque_lsa_flush_schedule(lsa
);
1912 /* Delete self-originated opaque LSAs of a given opaque type. This
1913 function is called when an application unregisters a given opaque
1914 type or a connection to an application closes and all those opaque
1915 LSAs need to be flushed the LSDB. */
1916 void ospf_apiserver_flush_opaque_lsa(struct ospf_apiserver
*apiserv
,
1917 uint8_t lsa_type
, uint8_t opaque_type
)
1920 struct ospf_apiserver
*apiserv
;
1922 uint8_t opaque_type
;
1924 struct listnode
*node
, *nnode
;
1926 struct ospf_area
*area
;
1928 ospf
= ospf_lookup_by_vrf_id(VRF_DEFAULT
);
1931 /* Set parameter struct. */
1932 param
.apiserv
= apiserv
;
1933 param
.lsa_type
= lsa_type
;
1934 param
.opaque_type
= opaque_type
;
1937 struct route_node
*rn
;
1938 struct ospf_lsa
*lsa
;
1940 case OSPF_OPAQUE_LINK_LSA
:
1941 for (ALL_LIST_ELEMENTS(ospf
->areas
, node
, nnode
, area
))
1942 LSDB_LOOP (OPAQUE_LINK_LSDB(area
), rn
, lsa
)
1943 apiserver_flush_opaque_type_callback(
1944 lsa
, (void *)¶m
, 0);
1946 case OSPF_OPAQUE_AREA_LSA
:
1947 for (ALL_LIST_ELEMENTS(ospf
->areas
, node
, nnode
, area
))
1948 LSDB_LOOP (OPAQUE_AREA_LSDB(area
), rn
, lsa
)
1949 apiserver_flush_opaque_type_callback(
1950 lsa
, (void *)¶m
, 0);
1952 case OSPF_OPAQUE_AS_LSA
:
1953 LSDB_LOOP (OPAQUE_LINK_LSDB(ospf
), rn
, lsa
)
1954 apiserver_flush_opaque_type_callback(lsa
,
1964 /* -----------------------------------------------------------
1965 * Followings are callback functions to handle opaque types
1966 * -----------------------------------------------------------
1969 int ospf_apiserver_new_if(struct interface
*ifp
)
1971 struct ospf_interface
*oi
;
1973 /* For some strange reason it seems possible that we are invoked
1974 with an interface that has no name. This seems to happen during
1975 initialization. Return if this happens */
1977 if (ifp
->name
[0] == '\0') {
1978 /* interface has empty name */
1979 zlog_warn("ospf_apiserver_new_if: interface has no name?");
1983 /* zlog_warn for debugging */
1984 zlog_warn("ospf_apiserver_new_if");
1985 zlog_warn("ifp name=%s status=%d index=%d", ifp
->name
, ifp
->status
,
1988 if (ifp
->name
[0] == '\0') {
1989 /* interface has empty name */
1990 zlog_warn("ospf_apiserver_new_if: interface has no name?");
1994 oi
= ospf_apiserver_if_lookup_by_ifp(ifp
);
1997 /* This interface is known to Zebra but not to OSPF daemon yet.
2000 "ospf_apiserver_new_if: interface %s not known to OSPFd?",
2007 /* New interface added to OSPF, tell clients about it */
2008 if (listcount(apiserver_list
) > 0) {
2009 ospf_apiserver_clients_notify_new_if(oi
);
2014 int ospf_apiserver_del_if(struct interface
*ifp
)
2016 struct ospf_interface
*oi
;
2018 /* zlog_warn for debugging */
2019 zlog_warn("ospf_apiserver_del_if");
2020 zlog_warn("ifp name=%s status=%d index=%d", ifp
->name
, ifp
->status
,
2023 oi
= ospf_apiserver_if_lookup_by_ifp(ifp
);
2026 /* This interface is known to Zebra but not to OSPF daemon
2027 anymore. No need to tell clients about it */
2031 /* Interface deleted, tell clients about it */
2032 if (listcount(apiserver_list
) > 0) {
2033 ospf_apiserver_clients_notify_del_if(oi
);
2038 void ospf_apiserver_ism_change(struct ospf_interface
*oi
, int old_state
)
2040 /* Tell clients about interface change */
2042 /* zlog_warn for debugging */
2043 zlog_warn("ospf_apiserver_ism_change");
2044 if (listcount(apiserver_list
) > 0) {
2045 ospf_apiserver_clients_notify_ism_change(oi
);
2048 zlog_warn("oi->ifp->name=%s", oi
->ifp
->name
);
2049 zlog_warn("old_state=%d", old_state
);
2050 zlog_warn("oi->state=%d", oi
->state
);
2053 void ospf_apiserver_nsm_change(struct ospf_neighbor
*nbr
, int old_status
)
2055 /* Neighbor status changed, tell clients about it */
2056 zlog_warn("ospf_apiserver_nsm_change");
2057 if (listcount(apiserver_list
) > 0) {
2058 ospf_apiserver_clients_notify_nsm_change(nbr
);
2062 void ospf_apiserver_show_info(struct vty
*vty
, struct json_object
*json
,
2063 struct ospf_lsa
*lsa
)
2066 struct lsa_header header
;
2067 uint8_t data
[1]; /* opaque data have variable length. This is
2071 struct opaque_lsa
*olsa
;
2077 olsa
= (struct opaque_lsa
*)lsa
->data
;
2079 if (VALID_OPAQUE_INFO_LEN(lsa
->data
))
2080 opaquelen
= ntohs(lsa
->data
->length
) - OSPF_LSA_HEADER_SIZE
;
2084 /* Output information about opaque LSAs */
2088 " Added using OSPF API: %u octets of opaque data %s\n",
2090 VALID_OPAQUE_INFO_LEN(lsa
->data
) ? ""
2091 : "(Invalid length?)");
2092 vty_out(vty
, " Opaque data: ");
2094 for (i
= 0; i
< opaquelen
; i
++) {
2095 vty_out(vty
, "0x%x ", olsa
->data
[i
]);
2101 " Added using OSPF API: %u octets of opaque data %s",
2103 VALID_OPAQUE_INFO_LEN(lsa
->data
) ? ""
2104 : "(Invalid length?)");
2105 zlog_debug(" Opaque data: ");
2107 for (i
= 0; i
< opaquelen
; i
++) {
2108 zlog_debug("0x%x ", olsa
->data
[i
]);
2114 /* -----------------------------------------------------------
2115 * Followings are functions to notify clients about events
2116 * -----------------------------------------------------------
2119 /* Send a message to all clients. This is useful for messages
2120 that need to be notified to all clients (such as interface
2123 void ospf_apiserver_clients_notify_all(struct msg
*msg
)
2125 struct listnode
*node
, *nnode
;
2126 struct ospf_apiserver
*apiserv
;
2128 /* Send message to all clients */
2129 for (ALL_LIST_ELEMENTS(apiserver_list
, node
, nnode
, apiserv
))
2130 ospf_apiserver_send_msg(apiserv
, msg
);
2133 /* An interface is now ready to accept opaque LSAs. Notify all
2134 clients that registered to use this opaque type */
2135 void ospf_apiserver_clients_notify_ready_type9(struct ospf_interface
*oi
)
2137 struct listnode
*node
, *nnode
;
2139 struct ospf_apiserver
*apiserv
;
2143 zlog_warn("Interface has no address?");
2147 if (!ospf_apiserver_is_ready_type9(oi
)) {
2148 zlog_warn("Interface not ready for type 9?");
2152 for (ALL_LIST_ELEMENTS(apiserver_list
, node
, nnode
, apiserv
)) {
2153 struct listnode
*node2
, *nnode2
;
2154 struct registered_opaque_type
*r
;
2156 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node2
, nnode2
,
2158 if (r
->lsa_type
== OSPF_OPAQUE_LINK_LSA
) {
2159 msg
= new_msg_ready_notify(
2160 0, OSPF_OPAQUE_LINK_LSA
, r
->opaque_type
,
2161 oi
->address
->u
.prefix4
);
2164 "ospf_apiserver_clients_notify_ready_type9: new_msg_ready_notify failed");
2166 /* Cannot allocate new message. What
2168 ospf_apiserver_free(apiserv
);
2173 ospf_apiserver_send_msg(apiserv
, msg
);
2183 void ospf_apiserver_clients_notify_ready_type10(struct ospf_area
*area
)
2185 struct listnode
*node
, *nnode
;
2187 struct ospf_apiserver
*apiserv
;
2191 if (!ospf_apiserver_is_ready_type10(area
)) {
2192 zlog_warn("Area not ready for type 10?");
2196 for (ALL_LIST_ELEMENTS(apiserver_list
, node
, nnode
, apiserv
)) {
2197 struct listnode
*node2
, *nnode2
;
2198 struct registered_opaque_type
*r
;
2200 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node2
, nnode2
,
2202 if (r
->lsa_type
== OSPF_OPAQUE_AREA_LSA
) {
2203 msg
= new_msg_ready_notify(
2204 0, OSPF_OPAQUE_AREA_LSA
, r
->opaque_type
,
2208 "ospf_apiserver_clients_notify_ready_type10: new_msg_ready_nofity failed");
2210 /* Cannot allocate new message. What
2212 ospf_apiserver_free(apiserv
);
2217 ospf_apiserver_send_msg(apiserv
, msg
);
2228 void ospf_apiserver_clients_notify_ready_type11(struct ospf
*top
)
2230 struct listnode
*node
, *nnode
;
2232 struct in_addr id_null
= {.s_addr
= 0L};
2233 struct ospf_apiserver
*apiserv
;
2237 if (!ospf_apiserver_is_ready_type11(top
)) {
2238 zlog_warn("AS not ready for type 11?");
2242 for (ALL_LIST_ELEMENTS(apiserver_list
, node
, nnode
, apiserv
)) {
2243 struct listnode
*node2
, *nnode2
;
2244 struct registered_opaque_type
*r
;
2246 for (ALL_LIST_ELEMENTS(apiserv
->opaque_types
, node2
, nnode2
,
2248 if (r
->lsa_type
== OSPF_OPAQUE_AS_LSA
) {
2249 msg
= new_msg_ready_notify(
2250 0, OSPF_OPAQUE_AS_LSA
, r
->opaque_type
,
2254 "ospf_apiserver_clients_notify_ready_type11: new_msg_ready_notify failed");
2256 /* Cannot allocate new message. What
2258 ospf_apiserver_free(apiserv
);
2263 ospf_apiserver_send_msg(apiserv
, msg
);
2273 void ospf_apiserver_clients_notify_new_if(struct ospf_interface
*oi
)
2277 msg
= new_msg_new_if(0, oi
->address
->u
.prefix4
, oi
->area
->area_id
);
2279 ospf_apiserver_clients_notify_all(msg
);
2284 void ospf_apiserver_clients_notify_del_if(struct ospf_interface
*oi
)
2288 msg
= new_msg_del_if(0, oi
->address
->u
.prefix4
);
2290 ospf_apiserver_clients_notify_all(msg
);
2295 void ospf_apiserver_clients_notify_ism_change(struct ospf_interface
*oi
)
2298 struct in_addr ifaddr
= {.s_addr
= 0L};
2299 struct in_addr area_id
= {.s_addr
= 0L};
2305 ifaddr
= oi
->address
->u
.prefix4
;
2308 area_id
= oi
->area
->area_id
;
2311 msg
= new_msg_ism_change(0, ifaddr
, area_id
, oi
->state
);
2314 "apiserver_clients_notify_ism_change: msg_new failed");
2318 ospf_apiserver_clients_notify_all(msg
);
2322 void ospf_apiserver_clients_notify_nsm_change(struct ospf_neighbor
*nbr
)
2325 struct in_addr ifaddr
;
2326 struct in_addr nbraddr
;
2330 ifaddr
= nbr
->oi
->address
->u
.prefix4
;
2332 nbraddr
= nbr
->address
.u
.prefix4
;
2334 msg
= new_msg_nsm_change(0, ifaddr
, nbraddr
, nbr
->router_id
,
2338 "apiserver_clients_notify_nsm_change: msg_new failed");
2342 ospf_apiserver_clients_notify_all(msg
);
2346 static void apiserver_clients_lsa_change_notify(uint8_t msgtype
,
2347 struct ospf_lsa
*lsa
)
2350 struct listnode
*node
, *nnode
;
2351 struct ospf_apiserver
*apiserv
;
2353 /* Default area for AS-External and Opaque11 LSAs */
2354 struct in_addr area_id
= {.s_addr
= 0L};
2356 /* Default interface for non Opaque9 LSAs */
2357 struct in_addr ifaddr
= {.s_addr
= 0L};
2360 area_id
= lsa
->area
->area_id
;
2362 if (lsa
->data
->type
== OSPF_OPAQUE_LINK_LSA
) {
2364 ifaddr
= lsa
->oi
->address
->u
.prefix4
;
2367 /* Prepare message that can be sent to clients that have a matching
2369 msg
= new_msg_lsa_change_notify(msgtype
, 0L, /* no sequence number */
2371 lsa
->flags
& OSPF_LSA_SELF
, lsa
->data
);
2374 "apiserver_clients_lsa_change_notify: msg_new failed");
2378 /* Now send message to all clients with a matching filter */
2379 for (ALL_LIST_ELEMENTS(apiserver_list
, node
, nnode
, apiserv
)) {
2380 struct lsa_filter_type
*filter
;
2385 /* Check filter for this client. */
2386 filter
= apiserv
->filter
;
2388 /* Check area IDs in case of non AS-E LSAs.
2389 * If filter has areas (num_areas > 0),
2390 * then one of the areas must match the area ID of this LSA. */
2392 i
= filter
->num_areas
;
2393 if ((lsa
->data
->type
== OSPF_AS_EXTERNAL_LSA
)
2394 || (lsa
->data
->type
== OSPF_OPAQUE_AS_LSA
)) {
2399 area
= (uint32_t *)(filter
+ 1);
2401 if (*area
== area_id
.s_addr
) {
2412 /* Area match. Check LSA type. */
2413 mask
= ntohs(filter
->typemask
);
2415 if (mask
& Power2
[lsa
->data
->type
]) {
2416 /* Type also matches. Check origin. */
2417 if ((filter
->origin
== ANY_ORIGIN
)
2418 || (filter
->origin
== IS_LSA_SELF(lsa
))) {
2419 ospf_apiserver_send_msg(apiserv
, msg
);
2424 /* Free message since it is not used anymore */
2429 /* -------------------------------------------------------------
2430 * Followings are hooks invoked when LSAs are updated or deleted
2431 * -------------------------------------------------------------
2435 static int apiserver_notify_clients_lsa(uint8_t msgtype
, struct ospf_lsa
*lsa
)
2438 /* default area for AS-External and Opaque11 LSAs */
2439 struct in_addr area_id
= {.s_addr
= 0L};
2441 /* default interface for non Opaque9 LSAs */
2442 struct in_addr ifaddr
= {.s_addr
= 0L};
2444 /* Only notify this update if the LSA's age is smaller than
2445 MAXAGE. Otherwise clients would see LSA updates with max age just
2446 before they are deleted from the LSDB. LSA delete messages have
2447 MAXAGE too but should not be filtered. */
2448 if (IS_LSA_MAXAGE(lsa
) && (msgtype
== MSG_LSA_UPDATE_NOTIFY
)) {
2453 area_id
= lsa
->area
->area_id
;
2455 if (lsa
->data
->type
== OSPF_OPAQUE_LINK_LSA
) {
2456 ifaddr
= lsa
->oi
->address
->u
.prefix4
;
2458 msg
= new_msg_lsa_change_notify(msgtype
, 0L, /* no sequence number */
2460 lsa
->flags
& OSPF_LSA_SELF
, lsa
->data
);
2462 zlog_warn("notify_clients_lsa: msg_new failed");
2465 /* Notify all clients that new LSA is added/updated */
2466 apiserver_clients_lsa_change_notify(msgtype
, lsa
);
2468 /* Clients made their own copies of msg so we can free msg here */
2474 int ospf_apiserver_lsa_update(struct ospf_lsa
*lsa
)
2476 return apiserver_notify_clients_lsa(MSG_LSA_UPDATE_NOTIFY
, lsa
);
2479 int ospf_apiserver_lsa_delete(struct ospf_lsa
*lsa
)
2481 return apiserver_notify_clients_lsa(MSG_LSA_DELETE_NOTIFY
, lsa
);
2484 #endif /* SUPPORT_OSPF_API */