]>
git.proxmox.com Git - mirror_frr.git/blob - ospfclient/ospf_apiclient.c
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 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 #include <lib/version.h>
38 /* work around gcc bug 69981, disable MTYPEs in libospf */
39 #define _QUAGGA_OSPF_MEMORY_H
41 #include "ospfd/ospfd.h"
42 #include "ospfd/ospf_interface.h"
43 #include "ospfd/ospf_asbr.h"
44 #include "ospfd/ospf_lsa.h"
45 #include "ospfd/ospf_opaque.h"
46 #include "ospfd/ospf_lsdb.h"
47 #include "ospfd/ospf_neighbor.h"
48 #include "ospfd/ospf_dump.h"
49 #include "ospfd/ospf_zebra.h"
50 #include "ospfd/ospf_api.h"
52 #include "ospf_apiclient.h"
54 /* *sigh* ... can't find a better way to hammer this into automake */
55 #include "ospfd/ospf_dump_api.c"
56 #include "ospfd/ospf_api.c"
58 DEFINE_MGROUP(OSPFCLIENT
, "libospfapiclient")
59 DEFINE_MTYPE_STATIC(OSPFCLIENT
, OSPF_APICLIENT
, "OSPF-API client")
61 /* Backlog for listen */
64 /* -----------------------------------------------------------
65 * Forward declarations
66 * -----------------------------------------------------------
69 void ospf_apiclient_handle_reply (struct ospf_apiclient
*oclient
,
71 void ospf_apiclient_handle_update_notify (struct ospf_apiclient
*oclient
,
73 void ospf_apiclient_handle_delete_notify (struct ospf_apiclient
*oclient
,
76 /* -----------------------------------------------------------
78 * -----------------------------------------------------------
82 ospf_apiclient_getport (void)
84 struct servent
*sp
= getservbyname ("ospfapi", "tcp");
86 return sp
? ntohs (sp
->s_port
) : OSPF_API_SYNC_PORT
;
89 /* -----------------------------------------------------------
90 * Followings are functions for connection management
91 * -----------------------------------------------------------
94 struct ospf_apiclient
*
95 ospf_apiclient_connect (char *host
, int syncport
)
97 struct sockaddr_in myaddr_sync
;
98 struct sockaddr_in myaddr_async
;
99 struct sockaddr_in peeraddr
;
101 struct ospf_apiclient
*new;
103 unsigned int peeraddrlen
;
104 int async_server_sock
;
109 /* There are two connections between the client and the server.
110 First the client opens a connection for synchronous requests/replies
111 to the server. The server will accept this connection and
112 as a reaction open a reverse connection channel for
113 asynchronous messages. */
115 async_server_sock
= socket (AF_INET
, SOCK_STREAM
, 0);
116 if (async_server_sock
< 0)
119 "ospf_apiclient_connect: creating async socket failed\n");
123 /* Prepare socket for asynchronous messages */
124 /* Initialize async address structure */
125 memset (&myaddr_async
, 0, sizeof (struct sockaddr_in
));
126 myaddr_async
.sin_family
= AF_INET
;
127 myaddr_async
.sin_addr
.s_addr
= htonl (INADDR_ANY
);
128 myaddr_async
.sin_port
= htons (syncport
+1);
129 size
= sizeof (struct sockaddr_in
);
130 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
131 myaddr_async
.sin_len
= size
;
132 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
134 /* This is a server socket, reuse addr and port */
135 ret
= setsockopt (async_server_sock
, SOL_SOCKET
,
136 SO_REUSEADDR
, (void *) &on
, sizeof (on
));
139 fprintf (stderr
, "ospf_apiclient_connect: SO_REUSEADDR failed\n");
140 close (async_server_sock
);
145 ret
= setsockopt (async_server_sock
, SOL_SOCKET
, SO_REUSEPORT
,
146 (void *) &on
, sizeof (on
));
149 fprintf (stderr
, "ospf_apiclient_connect: SO_REUSEPORT failed\n");
150 close (async_server_sock
);
153 #endif /* SO_REUSEPORT */
155 /* Bind socket to address structure */
156 ret
= bind (async_server_sock
, (struct sockaddr
*) &myaddr_async
, size
);
159 fprintf (stderr
, "ospf_apiclient_connect: bind async socket failed\n");
160 close (async_server_sock
);
164 /* Wait for reverse channel connection establishment from server */
165 ret
= listen (async_server_sock
, BACKLOG
);
168 fprintf (stderr
, "ospf_apiclient_connect: listen: %s\n", safe_strerror (errno
));
169 close (async_server_sock
);
173 /* Make connection for synchronous requests and connect to server */
174 /* Resolve address of server */
175 hp
= gethostbyname (host
);
178 fprintf (stderr
, "ospf_apiclient_connect: no such host %s\n", host
);
179 close (async_server_sock
);
183 fd1
= socket (AF_INET
, SOCK_STREAM
, 0);
187 "ospf_apiclient_connect: creating sync socket failed\n");
192 /* Reuse addr and port */
193 ret
= setsockopt (fd1
, SOL_SOCKET
,
194 SO_REUSEADDR
, (void *) &on
, sizeof (on
));
197 fprintf (stderr
, "ospf_apiclient_connect: SO_REUSEADDR failed\n");
203 ret
= setsockopt (fd1
, SOL_SOCKET
, SO_REUSEPORT
,
204 (void *) &on
, sizeof (on
));
207 fprintf (stderr
, "ospf_apiclient_connect: SO_REUSEPORT failed\n");
211 #endif /* SO_REUSEPORT */
214 /* Bind sync socket to address structure. This is needed since we
215 want the sync port number on a fixed port number. The reverse
216 async channel will be at this port+1 */
218 memset (&myaddr_sync
, 0, sizeof (struct sockaddr_in
));
219 myaddr_sync
.sin_family
= AF_INET
;
220 myaddr_sync
.sin_port
= htons (syncport
);
221 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
222 myaddr_sync
.sin_len
= sizeof (struct sockaddr_in
);
223 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
225 ret
= bind (fd1
, (struct sockaddr
*) &myaddr_sync
, size
);
228 fprintf (stderr
, "ospf_apiclient_connect: bind sync socket failed\n");
233 /* Prepare address structure for connect */
234 memcpy (&myaddr_sync
.sin_addr
, hp
->h_addr
, hp
->h_length
);
235 myaddr_sync
.sin_family
= AF_INET
;
236 myaddr_sync
.sin_port
= htons(ospf_apiclient_getport ());
237 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
238 myaddr_sync
.sin_len
= sizeof (struct sockaddr_in
);
239 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
241 /* Now establish synchronous channel with OSPF daemon */
242 ret
= connect (fd1
, (struct sockaddr
*) &myaddr_sync
,
243 sizeof (struct sockaddr_in
));
246 fprintf (stderr
, "ospf_apiclient_connect: sync connect failed\n");
247 close (async_server_sock
);
252 /* Accept reverse connection */
253 peeraddrlen
= sizeof (struct sockaddr_in
);
254 memset (&peeraddr
, 0, peeraddrlen
);
257 accept (async_server_sock
, (struct sockaddr
*) &peeraddr
, &peeraddrlen
);
260 fprintf (stderr
, "ospf_apiclient_connect: accept async failed\n");
261 close (async_server_sock
);
266 /* Server socket is not needed anymore since we are not accepting more
268 close (async_server_sock
);
270 /* Create new client-side instance */
271 new = XCALLOC (MTYPE_OSPF_APICLIENT
, sizeof (struct ospf_apiclient
));
273 /* Initialize socket descriptors for sync and async channels */
281 ospf_apiclient_close (struct ospf_apiclient
*oclient
)
284 if (oclient
->fd_sync
>= 0)
286 close (oclient
->fd_sync
);
289 if (oclient
->fd_async
>= 0)
291 close (oclient
->fd_async
);
294 /* Free client structure */
295 XFREE (MTYPE_OSPF_APICLIENT
, oclient
);
299 /* -----------------------------------------------------------
300 * Followings are functions to send a request to OSPFd
301 * -----------------------------------------------------------
304 /* Send synchronous request, wait for reply */
306 ospf_apiclient_send_request (struct ospf_apiclient
*oclient
, struct msg
*msg
)
309 struct msg_reply
*msgreply
;
312 /* NB: Given "msg" is freed inside this function. */
314 /* Remember the sequence number of the request */
315 reqseq
= ntohl (msg
->hdr
.msgseq
);
317 /* Write message to OSPFd */
318 rc
= msg_write (oclient
->fd_sync
, msg
);
326 /* Wait for reply *//* NB: New "msg" is allocated by "msg_read()". */
327 msg
= msg_read (oclient
->fd_sync
);
331 assert (msg
->hdr
.msgtype
== MSG_REPLY
);
332 assert (ntohl (msg
->hdr
.msgseq
) == reqseq
);
334 msgreply
= (struct msg_reply
*) STREAM_DATA (msg
->s
);
335 rc
= msgreply
->errcode
;
342 /* -----------------------------------------------------------
344 * -----------------------------------------------------------
348 ospf_apiclient_get_seqnr (void)
350 static u_int32_t seqnr
= MIN_SEQ
;
354 /* Increment sequence number */
366 /* -----------------------------------------------------------
367 * API to access OSPF daemon by client applications.
368 * -----------------------------------------------------------
372 * Synchronous request to register opaque type.
375 ospf_apiclient_register_opaque_type (struct ospf_apiclient
*cl
,
376 u_char ltype
, u_char otype
)
381 /* just put 1 as a sequence number. */
382 msg
= new_msg_register_opaque_type (ospf_apiclient_get_seqnr (),
386 fprintf (stderr
, "new_msg_register_opaque_type failed\n");
390 rc
= ospf_apiclient_send_request (cl
, msg
);
395 * Synchronous request to synchronize with OSPF's LSDB.
396 * Two steps required: register_event in order to get
397 * dynamic updates and LSDB_Sync.
400 ospf_apiclient_sync_lsdb (struct ospf_apiclient
*oclient
)
404 struct lsa_filter_type filter
;
406 filter
.typemask
= 0xFFFF; /* all LSAs */
407 filter
.origin
= ANY_ORIGIN
;
408 filter
.num_areas
= 0; /* all Areas. */
410 msg
= new_msg_register_event (ospf_apiclient_get_seqnr (), &filter
);
413 fprintf (stderr
, "new_msg_register_event failed\n");
416 rc
= ospf_apiclient_send_request (oclient
, msg
);
421 msg
= new_msg_sync_lsdb (ospf_apiclient_get_seqnr (), &filter
);
424 fprintf (stderr
, "new_msg_sync_lsdb failed\n");
427 rc
= ospf_apiclient_send_request (oclient
, msg
);
434 * Synchronous request to originate or update an LSA.
438 ospf_apiclient_lsa_originate (struct ospf_apiclient
*oclient
,
439 struct in_addr ifaddr
,
440 struct in_addr area_id
,
442 u_char opaque_type
, u_int32_t opaque_id
,
443 void *opaquedata
, int opaquelen
)
447 u_char buf
[OSPF_MAX_LSA_SIZE
];
448 struct lsa_header
*lsah
;
452 /* We can only originate opaque LSAs */
453 if (!IS_OPAQUE_LSA (lsa_type
))
455 fprintf (stderr
, "Cannot originate non-opaque LSA type %d\n", lsa_type
);
456 return OSPF_API_ILLEGALLSATYPE
;
459 /* Make a new LSA from parameters */
460 lsah
= (struct lsa_header
*) buf
;
463 lsah
->type
= lsa_type
;
465 tmp
= SET_OPAQUE_LSID (opaque_type
, opaque_id
);
466 lsah
->id
.s_addr
= htonl (tmp
);
467 lsah
->adv_router
.s_addr
= 0;
470 lsah
->length
= htons (sizeof (struct lsa_header
) + opaquelen
);
472 memcpy (((u_char
*) lsah
) + sizeof (struct lsa_header
), opaquedata
,
475 msg
= new_msg_originate_request (ospf_apiclient_get_seqnr (),
476 ifaddr
, area_id
, lsah
);
479 fprintf (stderr
, "new_msg_originate_request failed\n");
480 return OSPF_API_NOMEMORY
;
483 rc
= ospf_apiclient_send_request (oclient
, msg
);
488 ospf_apiclient_lsa_delete (struct ospf_apiclient
*oclient
,
489 struct in_addr area_id
, u_char lsa_type
,
490 u_char opaque_type
, u_int32_t opaque_id
)
495 /* Only opaque LSA can be deleted */
496 if (!IS_OPAQUE_LSA (lsa_type
))
498 fprintf (stderr
, "Cannot delete non-opaque LSA type %d\n", lsa_type
);
499 return OSPF_API_ILLEGALLSATYPE
;
502 /* opaque_id is in host byte order and will be converted
503 * to network byte order by new_msg_delete_request */
504 msg
= new_msg_delete_request (ospf_apiclient_get_seqnr (),
505 area_id
, lsa_type
, opaque_type
, opaque_id
);
507 rc
= ospf_apiclient_send_request (oclient
, msg
);
511 /* -----------------------------------------------------------
512 * Followings are handlers for messages from OSPF daemon
513 * -----------------------------------------------------------
517 ospf_apiclient_handle_ready (struct ospf_apiclient
*oclient
, struct msg
*msg
)
519 struct msg_ready_notify
*r
;
520 r
= (struct msg_ready_notify
*) STREAM_DATA (msg
->s
);
522 /* Invoke registered callback function. */
523 if (oclient
->ready_notify
)
525 (oclient
->ready_notify
) (r
->lsa_type
, r
->opaque_type
, r
->addr
);
530 ospf_apiclient_handle_new_if (struct ospf_apiclient
*oclient
, struct msg
*msg
)
532 struct msg_new_if
*n
;
533 n
= (struct msg_new_if
*) STREAM_DATA (msg
->s
);
535 /* Invoke registered callback function. */
538 (oclient
->new_if
) (n
->ifaddr
, n
->area_id
);
543 ospf_apiclient_handle_del_if (struct ospf_apiclient
*oclient
, struct msg
*msg
)
545 struct msg_del_if
*d
;
546 d
= (struct msg_del_if
*) STREAM_DATA (msg
->s
);
548 /* Invoke registered callback function. */
551 (oclient
->del_if
) (d
->ifaddr
);
556 ospf_apiclient_handle_ism_change (struct ospf_apiclient
*oclient
,
559 struct msg_ism_change
*m
;
560 m
= (struct msg_ism_change
*) STREAM_DATA (msg
->s
);
562 /* Invoke registered callback function. */
563 if (oclient
->ism_change
)
565 (oclient
->ism_change
) (m
->ifaddr
, m
->area_id
, m
->status
);
571 ospf_apiclient_handle_nsm_change (struct ospf_apiclient
*oclient
,
574 struct msg_nsm_change
*m
;
575 m
= (struct msg_nsm_change
*) STREAM_DATA (msg
->s
);
577 /* Invoke registered callback function. */
578 if (oclient
->nsm_change
)
580 (oclient
->nsm_change
) (m
->ifaddr
, m
->nbraddr
, m
->router_id
, m
->status
);
585 ospf_apiclient_handle_lsa_update (struct ospf_apiclient
*oclient
,
588 struct msg_lsa_change_notify
*cn
;
589 struct lsa_header
*lsa
;
592 cn
= (struct msg_lsa_change_notify
*) STREAM_DATA (msg
->s
);
594 /* Extract LSA from message */
595 lsalen
= ntohs (cn
->data
.length
);
596 lsa
= XMALLOC (MTYPE_OSPF_APICLIENT
, lsalen
);
599 fprintf (stderr
, "LSA update: Cannot allocate memory for LSA\n");
602 memcpy (lsa
, &(cn
->data
), lsalen
);
604 /* Invoke registered update callback function */
605 if (oclient
->update_notify
)
607 (oclient
->update_notify
) (cn
->ifaddr
, cn
->area_id
,
608 cn
->is_self_originated
, lsa
);
611 /* free memory allocated by ospf apiclient library */
612 XFREE (MTYPE_OSPF_APICLIENT
, lsa
);
616 ospf_apiclient_handle_lsa_delete (struct ospf_apiclient
*oclient
,
619 struct msg_lsa_change_notify
*cn
;
620 struct lsa_header
*lsa
;
623 cn
= (struct msg_lsa_change_notify
*) STREAM_DATA (msg
->s
);
625 /* Extract LSA from message */
626 lsalen
= ntohs (cn
->data
.length
);
627 lsa
= XMALLOC (MTYPE_OSPF_APICLIENT
, lsalen
);
630 fprintf (stderr
, "LSA delete: Cannot allocate memory for LSA\n");
633 memcpy (lsa
, &(cn
->data
), lsalen
);
635 /* Invoke registered update callback function */
636 if (oclient
->delete_notify
)
638 (oclient
->delete_notify
) (cn
->ifaddr
, cn
->area_id
,
639 cn
->is_self_originated
, lsa
);
642 /* free memory allocated by ospf apiclient library */
643 XFREE (MTYPE_OSPF_APICLIENT
, lsa
);
647 ospf_apiclient_msghandle (struct ospf_apiclient
*oclient
, struct msg
*msg
)
649 /* Call message handler function. */
650 switch (msg
->hdr
.msgtype
)
652 case MSG_READY_NOTIFY
:
653 ospf_apiclient_handle_ready (oclient
, msg
);
656 ospf_apiclient_handle_new_if (oclient
, msg
);
659 ospf_apiclient_handle_del_if (oclient
, msg
);
662 ospf_apiclient_handle_ism_change (oclient
, msg
);
665 ospf_apiclient_handle_nsm_change (oclient
, msg
);
667 case MSG_LSA_UPDATE_NOTIFY
:
668 ospf_apiclient_handle_lsa_update (oclient
, msg
);
670 case MSG_LSA_DELETE_NOTIFY
:
671 ospf_apiclient_handle_lsa_delete (oclient
, msg
);
674 fprintf (stderr
, "ospf_apiclient_read: Unknown message type: %d\n",
680 /* -----------------------------------------------------------
681 * Callback handler registration
682 * -----------------------------------------------------------
686 ospf_apiclient_register_callback (struct ospf_apiclient
*oclient
,
687 void (*ready_notify
) (u_char lsa_type
,
689 struct in_addr addr
),
690 void (*new_if
) (struct in_addr ifaddr
,
691 struct in_addr area_id
),
692 void (*del_if
) (struct in_addr ifaddr
),
693 void (*ism_change
) (struct in_addr ifaddr
,
694 struct in_addr area_id
,
696 void (*nsm_change
) (struct in_addr ifaddr
,
697 struct in_addr nbraddr
,
701 void (*update_notify
) (struct in_addr
708 void (*delete_notify
) (struct in_addr
717 assert (update_notify
);
719 /* Register callback function */
720 oclient
->ready_notify
= ready_notify
;
721 oclient
->new_if
= new_if
;
722 oclient
->del_if
= del_if
;
723 oclient
->ism_change
= ism_change
;
724 oclient
->nsm_change
= nsm_change
;
725 oclient
->update_notify
= update_notify
;
726 oclient
->delete_notify
= delete_notify
;
729 /* -----------------------------------------------------------
730 * Asynchronous message handling
731 * -----------------------------------------------------------
735 ospf_apiclient_handle_async (struct ospf_apiclient
*oclient
)
740 msg
= msg_read (oclient
->fd_async
);
744 /* Connection broke down */
749 ospf_apiclient_msghandle (oclient
, msg
);
751 /* Don't forget to free this message */