]>
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
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 /* work around gcc bug 69981, disable MTYPEs in libospf */
40 #define _QUAGGA_OSPF_MEMORY_H
42 #include "ospfd/ospfd.h"
43 #include "ospfd/ospf_interface.h"
44 #include "ospfd/ospf_asbr.h"
45 #include "ospfd/ospf_lsa.h"
46 #include "ospfd/ospf_opaque.h"
47 #include "ospfd/ospf_lsdb.h"
48 #include "ospfd/ospf_neighbor.h"
49 #include "ospfd/ospf_dump.h"
50 #include "ospfd/ospf_zebra.h"
51 #include "ospfd/ospf_api.h"
53 #include "ospf_apiclient.h"
55 /* *sigh* ... can't find a better way to hammer this into automake */
56 #include "ospfd/ospf_dump_api.c"
57 #include "ospfd/ospf_api.c"
59 DEFINE_MGROUP(OSPFCLIENT
, "libospfapiclient")
60 DEFINE_MTYPE_STATIC(OSPFCLIENT
, OSPF_APICLIENT
, "OSPF-API client")
62 /* Backlog for listen */
65 /* -----------------------------------------------------------
66 * Forward declarations
67 * -----------------------------------------------------------
70 void ospf_apiclient_handle_reply(struct ospf_apiclient
*oclient
,
72 void ospf_apiclient_handle_update_notify(struct ospf_apiclient
*oclient
,
74 void ospf_apiclient_handle_delete_notify(struct ospf_apiclient
*oclient
,
77 /* -----------------------------------------------------------
79 * -----------------------------------------------------------
82 static unsigned short 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
*ospf_apiclient_connect(char *host
, int syncport
)
96 struct sockaddr_in myaddr_sync
;
97 struct sockaddr_in myaddr_async
;
98 struct sockaddr_in peeraddr
;
100 struct ospf_apiclient
*new;
102 unsigned int peeraddrlen
;
103 int async_server_sock
;
108 /* There are two connections between the client and the server.
109 First the client opens a connection for synchronous requests/replies
110 to the server. The server will accept this connection and
111 as a reaction open a reverse connection channel for
112 asynchronous messages. */
114 async_server_sock
= socket(AF_INET
, SOCK_STREAM
, 0);
115 if (async_server_sock
< 0) {
117 "ospf_apiclient_connect: creating async socket failed\n");
121 /* Prepare socket for asynchronous messages */
122 /* Initialize async address structure */
123 memset(&myaddr_async
, 0, sizeof(struct sockaddr_in
));
124 myaddr_async
.sin_family
= AF_INET
;
125 myaddr_async
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
126 myaddr_async
.sin_port
= htons(syncport
+ 1);
127 size
= sizeof(struct sockaddr_in
);
128 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
129 myaddr_async
.sin_len
= size
;
130 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
132 /* This is a server socket, reuse addr and port */
133 ret
= setsockopt(async_server_sock
, SOL_SOCKET
, SO_REUSEADDR
,
134 (void *)&on
, sizeof(on
));
137 "ospf_apiclient_connect: SO_REUSEADDR failed\n");
138 close(async_server_sock
);
143 ret
= setsockopt(async_server_sock
, SOL_SOCKET
, SO_REUSEPORT
,
144 (void *)&on
, sizeof(on
));
147 "ospf_apiclient_connect: SO_REUSEPORT failed\n");
148 close(async_server_sock
);
151 #endif /* SO_REUSEPORT */
153 /* Bind socket to address structure */
154 ret
= bind(async_server_sock
, (struct sockaddr
*)&myaddr_async
, size
);
157 "ospf_apiclient_connect: bind async socket failed\n");
158 close(async_server_sock
);
162 /* Wait for reverse channel connection establishment from server */
163 ret
= listen(async_server_sock
, BACKLOG
);
165 fprintf(stderr
, "ospf_apiclient_connect: listen: %s\n",
166 safe_strerror(errno
));
167 close(async_server_sock
);
171 /* Make connection for synchronous requests and connect to server */
172 /* Resolve address of server */
173 hp
= gethostbyname(host
);
175 fprintf(stderr
, "ospf_apiclient_connect: no such host %s\n",
177 close(async_server_sock
);
181 fd1
= socket(AF_INET
, SOCK_STREAM
, 0);
184 "ospf_apiclient_connect: creating sync socket failed\n");
189 /* Reuse addr and port */
190 ret
= setsockopt(fd1
, SOL_SOCKET
, SO_REUSEADDR
, (void *)&on
,
194 "ospf_apiclient_connect: SO_REUSEADDR failed\n");
200 ret
= setsockopt(fd1
, SOL_SOCKET
, SO_REUSEPORT
, (void *)&on
,
204 "ospf_apiclient_connect: SO_REUSEPORT failed\n");
208 #endif /* SO_REUSEPORT */
211 /* Bind sync socket to address structure. This is needed since we
212 want the sync port number on a fixed port number. The reverse
213 async channel will be at this port+1 */
215 memset(&myaddr_sync
, 0, sizeof(struct sockaddr_in
));
216 myaddr_sync
.sin_family
= AF_INET
;
217 myaddr_sync
.sin_port
= htons(syncport
);
218 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
219 myaddr_sync
.sin_len
= sizeof(struct sockaddr_in
);
220 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
222 ret
= bind(fd1
, (struct sockaddr
*)&myaddr_sync
, size
);
225 "ospf_apiclient_connect: bind sync socket failed\n");
230 /* Prepare address structure for connect */
231 memcpy(&myaddr_sync
.sin_addr
, hp
->h_addr
, hp
->h_length
);
232 myaddr_sync
.sin_family
= AF_INET
;
233 myaddr_sync
.sin_port
= htons(ospf_apiclient_getport());
234 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
235 myaddr_sync
.sin_len
= sizeof(struct sockaddr_in
);
236 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
238 /* Now establish synchronous channel with OSPF daemon */
239 ret
= connect(fd1
, (struct sockaddr
*)&myaddr_sync
,
240 sizeof(struct sockaddr_in
));
243 "ospf_apiclient_connect: sync connect failed\n");
244 close(async_server_sock
);
249 /* Accept reverse connection */
250 peeraddrlen
= sizeof(struct sockaddr_in
);
251 memset(&peeraddr
, 0, peeraddrlen
);
253 fd2
= accept(async_server_sock
, (struct sockaddr
*)&peeraddr
,
257 "ospf_apiclient_connect: accept async failed\n");
258 close(async_server_sock
);
263 /* Server socket is not needed anymore since we are not accepting more
265 close(async_server_sock
);
267 /* Create new client-side instance */
268 new = XCALLOC(MTYPE_OSPF_APICLIENT
, sizeof(struct ospf_apiclient
));
270 /* Initialize socket descriptors for sync and async channels */
277 int ospf_apiclient_close(struct ospf_apiclient
*oclient
)
280 if (oclient
->fd_sync
>= 0) {
281 close(oclient
->fd_sync
);
284 if (oclient
->fd_async
>= 0) {
285 close(oclient
->fd_async
);
288 /* Free client structure */
289 XFREE(MTYPE_OSPF_APICLIENT
, oclient
);
293 /* -----------------------------------------------------------
294 * Followings are functions to send a request to OSPFd
295 * -----------------------------------------------------------
298 /* Send synchronous request, wait for reply */
299 static int ospf_apiclient_send_request(struct ospf_apiclient
*oclient
,
303 struct msg_reply
*msgreply
;
306 /* NB: Given "msg" is freed inside this function. */
308 /* Remember the sequence number of the request */
309 reqseq
= ntohl(msg
->hdr
.msgseq
);
311 /* Write message to OSPFd */
312 rc
= msg_write(oclient
->fd_sync
, msg
);
319 /* Wait for reply */ /* NB: New "msg" is allocated by "msg_read()". */
320 msg
= msg_read(oclient
->fd_sync
);
324 assert(msg
->hdr
.msgtype
== MSG_REPLY
);
325 assert(ntohl(msg
->hdr
.msgseq
) == reqseq
);
327 msgreply
= (struct msg_reply
*)STREAM_DATA(msg
->s
);
328 rc
= msgreply
->errcode
;
335 /* -----------------------------------------------------------
337 * -----------------------------------------------------------
340 static u_int32_t
ospf_apiclient_get_seqnr(void)
342 static u_int32_t seqnr
= MIN_SEQ
;
346 /* Increment sequence number */
347 if (seqnr
< MAX_SEQ
) {
355 /* -----------------------------------------------------------
356 * API to access OSPF daemon by client applications.
357 * -----------------------------------------------------------
361 * Synchronous request to register opaque type.
363 int ospf_apiclient_register_opaque_type(struct ospf_apiclient
*cl
, u_char ltype
,
369 /* just put 1 as a sequence number. */
370 msg
= new_msg_register_opaque_type(ospf_apiclient_get_seqnr(), ltype
,
373 fprintf(stderr
, "new_msg_register_opaque_type failed\n");
377 rc
= ospf_apiclient_send_request(cl
, msg
);
382 * Synchronous request to synchronize with OSPF's LSDB.
383 * Two steps required: register_event in order to get
384 * dynamic updates and LSDB_Sync.
386 int ospf_apiclient_sync_lsdb(struct ospf_apiclient
*oclient
)
390 struct lsa_filter_type filter
;
392 filter
.typemask
= 0xFFFF; /* all LSAs */
393 filter
.origin
= ANY_ORIGIN
;
394 filter
.num_areas
= 0; /* all Areas. */
396 msg
= new_msg_register_event(ospf_apiclient_get_seqnr(), &filter
);
398 fprintf(stderr
, "new_msg_register_event failed\n");
401 rc
= ospf_apiclient_send_request(oclient
, msg
);
406 msg
= new_msg_sync_lsdb(ospf_apiclient_get_seqnr(), &filter
);
408 fprintf(stderr
, "new_msg_sync_lsdb failed\n");
411 rc
= ospf_apiclient_send_request(oclient
, msg
);
418 * Synchronous request to originate or update an LSA.
421 int ospf_apiclient_lsa_originate(struct ospf_apiclient
*oclient
,
422 struct in_addr ifaddr
, struct in_addr area_id
,
423 u_char lsa_type
, u_char opaque_type
,
424 u_int32_t opaque_id
, void *opaquedata
,
429 u_char buf
[OSPF_MAX_LSA_SIZE
];
430 struct lsa_header
*lsah
;
434 /* We can only originate opaque LSAs */
435 if (!IS_OPAQUE_LSA(lsa_type
)) {
436 fprintf(stderr
, "Cannot originate non-opaque LSA type %d\n",
438 return OSPF_API_ILLEGALLSATYPE
;
441 /* Make a new LSA from parameters */
442 lsah
= (struct lsa_header
*)buf
;
445 lsah
->type
= lsa_type
;
447 tmp
= SET_OPAQUE_LSID(opaque_type
, opaque_id
);
448 lsah
->id
.s_addr
= htonl(tmp
);
449 lsah
->adv_router
.s_addr
= 0;
452 lsah
->length
= htons(sizeof(struct lsa_header
) + opaquelen
);
454 memcpy(((u_char
*)lsah
) + sizeof(struct lsa_header
), opaquedata
,
457 msg
= new_msg_originate_request(ospf_apiclient_get_seqnr(), ifaddr
,
460 fprintf(stderr
, "new_msg_originate_request failed\n");
461 return OSPF_API_NOMEMORY
;
464 rc
= ospf_apiclient_send_request(oclient
, msg
);
468 int ospf_apiclient_lsa_delete(struct ospf_apiclient
*oclient
,
469 struct in_addr area_id
, u_char lsa_type
,
470 u_char opaque_type
, u_int32_t opaque_id
)
475 /* Only opaque LSA can be deleted */
476 if (!IS_OPAQUE_LSA(lsa_type
)) {
477 fprintf(stderr
, "Cannot delete non-opaque LSA type %d\n",
479 return OSPF_API_ILLEGALLSATYPE
;
482 /* opaque_id is in host byte order and will be converted
483 * to network byte order by new_msg_delete_request */
484 msg
= new_msg_delete_request(ospf_apiclient_get_seqnr(), area_id
,
485 lsa_type
, opaque_type
, opaque_id
);
487 rc
= ospf_apiclient_send_request(oclient
, msg
);
491 /* -----------------------------------------------------------
492 * Followings are handlers for messages from OSPF daemon
493 * -----------------------------------------------------------
496 static void ospf_apiclient_handle_ready(struct ospf_apiclient
*oclient
,
499 struct msg_ready_notify
*r
;
500 r
= (struct msg_ready_notify
*)STREAM_DATA(msg
->s
);
502 /* Invoke registered callback function. */
503 if (oclient
->ready_notify
) {
504 (oclient
->ready_notify
)(r
->lsa_type
, r
->opaque_type
, r
->addr
);
508 static void ospf_apiclient_handle_new_if(struct ospf_apiclient
*oclient
,
511 struct msg_new_if
*n
;
512 n
= (struct msg_new_if
*)STREAM_DATA(msg
->s
);
514 /* Invoke registered callback function. */
515 if (oclient
->new_if
) {
516 (oclient
->new_if
)(n
->ifaddr
, n
->area_id
);
520 static void ospf_apiclient_handle_del_if(struct ospf_apiclient
*oclient
,
523 struct msg_del_if
*d
;
524 d
= (struct msg_del_if
*)STREAM_DATA(msg
->s
);
526 /* Invoke registered callback function. */
527 if (oclient
->del_if
) {
528 (oclient
->del_if
)(d
->ifaddr
);
532 static void ospf_apiclient_handle_ism_change(struct ospf_apiclient
*oclient
,
535 struct msg_ism_change
*m
;
536 m
= (struct msg_ism_change
*)STREAM_DATA(msg
->s
);
538 /* Invoke registered callback function. */
539 if (oclient
->ism_change
) {
540 (oclient
->ism_change
)(m
->ifaddr
, m
->area_id
, m
->status
);
544 static void ospf_apiclient_handle_nsm_change(struct ospf_apiclient
*oclient
,
547 struct msg_nsm_change
*m
;
548 m
= (struct msg_nsm_change
*)STREAM_DATA(msg
->s
);
550 /* Invoke registered callback function. */
551 if (oclient
->nsm_change
) {
552 (oclient
->nsm_change
)(m
->ifaddr
, m
->nbraddr
, m
->router_id
,
557 static void ospf_apiclient_handle_lsa_update(struct ospf_apiclient
*oclient
,
560 struct msg_lsa_change_notify
*cn
;
561 struct lsa_header
*lsa
;
564 cn
= (struct msg_lsa_change_notify
*)STREAM_DATA(msg
->s
);
566 /* Extract LSA from message */
567 lsalen
= ntohs(cn
->data
.length
);
568 lsa
= XMALLOC(MTYPE_OSPF_APICLIENT
, lsalen
);
570 fprintf(stderr
, "LSA update: Cannot allocate memory for LSA\n");
573 memcpy(lsa
, &(cn
->data
), lsalen
);
575 /* Invoke registered update callback function */
576 if (oclient
->update_notify
) {
577 (oclient
->update_notify
)(cn
->ifaddr
, cn
->area_id
,
578 cn
->is_self_originated
, lsa
);
581 /* free memory allocated by ospf apiclient library */
582 XFREE(MTYPE_OSPF_APICLIENT
, lsa
);
585 static void ospf_apiclient_handle_lsa_delete(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
);
598 fprintf(stderr
, "LSA delete: Cannot allocate memory for LSA\n");
601 memcpy(lsa
, &(cn
->data
), lsalen
);
603 /* Invoke registered update callback function */
604 if (oclient
->delete_notify
) {
605 (oclient
->delete_notify
)(cn
->ifaddr
, cn
->area_id
,
606 cn
->is_self_originated
, lsa
);
609 /* free memory allocated by ospf apiclient library */
610 XFREE(MTYPE_OSPF_APICLIENT
, lsa
);
613 static void ospf_apiclient_msghandle(struct ospf_apiclient
*oclient
,
616 /* Call message handler function. */
617 switch (msg
->hdr
.msgtype
) {
618 case MSG_READY_NOTIFY
:
619 ospf_apiclient_handle_ready(oclient
, msg
);
622 ospf_apiclient_handle_new_if(oclient
, msg
);
625 ospf_apiclient_handle_del_if(oclient
, msg
);
628 ospf_apiclient_handle_ism_change(oclient
, msg
);
631 ospf_apiclient_handle_nsm_change(oclient
, msg
);
633 case MSG_LSA_UPDATE_NOTIFY
:
634 ospf_apiclient_handle_lsa_update(oclient
, msg
);
636 case MSG_LSA_DELETE_NOTIFY
:
637 ospf_apiclient_handle_lsa_delete(oclient
, msg
);
641 "ospf_apiclient_read: Unknown message type: %d\n",
647 /* -----------------------------------------------------------
648 * Callback handler registration
649 * -----------------------------------------------------------
652 void ospf_apiclient_register_callback(
653 struct ospf_apiclient
*oclient
,
654 void (*ready_notify
)(u_char lsa_type
, u_char opaque_type
,
655 struct in_addr addr
),
656 void (*new_if
)(struct in_addr ifaddr
, struct in_addr area_id
),
657 void (*del_if
)(struct in_addr ifaddr
),
658 void (*ism_change
)(struct in_addr ifaddr
, struct in_addr area_id
,
660 void (*nsm_change
)(struct in_addr ifaddr
, struct in_addr nbraddr
,
661 struct in_addr router_id
, u_char status
),
662 void (*update_notify
)(struct in_addr ifaddr
, struct in_addr area_id
,
663 u_char self_origin
, struct lsa_header
*lsa
),
664 void (*delete_notify
)(struct in_addr ifaddr
, struct in_addr area_id
,
665 u_char self_origin
, struct lsa_header
*lsa
))
668 assert(update_notify
);
670 /* Register callback function */
671 oclient
->ready_notify
= ready_notify
;
672 oclient
->new_if
= new_if
;
673 oclient
->del_if
= del_if
;
674 oclient
->ism_change
= ism_change
;
675 oclient
->nsm_change
= nsm_change
;
676 oclient
->update_notify
= update_notify
;
677 oclient
->delete_notify
= delete_notify
;
680 /* -----------------------------------------------------------
681 * Asynchronous message handling
682 * -----------------------------------------------------------
685 int ospf_apiclient_handle_async(struct ospf_apiclient
*oclient
)
690 msg
= msg_read(oclient
->fd_async
);
693 /* Connection broke down */
698 ospf_apiclient_msghandle(oclient
, msg
);
700 /* Don't forget to free this message */