2 * Client side of OSPF API.
3 * Copyright (C) 2001, 2002, 2003 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
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.
25 #include <lib/version.h>
39 #include "ospfd/ospfd.h"
40 #include "ospfd/ospf_interface.h"
41 #include "ospfd/ospf_asbr.h"
42 #include "ospfd/ospf_lsa.h"
43 #include "ospfd/ospf_opaque.h"
44 #include "ospfd/ospf_lsdb.h"
45 #include "ospfd/ospf_neighbor.h"
46 #include "ospfd/ospf_dump.h"
47 #include "ospfd/ospf_zebra.h"
48 #include "ospfd/ospf_api.h"
50 #include "ospf_apiclient.h"
52 /* Backlog for listen */
55 /* -----------------------------------------------------------
56 * Forward declarations
57 * -----------------------------------------------------------
60 void ospf_apiclient_handle_reply (struct ospf_apiclient
*oclient
,
62 void ospf_apiclient_handle_update_notify (struct ospf_apiclient
*oclient
,
64 void ospf_apiclient_handle_delete_notify (struct ospf_apiclient
*oclient
,
67 /* -----------------------------------------------------------
69 * -----------------------------------------------------------
73 ospf_apiclient_getport (void)
75 struct servent
*sp
= getservbyname ("ospfapi", "tcp");
77 return sp
? ntohs (sp
->s_port
) : OSPF_API_SYNC_PORT
;
80 /* -----------------------------------------------------------
81 * Followings are functions for connection management
82 * -----------------------------------------------------------
85 struct ospf_apiclient
*
86 ospf_apiclient_connect (char *host
, int syncport
)
88 struct sockaddr_in myaddr_sync
;
89 struct sockaddr_in myaddr_async
;
90 struct sockaddr_in peeraddr
;
92 struct ospf_apiclient
*new;
94 unsigned int peeraddrlen
;
95 int async_server_sock
;
100 /* There are two connections between the client and the server.
101 First the client opens a connection for synchronous requests/replies
102 to the server. The server will accept this connection and
103 as a reaction open a reverse connection channel for
104 asynchronous messages. */
106 async_server_sock
= socket (AF_INET
, SOCK_STREAM
, 0);
107 if (async_server_sock
< 0)
110 "ospf_apiclient_connect: creating async socket failed\n");
114 /* Prepare socket for asynchronous messages */
115 /* Initialize async address structure */
116 memset (&myaddr_async
, 0, sizeof (struct sockaddr_in
));
117 myaddr_async
.sin_family
= AF_INET
;
118 myaddr_async
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
119 myaddr_async
.sin_port
= htons (syncport
+1);
120 size
= sizeof (struct sockaddr_in
);
121 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
122 myaddr_async
.sin_len
= size
;
123 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
125 /* This is a server socket, reuse addr and port */
126 ret
= setsockopt (async_server_sock
, SOL_SOCKET
,
127 SO_REUSEADDR
, (void *) &on
, sizeof (on
));
130 fprintf (stderr
, "ospf_apiclient_connect: SO_REUSEADDR failed\n");
131 close (async_server_sock
);
136 ret
= setsockopt (async_server_sock
, SOL_SOCKET
, SO_REUSEPORT
,
137 (void *) &on
, sizeof (on
));
140 fprintf (stderr
, "ospf_apiclient_connect: SO_REUSEPORT failed\n");
141 close (async_server_sock
);
144 #endif /* SO_REUSEPORT */
146 /* Bind socket to address structure */
147 ret
= bind (async_server_sock
, (struct sockaddr
*) &myaddr_async
, size
);
150 fprintf (stderr
, "ospf_apiclient_connect: bind async socket failed\n");
151 close (async_server_sock
);
155 /* Wait for reverse channel connection establishment from server */
156 ret
= listen (async_server_sock
, BACKLOG
);
159 fprintf (stderr
, "ospf_apiclient_connect: listen: %s\n", safe_strerror (errno
));
160 close (async_server_sock
);
164 /* Make connection for synchronous requests and connect to server */
165 /* Resolve address of server */
166 hp
= gethostbyname (host
);
169 fprintf (stderr
, "ospf_apiclient_connect: no such host %s\n", host
);
170 close (async_server_sock
);
174 fd1
= socket (AF_INET
, SOCK_STREAM
, 0);
178 "ospf_apiclient_connect: creating sync socket failed\n");
183 /* Reuse addr and port */
184 ret
= setsockopt (fd1
, SOL_SOCKET
,
185 SO_REUSEADDR
, (void *) &on
, sizeof (on
));
188 fprintf (stderr
, "ospf_apiclient_connect: SO_REUSEADDR failed\n");
194 ret
= setsockopt (fd1
, SOL_SOCKET
, SO_REUSEPORT
,
195 (void *) &on
, sizeof (on
));
198 fprintf (stderr
, "ospf_apiclient_connect: SO_REUSEPORT failed\n");
202 #endif /* SO_REUSEPORT */
205 /* Bind sync socket to address structure. This is needed since we
206 want the sync port number on a fixed port number. The reverse
207 async channel will be at this port+1 */
209 memset (&myaddr_sync
, 0, sizeof (struct sockaddr_in
));
210 myaddr_sync
.sin_family
= AF_INET
;
211 myaddr_sync
.sin_port
= htons (syncport
);
212 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
213 myaddr_sync
.sin_len
= sizeof (struct sockaddr_in
);
214 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
216 ret
= bind (fd1
, (struct sockaddr
*) &myaddr_sync
, size
);
219 fprintf (stderr
, "ospf_apiclient_connect: bind sync socket failed\n");
224 /* Prepare address structure for connect */
225 memcpy (&myaddr_sync
.sin_addr
, hp
->h_addr
, hp
->h_length
);
226 myaddr_sync
.sin_family
= AF_INET
;
227 myaddr_sync
.sin_port
= htons(ospf_apiclient_getport ());
228 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
229 myaddr_sync
.sin_len
= sizeof (struct sockaddr_in
);
230 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
232 /* Now establish synchronous channel with OSPF daemon */
233 ret
= connect (fd1
, (struct sockaddr
*) &myaddr_sync
,
234 sizeof (struct sockaddr_in
));
237 fprintf (stderr
, "ospf_apiclient_connect: sync connect failed\n");
238 close (async_server_sock
);
243 /* Accept reverse connection */
244 peeraddrlen
= sizeof (struct sockaddr_in
);
245 memset (&peeraddr
, 0, peeraddrlen
);
248 accept (async_server_sock
, (struct sockaddr
*) &peeraddr
, &peeraddrlen
);
251 fprintf (stderr
, "ospf_apiclient_connect: accept async failed\n");
252 close (async_server_sock
);
257 /* Server socket is not needed anymore since we are not accepting more
259 close (async_server_sock
);
261 /* Create new client-side instance */
262 new = XMALLOC (MTYPE_OSPF_APICLIENT
, sizeof (struct ospf_apiclient
));
263 memset (new, 0, sizeof (struct ospf_apiclient
));
265 /* Initialize socket descriptors for sync and async channels */
273 ospf_apiclient_close (struct ospf_apiclient
*oclient
)
276 if (oclient
->fd_sync
>= 0)
278 close (oclient
->fd_sync
);
281 if (oclient
->fd_async
>= 0)
283 close (oclient
->fd_async
);
286 /* Free client structure */
287 XFREE (MTYPE_OSPF_APICLIENT
, oclient
);
291 /* -----------------------------------------------------------
292 * Followings are functions to send a request to OSPFd
293 * -----------------------------------------------------------
296 /* Send synchronous request, wait for reply */
298 ospf_apiclient_send_request (struct ospf_apiclient
*oclient
, struct msg
*msg
)
301 struct msg_reply
*msgreply
;
304 /* NB: Given "msg" is freed inside this function. */
306 /* Remember the sequence number of the request */
307 reqseq
= ntohl (msg
->hdr
.msgseq
);
309 /* Write message to OSPFd */
310 rc
= msg_write (oclient
->fd_sync
, msg
);
318 /* Wait for reply *//* NB: New "msg" is allocated by "msg_read()". */
319 msg
= msg_read (oclient
->fd_sync
);
323 assert (msg
->hdr
.msgtype
== MSG_REPLY
);
324 assert (ntohl (msg
->hdr
.msgseq
) == reqseq
);
326 msgreply
= (struct msg_reply
*) STREAM_DATA (msg
->s
);
327 rc
= msgreply
->errcode
;
334 /* -----------------------------------------------------------
336 * -----------------------------------------------------------
340 ospf_apiclient_get_seqnr (void)
342 static u_int32_t seqnr
= MIN_SEQ
;
346 /* Increment sequence number */
358 /* -----------------------------------------------------------
359 * API to access OSPF daemon by client applications.
360 * -----------------------------------------------------------
364 * Synchronous request to register opaque type.
367 ospf_apiclient_register_opaque_type (struct ospf_apiclient
*cl
,
368 u_char ltype
, u_char otype
)
373 /* just put 1 as a sequence number. */
374 msg
= new_msg_register_opaque_type (ospf_apiclient_get_seqnr (),
378 fprintf (stderr
, "new_msg_register_opaque_type failed\n");
382 rc
= ospf_apiclient_send_request (cl
, msg
);
387 * Synchronous request to synchronize with OSPF's LSDB.
388 * Two steps required: register_event in order to get
389 * dynamic updates and LSDB_Sync.
392 ospf_apiclient_sync_lsdb (struct ospf_apiclient
*oclient
)
396 struct lsa_filter_type filter
;
398 filter
.typemask
= 0xFFFF; /* all LSAs */
399 filter
.origin
= ANY_ORIGIN
;
400 filter
.num_areas
= 0; /* all Areas. */
402 msg
= new_msg_register_event (ospf_apiclient_get_seqnr (), &filter
);
405 fprintf (stderr
, "new_msg_register_event failed\n");
408 rc
= ospf_apiclient_send_request (oclient
, msg
);
413 msg
= new_msg_sync_lsdb (ospf_apiclient_get_seqnr (), &filter
);
416 fprintf (stderr
, "new_msg_sync_lsdb failed\n");
419 rc
= ospf_apiclient_send_request (oclient
, msg
);
426 * Synchronous request to originate or update an LSA.
430 ospf_apiclient_lsa_originate (struct ospf_apiclient
*oclient
,
431 struct in_addr ifaddr
,
432 struct in_addr area_id
,
434 u_char opaque_type
, u_int32_t opaque_id
,
435 void *opaquedata
, int opaquelen
)
439 u_char buf
[OSPF_MAX_LSA_SIZE
];
440 struct lsa_header
*lsah
;
444 /* We can only originate opaque LSAs */
445 if (!IS_OPAQUE_LSA (lsa_type
))
447 fprintf (stderr
, "Cannot originate non-opaque LSA type %d\n", lsa_type
);
448 return OSPF_API_ILLEGALLSATYPE
;
451 /* Make a new LSA from parameters */
452 lsah
= (struct lsa_header
*) buf
;
455 lsah
->type
= lsa_type
;
457 tmp
= SET_OPAQUE_LSID (opaque_type
, opaque_id
);
458 lsah
->id
.s_addr
= htonl (tmp
);
459 lsah
->adv_router
.s_addr
= 0;
462 lsah
->length
= htons (sizeof (struct lsa_header
) + opaquelen
);
464 memcpy (((u_char
*) lsah
) + sizeof (struct lsa_header
), opaquedata
,
467 msg
= new_msg_originate_request (ospf_apiclient_get_seqnr (),
468 ifaddr
, area_id
, lsah
);
471 fprintf (stderr
, "new_msg_originate_request failed\n");
472 return OSPF_API_NOMEMORY
;
475 rc
= ospf_apiclient_send_request (oclient
, msg
);
480 ospf_apiclient_lsa_delete (struct ospf_apiclient
*oclient
,
481 struct in_addr area_id
, u_char lsa_type
,
482 u_char opaque_type
, u_int32_t opaque_id
)
487 /* Only opaque LSA can be deleted */
488 if (!IS_OPAQUE_LSA (lsa_type
))
490 fprintf (stderr
, "Cannot delete non-opaque LSA type %d\n", lsa_type
);
491 return OSPF_API_ILLEGALLSATYPE
;
494 /* opaque_id is in host byte order and will be converted
495 * to network byte order by new_msg_delete_request */
496 msg
= new_msg_delete_request (ospf_apiclient_get_seqnr (),
497 area_id
, lsa_type
, opaque_type
, opaque_id
);
499 rc
= ospf_apiclient_send_request (oclient
, msg
);
503 /* -----------------------------------------------------------
504 * Followings are handlers for messages from OSPF daemon
505 * -----------------------------------------------------------
509 ospf_apiclient_handle_ready (struct ospf_apiclient
*oclient
, struct msg
*msg
)
511 struct msg_ready_notify
*r
;
512 r
= (struct msg_ready_notify
*) STREAM_DATA (msg
->s
);
514 /* Invoke registered callback function. */
515 if (oclient
->ready_notify
)
517 (oclient
->ready_notify
) (r
->lsa_type
, r
->opaque_type
, r
->addr
);
522 ospf_apiclient_handle_new_if (struct ospf_apiclient
*oclient
, struct msg
*msg
)
524 struct msg_new_if
*n
;
525 n
= (struct msg_new_if
*) STREAM_DATA (msg
->s
);
527 /* Invoke registered callback function. */
530 (oclient
->new_if
) (n
->ifaddr
, n
->area_id
);
535 ospf_apiclient_handle_del_if (struct ospf_apiclient
*oclient
, struct msg
*msg
)
537 struct msg_del_if
*d
;
538 d
= (struct msg_del_if
*) STREAM_DATA (msg
->s
);
540 /* Invoke registered callback function. */
543 (oclient
->del_if
) (d
->ifaddr
);
548 ospf_apiclient_handle_ism_change (struct ospf_apiclient
*oclient
,
551 struct msg_ism_change
*m
;
552 m
= (struct msg_ism_change
*) STREAM_DATA (msg
->s
);
554 /* Invoke registered callback function. */
555 if (oclient
->ism_change
)
557 (oclient
->ism_change
) (m
->ifaddr
, m
->area_id
, m
->status
);
563 ospf_apiclient_handle_nsm_change (struct ospf_apiclient
*oclient
,
566 struct msg_nsm_change
*m
;
567 m
= (struct msg_nsm_change
*) STREAM_DATA (msg
->s
);
569 /* Invoke registered callback function. */
570 if (oclient
->nsm_change
)
572 (oclient
->nsm_change
) (m
->ifaddr
, m
->nbraddr
, m
->router_id
, m
->status
);
577 ospf_apiclient_handle_lsa_update (struct ospf_apiclient
*oclient
,
580 struct msg_lsa_change_notify
*cn
;
581 struct lsa_header
*lsa
;
584 cn
= (struct msg_lsa_change_notify
*) STREAM_DATA (msg
->s
);
586 /* Extract LSA from message */
587 lsalen
= ntohs (cn
->data
.length
);
588 lsa
= XMALLOC (MTYPE_OSPF_APICLIENT
, lsalen
);
591 fprintf (stderr
, "LSA update: Cannot allocate memory for LSA\n");
594 memcpy (lsa
, &(cn
->data
), lsalen
);
596 /* Invoke registered update callback function */
597 if (oclient
->update_notify
)
599 (oclient
->update_notify
) (cn
->ifaddr
, cn
->area_id
,
600 cn
->is_self_originated
, lsa
);
603 /* free memory allocated by ospf apiclient library */
604 XFREE (MTYPE_OSPF_APICLIENT
, lsa
);
608 ospf_apiclient_handle_lsa_delete (struct ospf_apiclient
*oclient
,
611 struct msg_lsa_change_notify
*cn
;
612 struct lsa_header
*lsa
;
615 cn
= (struct msg_lsa_change_notify
*) STREAM_DATA (msg
->s
);
617 /* Extract LSA from message */
618 lsalen
= ntohs (cn
->data
.length
);
619 lsa
= XMALLOC (MTYPE_OSPF_APICLIENT
, lsalen
);
622 fprintf (stderr
, "LSA delete: Cannot allocate memory for LSA\n");
625 memcpy (lsa
, &(cn
->data
), lsalen
);
627 /* Invoke registered update callback function */
628 if (oclient
->delete_notify
)
630 (oclient
->delete_notify
) (cn
->ifaddr
, cn
->area_id
,
631 cn
->is_self_originated
, lsa
);
634 /* free memory allocated by ospf apiclient library */
635 XFREE (MTYPE_OSPF_APICLIENT
, lsa
);
639 ospf_apiclient_msghandle (struct ospf_apiclient
*oclient
, struct msg
*msg
)
641 /* Call message handler function. */
642 switch (msg
->hdr
.msgtype
)
644 case MSG_READY_NOTIFY
:
645 ospf_apiclient_handle_ready (oclient
, msg
);
648 ospf_apiclient_handle_new_if (oclient
, msg
);
651 ospf_apiclient_handle_del_if (oclient
, msg
);
654 ospf_apiclient_handle_ism_change (oclient
, msg
);
657 ospf_apiclient_handle_nsm_change (oclient
, msg
);
659 case MSG_LSA_UPDATE_NOTIFY
:
660 ospf_apiclient_handle_lsa_update (oclient
, msg
);
662 case MSG_LSA_DELETE_NOTIFY
:
663 ospf_apiclient_handle_lsa_delete (oclient
, msg
);
666 fprintf (stderr
, "ospf_apiclient_read: Unknown message type: %d\n",
672 /* -----------------------------------------------------------
673 * Callback handler registration
674 * -----------------------------------------------------------
678 ospf_apiclient_register_callback (struct ospf_apiclient
*oclient
,
679 void (*ready_notify
) (u_char lsa_type
,
681 struct in_addr addr
),
682 void (*new_if
) (struct in_addr ifaddr
,
683 struct in_addr area_id
),
684 void (*del_if
) (struct in_addr ifaddr
),
685 void (*ism_change
) (struct in_addr ifaddr
,
686 struct in_addr area_id
,
688 void (*nsm_change
) (struct in_addr ifaddr
,
689 struct in_addr nbraddr
,
693 void (*update_notify
) (struct in_addr
700 void (*delete_notify
) (struct in_addr
709 assert (update_notify
);
711 /* Register callback function */
712 oclient
->ready_notify
= ready_notify
;
713 oclient
->new_if
= new_if
;
714 oclient
->del_if
= del_if
;
715 oclient
->ism_change
= ism_change
;
716 oclient
->nsm_change
= nsm_change
;
717 oclient
->update_notify
= update_notify
;
718 oclient
->delete_notify
= delete_notify
;
721 /* -----------------------------------------------------------
722 * Asynchronous message handling
723 * -----------------------------------------------------------
727 ospf_apiclient_handle_async (struct ospf_apiclient
*oclient
)
732 msg
= msg_read (oclient
->fd_async
);
736 /* Connection broke down */
741 ospf_apiclient_msghandle (oclient
, msg
);
743 /* Don't forget to free this message */