zebra: cleanup RIB meta queue code
[jleu-quagga.git] / ospfd / ospf_apiserver.c
blob15fd2e5fc0c25dcf577f1f7ffd85d43cdd1f5491
1 /*
2 * Server side of OSPF API.
3 * Copyright (C) 2001, 2002 Ralph Keller
5 * This file is part of GNU Zebra.
6 *
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
18 * along with GNU Zebra; see the file COPYING. If not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #include <zebra.h>
25 #ifdef SUPPORT_OSPF_API
26 #ifndef HAVE_OPAQUE_LSA
27 #error "Core Opaque-LSA module must be configured."
28 #endif /* HAVE_OPAQUE_LSA */
30 #include "linklist.h"
31 #include "prefix.h"
32 #include "if.h"
33 #include "table.h"
34 #include "memory.h"
35 #include "command.h"
36 #include "vty.h"
37 #include "stream.h"
38 #include "log.h"
39 #include "thread.h"
40 #include "hash.h"
41 #include "sockunion.h" /* for inet_aton() */
42 #include "buffer.h"
44 #include <sys/types.h>
46 #include "ospfd/ospfd.h" /* for "struct thread_master" */
47 #include "ospfd/ospf_interface.h"
48 #include "ospfd/ospf_ism.h"
49 #include "ospfd/ospf_asbr.h"
50 #include "ospfd/ospf_lsa.h"
51 #include "ospfd/ospf_lsdb.h"
52 #include "ospfd/ospf_neighbor.h"
53 #include "ospfd/ospf_nsm.h"
54 #include "ospfd/ospf_flood.h"
55 #include "ospfd/ospf_packet.h"
56 #include "ospfd/ospf_spf.h"
57 #include "ospfd/ospf_dump.h"
58 #include "ospfd/ospf_route.h"
59 #include "ospfd/ospf_ase.h"
60 #include "ospfd/ospf_zebra.h"
62 #include "ospfd/ospf_api.h"
63 #include "ospfd/ospf_apiserver.h"
65 /* This is an implementation of an API to the OSPF daemon that allows
66 * external applications to access the OSPF daemon through socket
67 * connections. The application can use this API to inject its own
68 * opaque LSAs and flood them to other OSPF daemons. Other OSPF
69 * daemons then receive these LSAs and inform applications through the
70 * API by sending a corresponding message. The application can also
71 * register to receive all LSA types (in addition to opaque types) and
72 * use this information to reconstruct the OSPF's LSDB. The OSPF
73 * daemon supports multiple applications concurrently. */
75 /* List of all active connections. */
76 struct list *apiserver_list;
78 /* -----------------------------------------------------------
79 * Functions to lookup interfaces
80 * -----------------------------------------------------------
83 struct ospf_interface *
84 ospf_apiserver_if_lookup_by_addr (struct in_addr address)
86 struct listnode *node, *nnode;
87 struct ospf_interface *oi;
88 struct ospf *ospf;
90 if (!(ospf = ospf_lookup ()))
91 return NULL;
93 for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi))
94 if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
95 if (IPV4_ADDR_SAME (&address, &oi->address->u.prefix4))
96 return oi;
98 return NULL;
101 struct ospf_interface *
102 ospf_apiserver_if_lookup_by_ifp (struct interface *ifp)
104 struct listnode *node, *nnode;
105 struct ospf_interface *oi;
106 struct ospf *ospf;
108 if (!(ospf = ospf_lookup ()));
109 return NULL;
111 for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi))
112 if (oi->ifp == ifp)
113 return oi;
115 return NULL;
118 /* -----------------------------------------------------------
119 * Initialization
120 * -----------------------------------------------------------
123 unsigned short
124 ospf_apiserver_getport (void)
126 struct servent *sp = getservbyname ("ospfapi", "tcp");
128 return sp ? ntohs (sp->s_port) : OSPF_API_SYNC_PORT;
131 /* Initialize OSPF API module. Invoked from ospf_opaque_init() */
133 ospf_apiserver_init (void)
135 int fd;
136 int rc = -1;
138 /* Create new socket for synchronous messages. */
139 fd = ospf_apiserver_serv_sock_family (ospf_apiserver_getport (), AF_INET);
141 if (fd < 0)
142 goto out;
144 /* Schedule new thread that handles accepted connections. */
145 ospf_apiserver_event (OSPF_APISERVER_ACCEPT, fd, NULL);
147 /* Initialize list that keeps track of all connections. */
148 apiserver_list = list_new ();
150 /* Register opaque-independent call back functions. These functions
151 are invoked on ISM, NSM changes and LSA update and LSA deletes */
152 rc =
153 ospf_register_opaque_functab (0 /* all LSAs */,
154 0 /* all opaque types */,
155 ospf_apiserver_new_if,
156 ospf_apiserver_del_if,
157 ospf_apiserver_ism_change,
158 ospf_apiserver_nsm_change,
159 NULL,
160 NULL,
161 NULL,
162 NULL, /* ospf_apiserver_show_info */
163 NULL, /* originator_func */
164 NULL, /* ospf_apiserver_lsa_refresher */
165 ospf_apiserver_lsa_update,
166 ospf_apiserver_lsa_delete);
167 if (rc != 0)
169 zlog_warn ("ospf_apiserver_init: Failed to register opaque type [0/0]");
172 rc = 0;
174 out:
175 return rc;
178 /* Terminate OSPF API module. */
179 void
180 ospf_apiserver_term (void)
182 struct ospf_apiserver *apiserv;
184 /* Unregister wildcard [0/0] type */
185 ospf_delete_opaque_functab (0 /* all LSAs */,
186 0 /* all opaque types */);
189 * Free all client instances. ospf_apiserver_free removes the node
190 * from the list, so we examine the head of the list anew each time.
192 while ( apiserver_list &&
193 (apiserv = listgetdata (listhead (apiserver_list))) != NULL)
194 ospf_apiserver_free (apiserv);
196 /* Free client list itself */
197 if (apiserver_list)
198 list_delete (apiserver_list);
200 /* Free wildcard list */
201 /* XXX */
204 static struct ospf_apiserver *
205 lookup_apiserver (u_char lsa_type, u_char opaque_type)
207 struct listnode *n1, *n2;
208 struct registered_opaque_type *r;
209 struct ospf_apiserver *apiserv, *found = NULL;
211 /* XXX: this approaches O(n**2) */
212 for (ALL_LIST_ELEMENTS_RO (apiserver_list, n1, apiserv))
214 for (ALL_LIST_ELEMENTS_RO (apiserv->opaque_types, n2, r))
215 if (r->lsa_type == lsa_type && r->opaque_type == opaque_type)
217 found = apiserv;
218 goto out;
221 out:
222 return found;
225 static struct ospf_apiserver *
226 lookup_apiserver_by_lsa (struct ospf_lsa *lsa)
228 struct lsa_header *lsah = lsa->data;
229 struct ospf_apiserver *found = NULL;
231 if (IS_OPAQUE_LSA (lsah->type))
233 found = lookup_apiserver (lsah->type,
234 GET_OPAQUE_TYPE (ntohl (lsah->id.s_addr)));
236 return found;
239 /* -----------------------------------------------------------
240 * Followings are functions to manage client connections.
241 * -----------------------------------------------------------
243 static int
244 ospf_apiserver_new_lsa_hook (struct ospf_lsa *lsa)
246 if (IS_DEBUG_OSPF_EVENT)
247 zlog_debug ("API: Put LSA(%p)[%s] into reserve, total=%ld", lsa, dump_lsa_key (lsa), lsa->lsdb->total);
248 return 0;
251 static int
252 ospf_apiserver_del_lsa_hook (struct ospf_lsa *lsa)
254 if (IS_DEBUG_OSPF_EVENT)
255 zlog_debug ("API: Get LSA(%p)[%s] from reserve, total=%ld", lsa, dump_lsa_key (lsa), lsa->lsdb->total);
256 return 0;
259 /* Allocate new connection structure. */
260 struct ospf_apiserver *
261 ospf_apiserver_new (int fd_sync, int fd_async)
263 struct ospf_apiserver *new =
264 XMALLOC (MTYPE_OSPF_APISERVER, sizeof (struct ospf_apiserver));
266 new->filter =
267 XMALLOC (MTYPE_OSPF_APISERVER_MSGFILTER, sizeof (struct lsa_filter_type));
269 new->fd_sync = fd_sync;
270 new->fd_async = fd_async;
272 /* list of registered opaque types that application uses */
273 new->opaque_types = list_new ();
275 /* Initialize temporary strage for LSA instances to be refreshed. */
276 memset (&new->reserve, 0, sizeof (struct ospf_lsdb));
277 ospf_lsdb_init (&new->reserve);
279 new->reserve.new_lsa_hook = ospf_apiserver_new_lsa_hook; /* debug */
280 new->reserve.del_lsa_hook = ospf_apiserver_del_lsa_hook; /* debug */
282 new->out_sync_fifo = msg_fifo_new ();
283 new->out_async_fifo = msg_fifo_new ();
284 new->t_sync_read = NULL;
285 #ifdef USE_ASYNC_READ
286 new->t_async_read = NULL;
287 #endif /* USE_ASYNC_READ */
288 new->t_sync_write = NULL;
289 new->t_async_write = NULL;
291 new->filter->typemask = 0; /* filter all LSAs */
292 new->filter->origin = ANY_ORIGIN;
293 new->filter->num_areas = 0;
295 return new;
298 void
299 ospf_apiserver_event (enum event event, int fd,
300 struct ospf_apiserver *apiserv)
302 struct thread *apiserver_serv_thread;
304 switch (event)
306 case OSPF_APISERVER_ACCEPT:
307 apiserver_serv_thread =
308 thread_add_read (master, ospf_apiserver_accept, apiserv, fd);
309 break;
310 case OSPF_APISERVER_SYNC_READ:
311 apiserv->t_sync_read =
312 thread_add_read (master, ospf_apiserver_read, apiserv, fd);
313 break;
314 #ifdef USE_ASYNC_READ
315 case OSPF_APISERVER_ASYNC_READ:
316 apiserv->t_async_read =
317 thread_add_read (master, ospf_apiserver_read, apiserv, fd);
318 break;
319 #endif /* USE_ASYNC_READ */
320 case OSPF_APISERVER_SYNC_WRITE:
321 if (!apiserv->t_sync_write)
323 apiserv->t_sync_write =
324 thread_add_write (master, ospf_apiserver_sync_write, apiserv, fd);
326 break;
327 case OSPF_APISERVER_ASYNC_WRITE:
328 if (!apiserv->t_async_write)
330 apiserv->t_async_write =
331 thread_add_write (master, ospf_apiserver_async_write, apiserv, fd);
333 break;
337 /* Free instance. First unregister all opaque types used by
338 application, flush opaque LSAs injected by application
339 from network and close connection. */
340 void
341 ospf_apiserver_free (struct ospf_apiserver *apiserv)
343 struct listnode *node;
345 /* Cancel read and write threads. */
346 if (apiserv->t_sync_read)
348 thread_cancel (apiserv->t_sync_read);
350 #ifdef USE_ASYNC_READ
351 if (apiserv->t_async_read)
353 thread_cancel (apiserv->t_async_read);
355 #endif /* USE_ASYNC_READ */
356 if (apiserv->t_sync_write)
358 thread_cancel (apiserv->t_sync_write);
361 if (apiserv->t_async_write)
363 thread_cancel (apiserv->t_async_write);
366 /* Unregister all opaque types that application registered
367 and flush opaque LSAs if still in LSDB. */
369 while ((node = listhead (apiserv->opaque_types)) != NULL)
371 struct registered_opaque_type *regtype = listgetdata(node);
373 ospf_apiserver_unregister_opaque_type (apiserv, regtype->lsa_type,
374 regtype->opaque_type);
378 /* Close connections to OSPFd. */
379 if (apiserv->fd_sync > 0)
381 close (apiserv->fd_sync);
384 if (apiserv->fd_async > 0)
386 close (apiserv->fd_async);
389 /* Free fifos */
390 msg_fifo_free (apiserv->out_sync_fifo);
391 msg_fifo_free (apiserv->out_async_fifo);
393 /* Clear temporary strage for LSA instances to be refreshed. */
394 ospf_lsdb_delete_all (&apiserv->reserve);
395 ospf_lsdb_cleanup (&apiserv->reserve);
397 /* Remove from the list of active clients. */
398 listnode_delete (apiserver_list, apiserv);
400 if (IS_DEBUG_OSPF_EVENT)
401 zlog_debug ("API: Delete apiserv(%p), total#(%d)", apiserv, apiserver_list->count);
403 /* And free instance. */
404 XFREE (MTYPE_OSPF_APISERVER, apiserv);
408 ospf_apiserver_read (struct thread *thread)
410 struct ospf_apiserver *apiserv;
411 struct msg *msg;
412 int fd;
413 int rc = -1;
414 enum event event;
416 apiserv = THREAD_ARG (thread);
417 fd = THREAD_FD (thread);
419 if (fd == apiserv->fd_sync)
421 event = OSPF_APISERVER_SYNC_READ;
422 apiserv->t_sync_read = NULL;
424 if (IS_DEBUG_OSPF_EVENT)
425 zlog_debug ("API: ospf_apiserver_read: Peer: %s/%u",
426 inet_ntoa (apiserv->peer_sync.sin_addr),
427 ntohs (apiserv->peer_sync.sin_port));
429 #ifdef USE_ASYNC_READ
430 else if (fd == apiserv->fd_async)
432 event = OSPF_APISERVER_ASYNC_READ;
433 apiserv->t_async_read = NULL;
435 if (IS_DEBUG_OSPF_EVENT)
436 zlog_debug ("API: ospf_apiserver_read: Peer: %s/%u",
437 inet_ntoa (apiserv->peer_async.sin_addr),
438 ntohs (apiserv->peer_async.sin_port));
440 #endif /* USE_ASYNC_READ */
441 else
443 zlog_warn ("ospf_apiserver_read: Unknown fd(%d)", fd);
444 ospf_apiserver_free (apiserv);
445 goto out;
448 /* Read message from fd. */
449 msg = msg_read (fd);
450 if (msg == NULL)
452 zlog_warn
453 ("ospf_apiserver_read: read failed on fd=%d, closing connection", fd);
455 /* Perform cleanup. */
456 ospf_apiserver_free (apiserv);
457 goto out;
460 if (IS_DEBUG_OSPF_EVENT)
461 msg_print (msg);
463 /* Dispatch to corresponding message handler. */
464 rc = ospf_apiserver_handle_msg (apiserv, msg);
466 /* Prepare for next message, add read thread. */
467 ospf_apiserver_event (event, fd, apiserv);
469 msg_free (msg);
471 out:
472 return rc;
476 ospf_apiserver_sync_write (struct thread *thread)
478 struct ospf_apiserver *apiserv;
479 struct msg *msg;
480 int fd;
481 int rc = -1;
483 apiserv = THREAD_ARG (thread);
484 assert (apiserv);
485 fd = THREAD_FD (thread);
487 apiserv->t_sync_write = NULL;
489 /* Sanity check */
490 if (fd != apiserv->fd_sync)
492 zlog_warn ("ospf_apiserver_sync_write: Unknown fd=%d", fd);
493 goto out;
496 if (IS_DEBUG_OSPF_EVENT)
497 zlog_debug ("API: ospf_apiserver_sync_write: Peer: %s/%u",
498 inet_ntoa (apiserv->peer_sync.sin_addr),
499 ntohs (apiserv->peer_sync.sin_port));
501 /* Check whether there is really a message in the fifo. */
502 msg = msg_fifo_pop (apiserv->out_sync_fifo);
503 if (!msg)
505 zlog_warn ("API: ospf_apiserver_sync_write: No message in Sync-FIFO?");
506 return 0;
509 if (IS_DEBUG_OSPF_EVENT)
510 msg_print (msg);
512 rc = msg_write (fd, msg);
514 /* Once a message is dequeued, it should be freed anyway. */
515 msg_free (msg);
517 if (rc < 0)
519 zlog_warn
520 ("ospf_apiserver_sync_write: write failed on fd=%d", fd);
521 goto out;
525 /* If more messages are in sync message fifo, schedule write thread. */
526 if (msg_fifo_head (apiserv->out_sync_fifo))
528 ospf_apiserver_event (OSPF_APISERVER_SYNC_WRITE, apiserv->fd_sync,
529 apiserv);
532 out:
534 if (rc < 0)
536 /* Perform cleanup and disconnect with peer */
537 ospf_apiserver_free (apiserv);
540 return rc;
545 ospf_apiserver_async_write (struct thread *thread)
547 struct ospf_apiserver *apiserv;
548 struct msg *msg;
549 int fd;
550 int rc = -1;
552 apiserv = THREAD_ARG (thread);
553 assert (apiserv);
554 fd = THREAD_FD (thread);
556 apiserv->t_async_write = NULL;
558 /* Sanity check */
559 if (fd != apiserv->fd_async)
561 zlog_warn ("ospf_apiserver_async_write: Unknown fd=%d", fd);
562 goto out;
565 if (IS_DEBUG_OSPF_EVENT)
566 zlog_debug ("API: ospf_apiserver_async_write: Peer: %s/%u",
567 inet_ntoa (apiserv->peer_async.sin_addr),
568 ntohs (apiserv->peer_async.sin_port));
570 /* Check whether there is really a message in the fifo. */
571 msg = msg_fifo_pop (apiserv->out_async_fifo);
572 if (!msg)
574 zlog_warn ("API: ospf_apiserver_async_write: No message in Async-FIFO?");
575 return 0;
578 if (IS_DEBUG_OSPF_EVENT)
579 msg_print (msg);
581 rc = msg_write (fd, msg);
583 /* Once a message is dequeued, it should be freed anyway. */
584 msg_free (msg);
586 if (rc < 0)
588 zlog_warn
589 ("ospf_apiserver_async_write: write failed on fd=%d", fd);
590 goto out;
594 /* If more messages are in async message fifo, schedule write thread. */
595 if (msg_fifo_head (apiserv->out_async_fifo))
597 ospf_apiserver_event (OSPF_APISERVER_ASYNC_WRITE, apiserv->fd_async,
598 apiserv);
601 out:
603 if (rc < 0)
605 /* Perform cleanup and disconnect with peer */
606 ospf_apiserver_free (apiserv);
609 return rc;
614 ospf_apiserver_serv_sock_family (unsigned short port, int family)
616 union sockunion su;
617 int accept_sock;
618 int rc;
620 memset (&su, 0, sizeof (union sockunion));
621 su.sa.sa_family = family;
623 /* Make new socket */
624 accept_sock = sockunion_stream_socket (&su);
625 if (accept_sock < 0)
626 return accept_sock;
628 /* This is a server, so reuse address and port */
629 sockopt_reuseaddr (accept_sock);
630 sockopt_reuseport (accept_sock);
632 /* Bind socket to address and given port. */
633 rc = sockunion_bind (accept_sock, &su, port, NULL);
634 if (rc < 0)
636 close (accept_sock); /* Close socket */
637 return rc;
640 /* Listen socket under queue length 3. */
641 rc = listen (accept_sock, 3);
642 if (rc < 0)
644 zlog_warn ("ospf_apiserver_serv_sock_family: listen: %s",
645 safe_strerror (errno));
646 close (accept_sock); /* Close socket */
647 return rc;
649 return accept_sock;
653 /* Accept connection request from external applications. For each
654 accepted connection allocate own connection instance. */
656 ospf_apiserver_accept (struct thread *thread)
658 int accept_sock;
659 int new_sync_sock;
660 int new_async_sock;
661 union sockunion su;
662 struct ospf_apiserver *apiserv;
663 struct sockaddr_in peer_async;
664 struct sockaddr_in peer_sync;
665 unsigned int peerlen;
666 int ret;
668 /* THREAD_ARG (thread) is NULL */
669 accept_sock = THREAD_FD (thread);
671 /* Keep hearing on socket for further connections. */
672 ospf_apiserver_event (OSPF_APISERVER_ACCEPT, accept_sock, NULL);
674 memset (&su, 0, sizeof (union sockunion));
675 /* Accept connection for synchronous messages */
676 new_sync_sock = sockunion_accept (accept_sock, &su);
677 if (new_sync_sock < 0)
679 zlog_warn ("ospf_apiserver_accept: accept: %s", safe_strerror (errno));
680 return -1;
683 /* Get port address and port number of peer to make reverse connection.
684 The reverse channel uses the port number of the peer port+1. */
686 memset(&peer_sync, 0, sizeof(struct sockaddr_in));
687 peerlen = sizeof (struct sockaddr_in);
689 ret = getpeername (new_sync_sock, (struct sockaddr *)&peer_sync, &peerlen);
690 if (ret < 0)
692 zlog_warn ("ospf_apiserver_accept: getpeername: %s", safe_strerror (errno));
693 close (new_sync_sock);
694 return -1;
697 if (IS_DEBUG_OSPF_EVENT)
698 zlog_debug ("API: ospf_apiserver_accept: New peer: %s/%u",
699 inet_ntoa (peer_sync.sin_addr), ntohs (peer_sync.sin_port));
701 /* Create new socket for asynchronous messages. */
702 peer_async = peer_sync;
703 peer_async.sin_port = htons(ntohs(peer_sync.sin_port) + 1);
705 /* Check if remote port number to make reverse connection is valid one. */
706 if (ntohs (peer_async.sin_port) == ospf_apiserver_getport ())
708 zlog_warn ("API: ospf_apiserver_accept: Peer(%s/%u): Invalid async port number?",
709 inet_ntoa (peer_async.sin_addr), ntohs (peer_async.sin_port));
710 close (new_sync_sock);
711 return -1;
714 new_async_sock = socket (AF_INET, SOCK_STREAM, 0);
715 if (new_async_sock < 0)
717 zlog_warn ("ospf_apiserver_accept: socket: %s", safe_strerror (errno));
718 close (new_sync_sock);
719 return -1;
722 ret = connect (new_async_sock, (struct sockaddr *) &peer_async,
723 sizeof (struct sockaddr_in));
725 if (ret < 0)
727 zlog_warn ("ospf_apiserver_accept: connect: %s", safe_strerror (errno));
728 close (new_sync_sock);
729 close (new_async_sock);
730 return -1;
733 #ifdef USE_ASYNC_READ
734 #else /* USE_ASYNC_READ */
735 /* Make the asynchronous channel write-only. */
736 ret = shutdown (new_async_sock, SHUT_RD);
737 if (ret < 0)
739 zlog_warn ("ospf_apiserver_accept: shutdown: %s", safe_strerror (errno));
740 close (new_sync_sock);
741 close (new_async_sock);
742 return -1;
744 #endif /* USE_ASYNC_READ */
746 /* Allocate new server-side connection structure */
747 apiserv = ospf_apiserver_new (new_sync_sock, new_async_sock);
749 /* Add to active connection list */
750 listnode_add (apiserver_list, apiserv);
751 apiserv->peer_sync = peer_sync;
752 apiserv->peer_async = peer_async;
754 /* And add read threads for new connection */
755 ospf_apiserver_event (OSPF_APISERVER_SYNC_READ, new_sync_sock, apiserv);
756 #ifdef USE_ASYNC_READ
757 ospf_apiserver_event (OSPF_APISERVER_ASYNC_READ, new_async_sock, apiserv);
758 #endif /* USE_ASYNC_READ */
760 if (IS_DEBUG_OSPF_EVENT)
761 zlog_debug ("API: New apiserv(%p), total#(%d)", apiserv, apiserver_list->count);
763 return 0;
767 /* -----------------------------------------------------------
768 * Send reply with return code to client application
769 * -----------------------------------------------------------
772 static int
773 ospf_apiserver_send_msg (struct ospf_apiserver *apiserv, struct msg *msg)
775 struct msg_fifo *fifo;
776 struct msg *msg2;
777 enum event event;
778 int fd;
780 switch (msg->hdr.msgtype)
782 case MSG_REPLY:
783 fifo = apiserv->out_sync_fifo;
784 fd = apiserv->fd_sync;
785 event = OSPF_APISERVER_SYNC_WRITE;
786 break;
787 case MSG_READY_NOTIFY:
788 case MSG_LSA_UPDATE_NOTIFY:
789 case MSG_LSA_DELETE_NOTIFY:
790 case MSG_NEW_IF:
791 case MSG_DEL_IF:
792 case MSG_ISM_CHANGE:
793 case MSG_NSM_CHANGE:
794 fifo = apiserv->out_async_fifo;
795 fd = apiserv->fd_async;
796 event = OSPF_APISERVER_ASYNC_WRITE;
797 break;
798 default:
799 zlog_warn ("ospf_apiserver_send_msg: Unknown message type %d",
800 msg->hdr.msgtype);
801 return -1;
804 /* Make a copy of the message and put in the fifo. Once the fifo
805 gets drained by the write thread, the message will be freed. */
806 /* NB: Given "msg" is untouched in this function. */
807 msg2 = msg_dup (msg);
809 /* Enqueue message into corresponding fifo queue */
810 msg_fifo_push (fifo, msg2);
812 /* Schedule write thread */
813 ospf_apiserver_event (event, fd, apiserv);
814 return 0;
818 ospf_apiserver_send_reply (struct ospf_apiserver *apiserv, u_int32_t seqnr,
819 u_char rc)
821 struct msg *msg = new_msg_reply (seqnr, rc);
822 int ret;
824 if (!msg)
826 zlog_warn ("ospf_apiserver_send_reply: msg_new failed");
827 #ifdef NOTYET
828 /* Cannot allocate new message. What should we do? */
829 ospf_apiserver_free (apiserv);
830 #endif
831 return -1;
834 ret = ospf_apiserver_send_msg (apiserv, msg);
835 msg_free (msg);
836 return ret;
840 /* -----------------------------------------------------------
841 * Generic message dispatching handler function
842 * -----------------------------------------------------------
846 ospf_apiserver_handle_msg (struct ospf_apiserver *apiserv, struct msg *msg)
848 int rc;
850 /* Call corresponding message handler function. */
851 switch (msg->hdr.msgtype)
853 case MSG_REGISTER_OPAQUETYPE:
854 rc = ospf_apiserver_handle_register_opaque_type (apiserv, msg);
855 break;
856 case MSG_UNREGISTER_OPAQUETYPE:
857 rc = ospf_apiserver_handle_unregister_opaque_type (apiserv, msg);
858 break;
859 case MSG_REGISTER_EVENT:
860 rc = ospf_apiserver_handle_register_event (apiserv, msg);
861 break;
862 case MSG_SYNC_LSDB:
863 rc = ospf_apiserver_handle_sync_lsdb (apiserv, msg);
864 break;
865 case MSG_ORIGINATE_REQUEST:
866 rc = ospf_apiserver_handle_originate_request (apiserv, msg);
867 break;
868 case MSG_DELETE_REQUEST:
869 rc = ospf_apiserver_handle_delete_request (apiserv, msg);
870 break;
871 default:
872 zlog_warn ("ospf_apiserver_handle_msg: Unknown message type: %d",
873 msg->hdr.msgtype);
874 rc = -1;
876 return rc;
880 /* -----------------------------------------------------------
881 * Following are functions for opaque type registration
882 * -----------------------------------------------------------
886 ospf_apiserver_register_opaque_type (struct ospf_apiserver *apiserv,
887 u_char lsa_type, u_char opaque_type)
889 struct registered_opaque_type *regtype;
890 int (*originator_func) (void *arg);
891 int rc;
893 switch (lsa_type)
895 case OSPF_OPAQUE_LINK_LSA:
896 originator_func = ospf_apiserver_lsa9_originator;
897 break;
898 case OSPF_OPAQUE_AREA_LSA:
899 originator_func = ospf_apiserver_lsa10_originator;
900 break;
901 case OSPF_OPAQUE_AS_LSA:
902 originator_func = ospf_apiserver_lsa11_originator;
903 break;
904 default:
905 zlog_warn ("ospf_apiserver_register_opaque_type: lsa_type(%d)",
906 lsa_type);
907 return OSPF_API_ILLEGALLSATYPE;
911 /* Register opaque function table */
912 /* NB: Duplicated registration will be detected inside the function. */
913 rc =
914 ospf_register_opaque_functab (lsa_type, opaque_type,
915 NULL, /* ospf_apiserver_new_if */
916 NULL, /* ospf_apiserver_del_if */
917 NULL, /* ospf_apiserver_ism_change */
918 NULL, /* ospf_apiserver_nsm_change */
919 NULL,
920 NULL,
921 NULL,
922 ospf_apiserver_show_info,
923 originator_func,
924 ospf_apiserver_lsa_refresher,
925 NULL, /* ospf_apiserver_lsa_update */
926 NULL /* ospf_apiserver_lsa_delete */);
928 if (rc != 0)
930 zlog_warn ("Failed to register opaque type [%d/%d]",
931 lsa_type, opaque_type);
932 return OSPF_API_OPAQUETYPEINUSE;
935 /* Remember the opaque type that application registers so when
936 connection shuts down, we can flush all LSAs of this opaque
937 type. */
939 regtype =
940 XCALLOC (MTYPE_OSPF_APISERVER, sizeof (struct registered_opaque_type));
941 regtype->lsa_type = lsa_type;
942 regtype->opaque_type = opaque_type;
944 /* Add to list of registered opaque types */
945 listnode_add (apiserv->opaque_types, regtype);
947 if (IS_DEBUG_OSPF_EVENT)
948 zlog_debug ("API: Add LSA-type(%d)/Opaque-type(%d) into"
949 " apiserv(%p), total#(%d)",
950 lsa_type, opaque_type, apiserv,
951 listcount (apiserv->opaque_types));
953 return 0;
957 ospf_apiserver_unregister_opaque_type (struct ospf_apiserver *apiserv,
958 u_char lsa_type, u_char opaque_type)
960 struct listnode *node, *nnode;
961 struct registered_opaque_type *regtype;
963 for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node, nnode, regtype))
965 /* Check if we really registered this opaque type */
966 if (regtype->lsa_type == lsa_type &&
967 regtype->opaque_type == opaque_type)
970 /* Yes, we registered this opaque type. Flush
971 all existing opaque LSAs of this type */
973 ospf_apiserver_flush_opaque_lsa (apiserv, lsa_type, opaque_type);
974 ospf_delete_opaque_functab (lsa_type, opaque_type);
976 /* Remove from list of registered opaque types */
977 listnode_delete (apiserv->opaque_types, regtype);
979 if (IS_DEBUG_OSPF_EVENT)
980 zlog_debug ("API: Del LSA-type(%d)/Opaque-type(%d)"
981 " from apiserv(%p), total#(%d)",
982 lsa_type, opaque_type, apiserv,
983 listcount (apiserv->opaque_types));
985 return 0;
989 /* Opaque type is not registered */
990 zlog_warn ("Failed to unregister opaque type [%d/%d]",
991 lsa_type, opaque_type);
992 return OSPF_API_OPAQUETYPENOTREGISTERED;
996 static int
997 apiserver_is_opaque_type_registered (struct ospf_apiserver *apiserv,
998 u_char lsa_type, u_char opaque_type)
1000 struct listnode *node, *nnode;
1001 struct registered_opaque_type *regtype;
1003 /* XXX: how many types are there? if few, why not just a bitmap? */
1004 for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node, nnode, regtype))
1006 /* Check if we really registered this opaque type */
1007 if (regtype->lsa_type == lsa_type &&
1008 regtype->opaque_type == opaque_type)
1010 /* Yes registered */
1011 return 1;
1014 /* Not registered */
1015 return 0;
1019 ospf_apiserver_handle_register_opaque_type (struct ospf_apiserver *apiserv,
1020 struct msg *msg)
1022 struct msg_register_opaque_type *rmsg;
1023 u_char lsa_type;
1024 u_char opaque_type;
1025 int rc = 0;
1027 /* Extract parameters from register opaque type message */
1028 rmsg = (struct msg_register_opaque_type *) STREAM_DATA (msg->s);
1030 lsa_type = rmsg->lsatype;
1031 opaque_type = rmsg->opaquetype;
1033 rc = ospf_apiserver_register_opaque_type (apiserv, lsa_type, opaque_type);
1035 /* Send a reply back to client including return code */
1036 rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc);
1037 if (rc < 0)
1038 goto out;
1040 /* Now inform application about opaque types that are ready */
1041 switch (lsa_type)
1043 case OSPF_OPAQUE_LINK_LSA:
1044 ospf_apiserver_notify_ready_type9 (apiserv);
1045 break;
1046 case OSPF_OPAQUE_AREA_LSA:
1047 ospf_apiserver_notify_ready_type10 (apiserv);
1048 break;
1049 case OSPF_OPAQUE_AS_LSA:
1050 ospf_apiserver_notify_ready_type11 (apiserv);
1051 break;
1053 out:
1054 return rc;
1058 /* Notify specific client about all opaque types 9 that are ready. */
1059 void
1060 ospf_apiserver_notify_ready_type9 (struct ospf_apiserver *apiserv)
1062 struct listnode *node, *nnode;
1063 struct listnode *node2, *nnode2;
1064 struct ospf *ospf;
1065 struct ospf_interface *oi;
1066 struct registered_opaque_type *r;
1068 ospf = ospf_lookup ();
1070 for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi))
1072 /* Check if this interface is indeed ready for type 9 */
1073 if (!ospf_apiserver_is_ready_type9 (oi))
1074 continue;
1076 /* Check for registered opaque type 9 types */
1077 /* XXX: loop-de-loop - optimise me */
1078 for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r))
1080 struct msg *msg;
1082 if (r->lsa_type == OSPF_OPAQUE_LINK_LSA)
1085 /* Yes, this opaque type is ready */
1086 msg = new_msg_ready_notify (0, OSPF_OPAQUE_LINK_LSA,
1087 r->opaque_type,
1088 oi->address->u.prefix4);
1089 if (!msg)
1091 zlog_warn ("apiserver_notify_ready_type9: msg_new failed");
1092 #ifdef NOTYET
1093 /* Cannot allocate new message. What should we do? */
1094 ospf_apiserver_free (apiserv);
1095 #endif
1096 goto out;
1098 ospf_apiserver_send_msg (apiserv, msg);
1099 msg_free (msg);
1104 out:
1105 return;
1109 /* Notify specific client about all opaque types 10 that are ready. */
1110 void
1111 ospf_apiserver_notify_ready_type10 (struct ospf_apiserver *apiserv)
1113 struct listnode *node, *nnode;
1114 struct listnode *node2, *nnode2;
1115 struct ospf *ospf;
1116 struct ospf_area *area;
1118 ospf = ospf_lookup ();
1120 for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area))
1122 struct registered_opaque_type *r;
1124 if (!ospf_apiserver_is_ready_type10 (area))
1126 continue;
1129 /* Check for registered opaque type 10 types */
1130 /* XXX: loop in loop - optimise me */
1131 for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r))
1133 struct msg *msg;
1135 if (r->lsa_type == OSPF_OPAQUE_AREA_LSA)
1137 /* Yes, this opaque type is ready */
1138 msg =
1139 new_msg_ready_notify (0, OSPF_OPAQUE_AREA_LSA,
1140 r->opaque_type, area->area_id);
1141 if (!msg)
1143 zlog_warn ("apiserver_notify_ready_type10: msg_new failed");
1144 #ifdef NOTYET
1145 /* Cannot allocate new message. What should we do? */
1146 ospf_apiserver_free (apiserv);
1147 #endif
1148 goto out;
1150 ospf_apiserver_send_msg (apiserv, msg);
1151 msg_free (msg);
1156 out:
1157 return;
1160 /* Notify specific client about all opaque types 11 that are ready */
1161 void
1162 ospf_apiserver_notify_ready_type11 (struct ospf_apiserver *apiserv)
1164 struct listnode *node, *nnode;
1165 struct ospf *ospf;
1166 struct registered_opaque_type *r;
1168 ospf = ospf_lookup ();
1170 /* Can type 11 be originated? */
1171 if (!ospf_apiserver_is_ready_type11 (ospf))
1172 goto out;
1174 /* Check for registered opaque type 11 types */
1175 for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node, nnode, r))
1177 struct msg *msg;
1178 struct in_addr noarea_id = { .s_addr = 0L };
1180 if (r->lsa_type == OSPF_OPAQUE_AS_LSA)
1182 /* Yes, this opaque type is ready */
1183 msg = new_msg_ready_notify (0, OSPF_OPAQUE_AS_LSA,
1184 r->opaque_type, noarea_id);
1186 if (!msg)
1188 zlog_warn ("apiserver_notify_ready_type11: msg_new failed");
1189 #ifdef NOTYET
1190 /* Cannot allocate new message. What should we do? */
1191 ospf_apiserver_free (apiserv);
1192 #endif
1193 goto out;
1195 ospf_apiserver_send_msg (apiserv, msg);
1196 msg_free (msg);
1200 out:
1201 return;
1205 ospf_apiserver_handle_unregister_opaque_type (struct ospf_apiserver *apiserv,
1206 struct msg *msg)
1208 struct msg_unregister_opaque_type *umsg;
1209 u_char ltype;
1210 u_char otype;
1211 int rc = 0;
1213 /* Extract parameters from unregister opaque type message */
1214 umsg = (struct msg_unregister_opaque_type *) STREAM_DATA (msg->s);
1216 ltype = umsg->lsatype;
1217 otype = umsg->opaquetype;
1219 rc = ospf_apiserver_unregister_opaque_type (apiserv, ltype, otype);
1221 /* Send a reply back to client including return code */
1222 rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc);
1224 return rc;
1228 /* -----------------------------------------------------------
1229 * Following are functions for event (filter) registration.
1230 * -----------------------------------------------------------
1233 ospf_apiserver_handle_register_event (struct ospf_apiserver *apiserv,
1234 struct msg *msg)
1236 struct msg_register_event *rmsg;
1237 int rc;
1238 u_int32_t seqnum;
1240 rmsg = (struct msg_register_event *) STREAM_DATA (msg->s);
1242 /* Get request sequence number */
1243 seqnum = msg_get_seq (msg);
1245 /* Free existing filter in apiserv. */
1246 XFREE (MTYPE_OSPF_APISERVER_MSGFILTER, apiserv->filter);
1247 /* Alloc new space for filter. */
1249 apiserv->filter = XMALLOC (MTYPE_OSPF_APISERVER_MSGFILTER,
1250 ntohs (msg->hdr.msglen));
1251 if (apiserv->filter)
1253 /* copy it over. */
1254 memcpy (apiserv->filter, &rmsg->filter, ntohs (msg->hdr.msglen));
1255 rc = OSPF_API_OK;
1257 else
1259 rc = OSPF_API_NOMEMORY;
1261 /* Send a reply back to client with return code */
1262 rc = ospf_apiserver_send_reply (apiserv, seqnum, rc);
1263 return rc;
1267 /* -----------------------------------------------------------
1268 * Followings are functions for LSDB synchronization.
1269 * -----------------------------------------------------------
1272 static int
1273 apiserver_sync_callback (struct ospf_lsa *lsa, void *p_arg, int int_arg)
1275 struct ospf_apiserver *apiserv;
1276 int seqnum;
1277 struct msg *msg;
1278 struct param_t
1280 struct ospf_apiserver *apiserv;
1281 struct lsa_filter_type *filter;
1283 *param;
1284 int rc = -1;
1286 /* Sanity check */
1287 assert (lsa->data);
1288 assert (p_arg);
1290 param = (struct param_t *) p_arg;
1291 apiserv = param->apiserv;
1292 seqnum = (u_int32_t) int_arg;
1294 /* Check origin in filter. */
1295 if ((param->filter->origin == ANY_ORIGIN) ||
1296 (param->filter->origin == (lsa->flags & OSPF_LSA_SELF)))
1299 /* Default area for AS-External and Opaque11 LSAs */
1300 struct in_addr area_id = { .s_addr = 0L };
1302 /* Default interface for non Opaque9 LSAs */
1303 struct in_addr ifaddr = { .s_addr = 0L };
1305 if (lsa->area)
1307 area_id = lsa->area->area_id;
1309 if (lsa->data->type == OSPF_OPAQUE_LINK_LSA)
1311 ifaddr = lsa->oi->address->u.prefix4;
1314 msg = new_msg_lsa_change_notify (MSG_LSA_UPDATE_NOTIFY,
1315 seqnum,
1316 ifaddr, area_id,
1317 lsa->flags & OSPF_LSA_SELF, lsa->data);
1318 if (!msg)
1320 zlog_warn ("apiserver_sync_callback: new_msg_update failed");
1321 #ifdef NOTYET
1322 /* Cannot allocate new message. What should we do? */
1323 /* ospf_apiserver_free (apiserv);*//* Do nothing here XXX */
1324 #endif
1325 goto out;
1328 /* Send LSA */
1329 ospf_apiserver_send_msg (apiserv, msg);
1330 msg_free (msg);
1332 rc = 0;
1334 out:
1335 return rc;
1339 ospf_apiserver_handle_sync_lsdb (struct ospf_apiserver *apiserv,
1340 struct msg *msg)
1342 struct listnode *node, *nnode;
1343 u_int32_t seqnum;
1344 int rc = 0;
1345 struct msg_sync_lsdb *smsg;
1346 struct ospf_apiserver_param_t
1348 struct ospf_apiserver *apiserv;
1349 struct lsa_filter_type *filter;
1350 } param;
1351 u_int16_t mask;
1352 struct route_node *rn;
1353 struct ospf_lsa *lsa;
1354 struct ospf *ospf;
1355 struct ospf_area *area;
1357 ospf = ospf_lookup ();
1359 /* Get request sequence number */
1360 seqnum = msg_get_seq (msg);
1361 /* Set sync msg. */
1362 smsg = (struct msg_sync_lsdb *) STREAM_DATA (msg->s);
1364 /* Set parameter struct. */
1365 param.apiserv = apiserv;
1366 param.filter = &smsg->filter;
1368 /* Remember mask. */
1369 mask = ntohs (smsg->filter.typemask);
1371 /* Iterate over all areas. */
1372 for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area))
1374 int i;
1375 u_int32_t *area_id = NULL;
1377 /* Compare area_id with area_ids in sync request. */
1378 if ((i = smsg->filter.num_areas) > 0)
1380 /* Let area_id point to the list of area IDs,
1381 * which is at the end of smsg->filter. */
1382 area_id = (u_int32_t *) (&smsg->filter + 1);
1383 while (i)
1385 if (*area_id == area->area_id.s_addr)
1387 break;
1389 i--;
1390 area_id++;
1393 else
1395 i = 1;
1398 /* If area was found, then i>0 here. */
1399 if (i)
1401 /* Check msg type. */
1402 if (mask & Power2[OSPF_ROUTER_LSA])
1403 LSDB_LOOP (ROUTER_LSDB (area), rn, lsa)
1404 apiserver_sync_callback(lsa, (void *) &param, seqnum);
1405 if (mask & Power2[OSPF_NETWORK_LSA])
1406 LSDB_LOOP (NETWORK_LSDB (area), rn, lsa)
1407 apiserver_sync_callback(lsa, (void *) &param, seqnum);
1408 if (mask & Power2[OSPF_SUMMARY_LSA])
1409 LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa)
1410 apiserver_sync_callback(lsa, (void *) &param, seqnum);
1411 if (mask & Power2[OSPF_ASBR_SUMMARY_LSA])
1412 LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa)
1413 apiserver_sync_callback(lsa, (void *) &param, seqnum);
1414 if (mask & Power2[OSPF_OPAQUE_LINK_LSA])
1415 LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
1416 apiserver_sync_callback(lsa, (void *) &param, seqnum);
1417 if (mask & Power2[OSPF_OPAQUE_AREA_LSA])
1418 LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
1419 apiserver_sync_callback(lsa, (void *) &param, seqnum);
1423 /* For AS-external LSAs */
1424 if (ospf->lsdb)
1426 if (mask & Power2[OSPF_AS_EXTERNAL_LSA])
1427 LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
1428 apiserver_sync_callback(lsa, (void *) &param, seqnum);
1431 /* For AS-external opaque LSAs */
1432 if (ospf->lsdb)
1434 if (mask & Power2[OSPF_OPAQUE_AS_LSA])
1435 LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa)
1436 apiserver_sync_callback(lsa, (void *) &param, seqnum);
1439 /* Send a reply back to client with return code */
1440 rc = ospf_apiserver_send_reply (apiserv, seqnum, rc);
1441 return rc;
1445 /* -----------------------------------------------------------
1446 * Followings are functions to originate or update LSA
1447 * from an application.
1448 * -----------------------------------------------------------
1451 /* Create a new internal opaque LSA by taking prototype and filling in
1452 missing fields such as age, sequence number, advertising router,
1453 checksum and so on. The interface parameter is used for type 9
1454 LSAs, area parameter for type 10. Type 11 LSAs do neither need area
1455 nor interface. */
1457 struct ospf_lsa *
1458 ospf_apiserver_opaque_lsa_new (struct ospf_area *area,
1459 struct ospf_interface *oi,
1460 struct lsa_header *protolsa)
1462 struct stream *s;
1463 struct lsa_header *newlsa;
1464 struct ospf_lsa *new = NULL;
1465 u_char options = 0x0;
1466 u_int16_t length;
1468 struct ospf *ospf;
1470 ospf = ospf_lookup();
1471 assert(ospf);
1473 /* Create a stream for internal opaque LSA */
1474 if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL)
1476 zlog_warn ("ospf_apiserver_opaque_lsa_new: stream_new failed");
1477 return NULL;
1480 newlsa = (struct lsa_header *) STREAM_DATA (s);
1482 /* XXX If this is a link-local LSA or an AS-external LSA, how do we
1483 have to set options? */
1485 if (area)
1487 options = LSA_OPTIONS_GET (area);
1488 options |= LSA_OPTIONS_NSSA_GET (area);
1491 options |= OSPF_OPTION_O; /* Don't forget to set option bit */
1493 if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
1495 zlog_debug ("LSA[Type%d:%s]: Creating an Opaque-LSA instance",
1496 protolsa->type, inet_ntoa (protolsa->id));
1499 /* Set opaque-LSA header fields. */
1500 lsa_header_set (s, options, protolsa->type, protolsa->id,
1501 ospf->router_id);
1503 /* Set opaque-LSA body fields. */
1504 stream_put (s, ((u_char *) protolsa) + sizeof (struct lsa_header),
1505 ntohs (protolsa->length) - sizeof (struct lsa_header));
1507 /* Determine length of LSA. */
1508 length = stream_get_endp (s);
1509 newlsa->length = htons (length);
1511 /* Create OSPF LSA. */
1512 if ((new = ospf_lsa_new ()) == NULL)
1514 zlog_warn ("ospf_apiserver_opaque_lsa_new: ospf_lsa_new() ?");
1515 stream_free (s);
1516 return NULL;
1519 if ((new->data = ospf_lsa_data_new (length)) == NULL)
1521 zlog_warn ("ospf_apiserver_opaque_lsa_new: ospf_lsa_data_new() ?");
1522 ospf_lsa_unlock (&new);
1523 stream_free (s);
1524 return NULL;
1527 new->area = area;
1528 new->oi = oi;
1530 SET_FLAG (new->flags, OSPF_LSA_SELF);
1531 memcpy (new->data, newlsa, length);
1532 stream_free (s);
1534 return new;
1539 ospf_apiserver_is_ready_type9 (struct ospf_interface *oi)
1541 /* Type 9 opaque LSA can be originated if there is at least one
1542 active opaque-capable neighbor attached to the outgoing
1543 interface. */
1545 return (ospf_nbr_count_opaque_capable (oi) > 0);
1549 ospf_apiserver_is_ready_type10 (struct ospf_area *area)
1551 /* Type 10 opaque LSA can be originated if there is at least one
1552 interface belonging to the area that has an active opaque-capable
1553 neighbor. */
1554 struct listnode *node, *nnode;
1555 struct ospf_interface *oi;
1557 for (ALL_LIST_ELEMENTS (area->oiflist, node, nnode, oi))
1558 /* Is there an active neighbor attached to this interface? */
1559 if (ospf_apiserver_is_ready_type9 (oi))
1560 return 1;
1562 /* No active neighbor in area */
1563 return 0;
1567 ospf_apiserver_is_ready_type11 (struct ospf *ospf)
1569 /* Type 11 opaque LSA can be originated if there is at least one interface
1570 that has an active opaque-capable neighbor. */
1571 struct listnode *node, *nnode;
1572 struct ospf_interface *oi;
1574 for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi))
1575 /* Is there an active neighbor attached to this interface? */
1576 if (ospf_apiserver_is_ready_type9 (oi))
1577 return 1;
1579 /* No active neighbor at all */
1580 return 0;
1585 ospf_apiserver_handle_originate_request (struct ospf_apiserver *apiserv,
1586 struct msg *msg)
1588 struct msg_originate_request *omsg;
1589 struct lsa_header *data;
1590 struct ospf_lsa *new;
1591 struct ospf_lsa *old;
1592 struct ospf_area *area = NULL;
1593 struct ospf_interface *oi = NULL;
1594 struct ospf_lsdb *lsdb = NULL;
1595 struct ospf *ospf;
1596 int lsa_type, opaque_type;
1597 int ready = 0;
1598 int rc = 0;
1600 ospf = ospf_lookup();
1602 /* Extract opaque LSA data from message */
1603 omsg = (struct msg_originate_request *) STREAM_DATA (msg->s);
1604 data = &omsg->data;
1606 /* Determine interface for type9 or area for type10 LSAs. */
1607 switch (data->type)
1609 case OSPF_OPAQUE_LINK_LSA:
1610 oi = ospf_apiserver_if_lookup_by_addr (omsg->ifaddr);
1611 if (!oi)
1613 zlog_warn ("apiserver_originate: unknown interface %s",
1614 inet_ntoa (omsg->ifaddr));
1615 rc = OSPF_API_NOSUCHINTERFACE;
1616 goto out;
1618 area = oi->area;
1619 lsdb = area->lsdb;
1620 break;
1621 case OSPF_OPAQUE_AREA_LSA:
1622 area = ospf_area_lookup_by_area_id (ospf, omsg->area_id);
1623 if (!area)
1625 zlog_warn ("apiserver_originate: unknown area %s",
1626 inet_ntoa (omsg->area_id));
1627 rc = OSPF_API_NOSUCHAREA;
1628 goto out;
1630 lsdb = area->lsdb;
1631 break;
1632 case OSPF_OPAQUE_AS_LSA:
1633 lsdb = ospf->lsdb;
1634 break;
1635 default:
1636 /* We can only handle opaque types here */
1637 zlog_warn ("apiserver_originate: Cannot originate non-opaque LSA type %d",
1638 data->type);
1639 rc = OSPF_API_ILLEGALLSATYPE;
1640 goto out;
1643 /* Check if we registered this opaque type */
1644 lsa_type = data->type;
1645 opaque_type = GET_OPAQUE_TYPE (ntohl (data->id.s_addr));
1647 if (!apiserver_is_opaque_type_registered (apiserv, lsa_type, opaque_type))
1649 zlog_warn ("apiserver_originate: LSA-type(%d)/Opaque-type(%d): Not registered", lsa_type, opaque_type);
1650 rc = OSPF_API_OPAQUETYPENOTREGISTERED;
1651 goto out;
1654 /* Make sure that the neighbors are ready before we can originate */
1655 switch (data->type)
1657 case OSPF_OPAQUE_LINK_LSA:
1658 ready = ospf_apiserver_is_ready_type9 (oi);
1659 break;
1660 case OSPF_OPAQUE_AREA_LSA:
1661 ready = ospf_apiserver_is_ready_type10 (area);
1662 break;
1663 case OSPF_OPAQUE_AS_LSA:
1664 ready = ospf_apiserver_is_ready_type11 (ospf);
1665 break;
1666 default:
1667 break;
1670 if (!ready)
1672 zlog_warn ("Neighbors not ready to originate type %d", data->type);
1673 rc = OSPF_API_NOTREADY;
1674 goto out;
1677 /* Create OSPF's internal opaque LSA representation */
1678 new = ospf_apiserver_opaque_lsa_new (area, oi, data);
1679 if (!new)
1681 rc = OSPF_API_NOMEMORY; /* XXX */
1682 goto out;
1685 /* Determine if LSA is new or an update for an existing one. */
1686 old = ospf_lsdb_lookup (lsdb, new);
1688 if (!old)
1690 /* New LSA install in LSDB. */
1691 rc = ospf_apiserver_originate1 (new);
1693 else
1696 * Keep the new LSA instance in the "waiting place" until the next
1697 * refresh timing. If several LSA update requests for the same LSID
1698 * have issued by peer, the last one takes effect.
1700 new->lsdb = &apiserv->reserve;
1701 ospf_lsdb_add (&apiserv->reserve, new);
1703 /* Kick the scheduler function. */
1704 ospf_opaque_lsa_refresh_schedule (old);
1707 out:
1709 /* Send a reply back to client with return code */
1710 rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc);
1711 return rc;
1715 /* -----------------------------------------------------------
1716 * Flood an LSA within its flooding scope.
1717 * -----------------------------------------------------------
1720 /* XXX We can probably use ospf_flood_through instead of this function
1721 but then we need the neighbor parameter. If we set nbr to
1722 NULL then ospf_flood_through crashes due to dereferencing NULL. */
1724 void
1725 ospf_apiserver_flood_opaque_lsa (struct ospf_lsa *lsa)
1727 assert (lsa);
1729 switch (lsa->data->type)
1731 case OSPF_OPAQUE_LINK_LSA:
1732 /* Increment counters? XXX */
1734 /* Flood LSA through local network. */
1735 ospf_flood_through_area (lsa->area, NULL /*nbr */ , lsa);
1736 break;
1737 case OSPF_OPAQUE_AREA_LSA:
1738 /* Update LSA origination count. */
1739 assert (lsa->area);
1740 lsa->area->ospf->lsa_originate_count++;
1742 /* Flood LSA through area. */
1743 ospf_flood_through_area (lsa->area, NULL /*nbr */ , lsa);
1744 break;
1745 case OSPF_OPAQUE_AS_LSA:
1747 struct ospf *ospf;
1749 ospf = ospf_lookup();
1750 assert(ospf);
1752 /* Increment counters? XXX */
1754 /* Flood LSA through AS. */
1755 ospf_flood_through_as (ospf, NULL /*nbr */ , lsa);
1756 break;
1762 ospf_apiserver_originate1 (struct ospf_lsa *lsa)
1764 struct ospf *ospf;
1766 ospf = ospf_lookup();
1767 assert(ospf);
1769 /* Install this LSA into LSDB. */
1770 if (ospf_lsa_install (ospf, lsa->oi, lsa) == NULL)
1772 zlog_warn ("ospf_apiserver_originate1: ospf_lsa_install failed");
1773 return -1;
1776 /* Flood LSA within scope */
1778 #ifdef NOTYET
1780 * NB: Modified version of "ospf_flood_though ()" accepts NULL "inbr"
1781 * parameter, and thus it does not cause SIGSEGV error.
1783 ospf_flood_through (NULL /*nbr */ , lsa);
1784 #else /* NOTYET */
1786 ospf_apiserver_flood_opaque_lsa (lsa);
1787 #endif /* NOTYET */
1789 return 0;
1793 /* Opaque LSAs of type 9 on a specific interface can now be
1794 originated. Tell clients that registered type 9. */
1796 ospf_apiserver_lsa9_originator (void *arg)
1798 struct ospf_interface *oi;
1800 oi = (struct ospf_interface *) arg;
1801 if (listcount (apiserver_list) > 0) {
1802 ospf_apiserver_clients_notify_ready_type9 (oi);
1804 return 0;
1808 ospf_apiserver_lsa10_originator (void *arg)
1810 struct ospf_area *area;
1812 area = (struct ospf_area *) arg;
1813 if (listcount (apiserver_list) > 0) {
1814 ospf_apiserver_clients_notify_ready_type10 (area);
1816 return 0;
1820 ospf_apiserver_lsa11_originator (void *arg)
1822 struct ospf *ospf;
1824 ospf = (struct ospf *) arg;
1825 if (listcount (apiserver_list) > 0) {
1826 ospf_apiserver_clients_notify_ready_type11 (ospf);
1828 return 0;
1832 /* Periodically refresh opaque LSAs so that they do not expire in
1833 other routers. */
1834 void
1835 ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa)
1837 struct ospf_apiserver *apiserv;
1838 struct ospf_lsa *new = NULL;
1839 struct ospf * ospf;
1841 ospf = ospf_lookup();
1842 assert(ospf);
1844 apiserv = lookup_apiserver_by_lsa (lsa);
1845 if (!apiserv)
1847 zlog_warn ("ospf_apiserver_lsa_refresher: LSA[%s]: No apiserver?", dump_lsa_key (lsa));
1848 lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */
1851 if (IS_LSA_MAXAGE (lsa))
1853 ospf_opaque_lsa_flush_schedule (lsa);
1854 goto out;
1857 /* Check if updated version of LSA instance has already prepared. */
1858 new = ospf_lsdb_lookup (&apiserv->reserve, lsa);
1859 if (!new)
1861 /* This is a periodic refresh, driven by core OSPF mechanism. */
1862 new = ospf_apiserver_opaque_lsa_new (lsa->area, lsa->oi, lsa->data);
1863 if (!new)
1865 zlog_warn ("ospf_apiserver_lsa_refresher: Cannot create a new LSA?");
1866 goto out;
1869 else
1871 /* This is a forcible refresh, requested by OSPF-API client. */
1872 ospf_lsdb_delete (&apiserv->reserve, new);
1873 new->lsdb = NULL;
1876 /* Increment sequence number */
1877 new->data->ls_seqnum = lsa_seqnum_increment (lsa);
1879 /* New LSA is in same area. */
1880 new->area = lsa->area;
1881 SET_FLAG (new->flags, OSPF_LSA_SELF);
1883 /* Install LSA into LSDB. */
1884 if (ospf_lsa_install (ospf, new->oi, new) == NULL)
1886 zlog_warn ("ospf_apiserver_lsa_refresher: ospf_lsa_install failed");
1887 ospf_lsa_unlock (&new);
1888 goto out;
1891 /* Flood updated LSA through interface, area or AS */
1893 #ifdef NOTYET
1894 ospf_flood_through (NULL /*nbr */ , new);
1895 #endif /* NOTYET */
1896 ospf_apiserver_flood_opaque_lsa (new);
1898 /* Debug logging. */
1899 if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
1901 zlog_debug ("LSA[Type%d:%s]: Refresh Opaque LSA",
1902 new->data->type, inet_ntoa (new->data->id));
1903 ospf_lsa_header_dump (new->data);
1906 out:
1907 return;
1911 /* -----------------------------------------------------------
1912 * Followings are functions to delete LSAs
1913 * -----------------------------------------------------------
1917 ospf_apiserver_handle_delete_request (struct ospf_apiserver *apiserv,
1918 struct msg *msg)
1920 struct msg_delete_request *dmsg;
1921 struct ospf_lsa *old;
1922 struct ospf_area *area = NULL;
1923 struct in_addr id;
1924 int lsa_type, opaque_type;
1925 int rc = 0;
1926 struct ospf * ospf;
1928 ospf = ospf_lookup();
1929 assert(ospf);
1931 /* Extract opaque LSA from message */
1932 dmsg = (struct msg_delete_request *) STREAM_DATA (msg->s);
1934 /* Lookup area for link-local and area-local opaque LSAs */
1935 switch (dmsg->lsa_type)
1937 case OSPF_OPAQUE_LINK_LSA:
1938 case OSPF_OPAQUE_AREA_LSA:
1939 area = ospf_area_lookup_by_area_id (ospf, dmsg->area_id);
1940 if (!area)
1942 zlog_warn ("ospf_apiserver_lsa_delete: unknown area %s",
1943 inet_ntoa (dmsg->area_id));
1944 rc = OSPF_API_NOSUCHAREA;
1945 goto out;
1947 break;
1948 case OSPF_OPAQUE_AS_LSA:
1949 /* AS-external opaque LSAs have no designated area */
1950 area = NULL;
1951 break;
1952 default:
1953 zlog_warn
1954 ("ospf_apiserver_lsa_delete: Cannot delete non-opaque LSA type %d",
1955 dmsg->lsa_type);
1956 rc = OSPF_API_ILLEGALLSATYPE;
1957 goto out;
1960 /* Check if we registered this opaque type */
1961 lsa_type = dmsg->lsa_type;
1962 opaque_type = dmsg->opaque_type;
1964 if (!apiserver_is_opaque_type_registered (apiserv, lsa_type, opaque_type))
1966 zlog_warn ("ospf_apiserver_lsa_delete: LSA-type(%d)/Opaque-type(%d): Not registered", lsa_type, opaque_type);
1967 rc = OSPF_API_OPAQUETYPENOTREGISTERED;
1968 goto out;
1971 /* opaque_id is in network byte order */
1972 id.s_addr = htonl (SET_OPAQUE_LSID (dmsg->opaque_type,
1973 ntohl (dmsg->opaque_id)));
1976 * Even if the target LSA has once scheduled to flush, it remains in
1977 * the LSDB until it is finally handled by the maxage remover thread.
1978 * Therefore, the lookup function below may return non-NULL result.
1980 old = ospf_lsa_lookup (area, dmsg->lsa_type, id, ospf->router_id);
1981 if (!old)
1983 zlog_warn ("ospf_apiserver_lsa_delete: LSA[Type%d:%s] not in LSDB",
1984 dmsg->lsa_type, inet_ntoa (id));
1985 rc = OSPF_API_NOSUCHLSA;
1986 goto out;
1989 /* Schedule flushing of LSA from LSDB */
1990 /* NB: Multiple scheduling will produce a warning message, but harmless. */
1991 ospf_opaque_lsa_flush_schedule (old);
1993 out:
1995 /* Send reply back to client including return code */
1996 rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc);
1997 return rc;
2000 /* Flush self-originated opaque LSA */
2001 static int
2002 apiserver_flush_opaque_type_callback (struct ospf_lsa *lsa,
2003 void *p_arg, int int_arg)
2005 struct param_t
2007 struct ospf_apiserver *apiserv;
2008 u_char lsa_type;
2009 u_char opaque_type;
2011 *param;
2013 /* Sanity check */
2014 assert (lsa->data);
2015 assert (p_arg);
2016 param = (struct param_t *) p_arg;
2018 /* If LSA matches type and opaque type then delete it */
2019 if (IS_LSA_SELF (lsa) && lsa->data->type == param->lsa_type
2020 && GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)) == param->opaque_type)
2022 ospf_opaque_lsa_flush_schedule (lsa);
2024 return 0;
2027 /* Delete self-originated opaque LSAs of a given opaque type. This
2028 function is called when an application unregisters a given opaque
2029 type or a connection to an application closes and all those opaque
2030 LSAs need to be flushed the LSDB. */
2031 void
2032 ospf_apiserver_flush_opaque_lsa (struct ospf_apiserver *apiserv,
2033 u_char lsa_type, u_char opaque_type)
2035 struct param_t
2037 struct ospf_apiserver *apiserv;
2038 u_char lsa_type;
2039 u_char opaque_type;
2040 } param;
2041 struct listnode *node, *nnode;
2042 struct ospf * ospf;
2043 struct ospf_area *area;
2045 ospf = ospf_lookup();
2046 assert(ospf);
2048 /* Set parameter struct. */
2049 param.apiserv = apiserv;
2050 param.lsa_type = lsa_type;
2051 param.opaque_type = opaque_type;
2053 switch (lsa_type)
2055 struct route_node *rn;
2056 struct ospf_lsa *lsa;
2058 case OSPF_OPAQUE_LINK_LSA:
2059 for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area))
2060 LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
2061 apiserver_flush_opaque_type_callback(lsa, (void *) &param, 0);
2062 break;
2063 case OSPF_OPAQUE_AREA_LSA:
2064 for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area))
2065 LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
2066 apiserver_flush_opaque_type_callback(lsa, (void *) &param, 0);
2067 break;
2068 case OSPF_OPAQUE_AS_LSA:
2069 LSDB_LOOP (OPAQUE_LINK_LSDB (ospf), rn, lsa)
2070 apiserver_flush_opaque_type_callback(lsa, (void *) &param, 0);
2071 break;
2072 default:
2073 break;
2075 return;
2079 /* -----------------------------------------------------------
2080 * Followings are callback functions to handle opaque types
2081 * -----------------------------------------------------------
2085 ospf_apiserver_new_if (struct interface *ifp)
2087 struct ospf_interface *oi;
2089 /* For some strange reason it seems possible that we are invoked
2090 with an interface that has no name. This seems to happen during
2091 initialization. Return if this happens */
2093 if (ifp->name[0] == '\0') {
2094 /* interface has empty name */
2095 zlog_warn ("ospf_apiserver_new_if: interface has no name?");
2096 return 0;
2099 /* zlog_warn for debugging */
2100 zlog_warn ("ospf_apiserver_new_if");
2101 zlog_warn ("ifp name=%s status=%d index=%d", ifp->name, ifp->status,
2102 ifp->ifindex);
2104 if (ifp->name[0] == '\0') {
2105 /* interface has empty name */
2106 zlog_warn ("ospf_apiserver_new_if: interface has no name?");
2107 return 0;
2110 oi = ospf_apiserver_if_lookup_by_ifp (ifp);
2112 if (!oi) {
2113 /* This interface is known to Zebra but not to OSPF daemon yet. */
2114 zlog_warn ("ospf_apiserver_new_if: interface %s not known to OSPFd?",
2115 ifp->name);
2116 return 0;
2119 assert (oi);
2121 /* New interface added to OSPF, tell clients about it */
2122 if (listcount (apiserver_list) > 0) {
2123 ospf_apiserver_clients_notify_new_if (oi);
2125 return 0;
2129 ospf_apiserver_del_if (struct interface *ifp)
2131 struct ospf_interface *oi;
2133 /* zlog_warn for debugging */
2134 zlog_warn ("ospf_apiserver_del_if");
2135 zlog_warn ("ifp name=%s status=%d index=%d\n", ifp->name, ifp->status,
2136 ifp->ifindex);
2138 oi = ospf_apiserver_if_lookup_by_ifp (ifp);
2140 if (!oi) {
2141 /* This interface is known to Zebra but not to OSPF daemon
2142 anymore. No need to tell clients about it */
2143 return 0;
2146 /* Interface deleted, tell clients about it */
2147 if (listcount (apiserver_list) > 0) {
2148 ospf_apiserver_clients_notify_del_if (oi);
2150 return 0;
2153 void
2154 ospf_apiserver_ism_change (struct ospf_interface *oi, int old_state)
2156 /* Tell clients about interface change */
2158 /* zlog_warn for debugging */
2159 zlog_warn ("ospf_apiserver_ism_change");
2160 if (listcount (apiserver_list) > 0) {
2161 ospf_apiserver_clients_notify_ism_change (oi);
2164 zlog_warn ("oi->ifp->name=%s", oi->ifp->name);
2165 zlog_warn ("old_state=%d", old_state);
2166 zlog_warn ("oi->state=%d", oi->state);
2169 void
2170 ospf_apiserver_nsm_change (struct ospf_neighbor *nbr, int old_status)
2172 /* Neighbor status changed, tell clients about it */
2173 zlog_warn ("ospf_apiserver_nsm_change");
2174 if (listcount (apiserver_list) > 0) {
2175 ospf_apiserver_clients_notify_nsm_change (nbr);
2179 void
2180 ospf_apiserver_show_info (struct vty *vty, struct ospf_lsa *lsa)
2182 struct opaque_lsa
2184 struct lsa_header header;
2185 u_char data[1]; /* opaque data have variable length. This is start
2186 address */
2188 struct opaque_lsa *olsa;
2189 int opaquelen;
2191 olsa = (struct opaque_lsa *) lsa->data;
2193 if (VALID_OPAQUE_INFO_LEN (lsa->data))
2194 opaquelen = ntohs (lsa->data->length) - OSPF_LSA_HEADER_SIZE;
2195 else
2196 opaquelen = 0;
2198 /* Output information about opaque LSAs */
2199 if (vty != NULL)
2201 int i;
2202 vty_out (vty, " Added using OSPF API: %u octets of opaque data %s%s",
2203 opaquelen,
2204 VALID_OPAQUE_INFO_LEN (lsa->data) ? "" : "(Invalid length?)",
2205 VTY_NEWLINE);
2206 vty_out (vty, " Opaque data: ");
2208 for (i = 0; i < opaquelen; i++)
2210 vty_out (vty, "0x%x ", olsa->data[i]);
2212 vty_out (vty, "%s", VTY_NEWLINE);
2214 else
2216 int i;
2217 zlog_debug (" Added using OSPF API: %u octets of opaque data %s",
2218 opaquelen,
2219 VALID_OPAQUE_INFO_LEN (lsa->
2220 data) ? "" : "(Invalid length?)");
2221 zlog_debug (" Opaque data: ");
2223 for (i = 0; i < opaquelen; i++)
2225 zlog_debug ("0x%x ", olsa->data[i]);
2227 zlog_debug ("\n");
2229 return;
2232 /* -----------------------------------------------------------
2233 * Followings are functions to notify clients about events
2234 * -----------------------------------------------------------
2237 /* Send a message to all clients. This is useful for messages
2238 that need to be notified to all clients (such as interface
2239 changes) */
2241 void
2242 ospf_apiserver_clients_notify_all (struct msg *msg)
2244 struct listnode *node, *nnode;
2245 struct ospf_apiserver *apiserv;
2247 /* Send message to all clients */
2248 for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv))
2249 ospf_apiserver_send_msg (apiserv, msg);
2252 /* An interface is now ready to accept opaque LSAs. Notify all
2253 clients that registered to use this opaque type */
2254 void
2255 ospf_apiserver_clients_notify_ready_type9 (struct ospf_interface *oi)
2257 struct listnode *node, *nnode;
2258 struct msg *msg;
2259 struct ospf_apiserver *apiserv;
2261 assert (oi);
2262 if (!oi->address)
2264 zlog_warn ("Interface has no address?");
2265 return;
2268 if (!ospf_apiserver_is_ready_type9 (oi))
2270 zlog_warn ("Interface not ready for type 9?");
2271 return;
2274 for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv))
2276 struct listnode *node2, *nnode2;
2277 struct registered_opaque_type *r;
2279 for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r))
2281 if (r->lsa_type == OSPF_OPAQUE_LINK_LSA)
2283 msg = new_msg_ready_notify (0, OSPF_OPAQUE_LINK_LSA,
2284 r->opaque_type,
2285 oi->address->u.prefix4);
2286 if (!msg)
2288 zlog_warn
2289 ("ospf_apiserver_clients_notify_ready_type9: new_msg_ready_notify failed");
2290 #ifdef NOTYET
2291 /* Cannot allocate new message. What should we do? */
2292 ospf_apiserver_free (apiserv);
2293 #endif
2294 goto out;
2297 ospf_apiserver_send_msg (apiserv, msg);
2298 msg_free (msg);
2303 out:
2304 return;
2307 void
2308 ospf_apiserver_clients_notify_ready_type10 (struct ospf_area *area)
2310 struct listnode *node, *nnode;
2311 struct msg *msg;
2312 struct ospf_apiserver *apiserv;
2314 assert (area);
2316 if (!ospf_apiserver_is_ready_type10 (area))
2318 zlog_warn ("Area not ready for type 10?");
2319 return;
2322 for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv))
2324 struct listnode *node2, *nnode2;
2325 struct registered_opaque_type *r;
2327 for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r))
2329 if (r->lsa_type == OSPF_OPAQUE_AREA_LSA)
2331 msg = new_msg_ready_notify (0, OSPF_OPAQUE_AREA_LSA,
2332 r->opaque_type, area->area_id);
2333 if (!msg)
2335 zlog_warn
2336 ("ospf_apiserver_clients_notify_ready_type10: new_msg_ready_nofity failed");
2337 #ifdef NOTYET
2338 /* Cannot allocate new message. What should we do? */
2339 ospf_apiserver_free (apiserv);
2340 #endif
2341 goto out;
2344 ospf_apiserver_send_msg (apiserv, msg);
2345 msg_free (msg);
2350 out:
2351 return;
2355 void
2356 ospf_apiserver_clients_notify_ready_type11 (struct ospf *top)
2358 struct listnode *node, *nnode;
2359 struct msg *msg;
2360 struct in_addr id_null = { .s_addr = 0L };
2361 struct ospf_apiserver *apiserv;
2363 assert (top);
2365 if (!ospf_apiserver_is_ready_type11 (top))
2367 zlog_warn ("AS not ready for type 11?");
2368 return;
2371 for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv))
2373 struct listnode *node2, *nnode2;
2374 struct registered_opaque_type *r;
2376 for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r))
2378 if (r->lsa_type == OSPF_OPAQUE_AS_LSA)
2380 msg = new_msg_ready_notify (0, OSPF_OPAQUE_AS_LSA,
2381 r->opaque_type, id_null);
2382 if (!msg)
2384 zlog_warn
2385 ("ospf_apiserver_clients_notify_ready_type11: new_msg_ready_notify failed");
2386 #ifdef NOTYET
2387 /* Cannot allocate new message. What should we do? */
2388 ospf_apiserver_free (apiserv);
2389 #endif
2390 goto out;
2393 ospf_apiserver_send_msg (apiserv, msg);
2394 msg_free (msg);
2399 out:
2400 return;
2403 void
2404 ospf_apiserver_clients_notify_new_if (struct ospf_interface *oi)
2406 struct msg *msg;
2408 msg = new_msg_new_if (0, oi->address->u.prefix4, oi->area->area_id);
2409 if (msg != NULL)
2411 ospf_apiserver_clients_notify_all (msg);
2412 msg_free (msg);
2416 void
2417 ospf_apiserver_clients_notify_del_if (struct ospf_interface *oi)
2419 struct msg *msg;
2421 msg = new_msg_del_if (0, oi->address->u.prefix4);
2422 if (msg != NULL)
2424 ospf_apiserver_clients_notify_all (msg);
2425 msg_free (msg);
2429 void
2430 ospf_apiserver_clients_notify_ism_change (struct ospf_interface *oi)
2432 struct msg *msg;
2433 struct in_addr ifaddr = { .s_addr = 0L };
2434 struct in_addr area_id = { .s_addr = 0L };
2436 assert (oi);
2437 assert (oi->ifp);
2439 if (oi->address)
2441 ifaddr = oi->address->u.prefix4;
2443 if (oi->area)
2445 area_id = oi->area->area_id;
2448 msg = new_msg_ism_change (0, ifaddr, area_id, oi->state);
2449 if (!msg)
2451 zlog_warn ("apiserver_clients_notify_ism_change: msg_new failed");
2452 return;
2455 ospf_apiserver_clients_notify_all (msg);
2456 msg_free (msg);
2459 void
2460 ospf_apiserver_clients_notify_nsm_change (struct ospf_neighbor *nbr)
2462 struct msg *msg;
2463 struct in_addr ifaddr = { .s_addr = 0L };
2464 struct in_addr nbraddr = { .s_addr = 0L };
2466 assert (nbr);
2468 if (nbr->oi)
2470 ifaddr = nbr->oi->address->u.prefix4;
2473 nbraddr = nbr->address.u.prefix4;
2475 msg = new_msg_nsm_change (0, ifaddr, nbraddr, nbr->router_id, nbr->state);
2476 if (!msg)
2478 zlog_warn ("apiserver_clients_notify_nsm_change: msg_new failed");
2479 return;
2482 ospf_apiserver_clients_notify_all (msg);
2483 msg_free (msg);
2486 static void
2487 apiserver_clients_lsa_change_notify (u_char msgtype, struct ospf_lsa *lsa)
2489 struct msg *msg;
2490 struct listnode *node, *nnode;
2491 struct ospf_apiserver *apiserv;
2493 /* Default area for AS-External and Opaque11 LSAs */
2494 struct in_addr area_id = { .s_addr = 0L };
2496 /* Default interface for non Opaque9 LSAs */
2497 struct in_addr ifaddr = { .s_addr = 0L };
2499 if (lsa->area)
2501 area_id = lsa->area->area_id;
2503 if (lsa->data->type == OSPF_OPAQUE_LINK_LSA)
2505 assert (lsa->oi);
2506 ifaddr = lsa->oi->address->u.prefix4;
2509 /* Prepare message that can be sent to clients that have a matching
2510 filter */
2511 msg = new_msg_lsa_change_notify (msgtype, 0L, /* no sequence number */
2512 ifaddr, area_id,
2513 lsa->flags & OSPF_LSA_SELF, lsa->data);
2514 if (!msg)
2516 zlog_warn ("apiserver_clients_lsa_change_notify: msg_new failed");
2517 return;
2520 /* Now send message to all clients with a matching filter */
2521 for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv))
2523 struct lsa_filter_type *filter;
2524 u_int16_t mask;
2525 u_int32_t *area;
2526 int i;
2528 /* Check filter for this client. */
2529 filter = apiserv->filter;
2531 /* Check area IDs in case of non AS-E LSAs.
2532 * If filter has areas (num_areas > 0),
2533 * then one of the areas must match the area ID of this LSA. */
2535 i = filter->num_areas;
2536 if ((lsa->data->type == OSPF_AS_EXTERNAL_LSA) ||
2537 (lsa->data->type == OSPF_OPAQUE_AS_LSA))
2539 i = 0;
2542 if (i > 0)
2544 area = (u_int32_t *) (filter + 1);
2545 while (i)
2547 if (*area == area_id.s_addr)
2549 break;
2551 i--;
2552 area++;
2555 else
2557 i = 1;
2560 if (i > 0)
2562 /* Area match. Check LSA type. */
2563 mask = ntohs (filter->typemask);
2565 if (mask & Power2[lsa->data->type])
2567 /* Type also matches. Check origin. */
2568 if ((filter->origin == ANY_ORIGIN) ||
2569 (filter->origin == IS_LSA_SELF (lsa)))
2571 ospf_apiserver_send_msg (apiserv, msg);
2576 /* Free message since it is not used anymore */
2577 msg_free (msg);
2581 /* -------------------------------------------------------------
2582 * Followings are hooks invoked when LSAs are updated or deleted
2583 * -------------------------------------------------------------
2587 static int
2588 apiserver_notify_clients_lsa (u_char msgtype, struct ospf_lsa *lsa)
2590 struct msg *msg;
2591 /* default area for AS-External and Opaque11 LSAs */
2592 struct in_addr area_id = { .s_addr = 0L };
2594 /* default interface for non Opaque9 LSAs */
2595 struct in_addr ifaddr = { .s_addr = 0L };
2597 /* Only notify this update if the LSA's age is smaller than
2598 MAXAGE. Otherwise clients would see LSA updates with max age just
2599 before they are deleted from the LSDB. LSA delete messages have
2600 MAXAGE too but should not be filtered. */
2601 if (IS_LSA_MAXAGE(lsa) && (msgtype == MSG_LSA_UPDATE_NOTIFY)) {
2602 return 0;
2605 if (lsa->area)
2607 area_id = lsa->area->area_id;
2609 if (lsa->data->type == OSPF_OPAQUE_LINK_LSA)
2611 ifaddr = lsa->oi->address->u.prefix4;
2613 msg = new_msg_lsa_change_notify (msgtype, 0L, /* no sequence number */
2614 ifaddr, area_id,
2615 lsa->flags & OSPF_LSA_SELF, lsa->data);
2616 if (!msg)
2618 zlog_warn ("notify_clients_lsa: msg_new failed");
2619 return -1;
2621 /* Notify all clients that new LSA is added/updated */
2622 apiserver_clients_lsa_change_notify (msgtype, lsa);
2624 /* Clients made their own copies of msg so we can free msg here */
2625 msg_free (msg);
2627 return 0;
2631 ospf_apiserver_lsa_update (struct ospf_lsa *lsa)
2633 return apiserver_notify_clients_lsa (MSG_LSA_UPDATE_NOTIFY, lsa);
2637 ospf_apiserver_lsa_delete (struct ospf_lsa *lsa)
2639 return apiserver_notify_clients_lsa (MSG_LSA_DELETE_NOTIFY, lsa);
2642 #endif /* SUPPORT_OSPF_API */