]>
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>
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_route.h"
51 #include "ospfd/ospf_zebra.h"
52 #include "ospfd/ospf_api.h"
53 #include "ospfd/ospf_errors.h"
55 #include "ospf_apiclient.h"
57 /* *sigh* ... can't find a better way to hammer this into automake */
58 #include "ospfd/ospf_dump_api.c"
59 #include "ospfd/ospf_api.c"
63 DEFINE_MGROUP(OSPFCLIENT
, "libospfapiclient");
64 DEFINE_MTYPE_STATIC(OSPFCLIENT
, OSPF_APICLIENT
, "OSPF-API client");
66 /* Backlog for listen */
69 /* -----------------------------------------------------------
70 * Forward declarations
71 * -----------------------------------------------------------
74 void ospf_apiclient_handle_reply(struct ospf_apiclient
*oclient
,
76 void ospf_apiclient_handle_update_notify(struct ospf_apiclient
*oclient
,
78 void ospf_apiclient_handle_delete_notify(struct ospf_apiclient
*oclient
,
81 /* -----------------------------------------------------------
83 * -----------------------------------------------------------
86 static unsigned short ospf_apiclient_getport(void)
88 struct servent
*sp
= getservbyname("ospfapi", "tcp");
90 return sp
? ntohs(sp
->s_port
) : OSPF_API_SYNC_PORT
;
93 /* -----------------------------------------------------------
94 * Following are functions for connection management
95 * -----------------------------------------------------------
98 struct ospf_apiclient
*ospf_apiclient_connect(char *host
, int syncport
)
100 struct sockaddr_in myaddr_sync
;
101 struct sockaddr_in myaddr_async
;
102 struct sockaddr_in peeraddr
;
104 struct ospf_apiclient
*new;
106 unsigned int peeraddrlen
;
107 int async_server_sock
;
112 /* There are two connections between the client and the server.
113 First the client opens a connection for synchronous requests/replies
114 to the server. The server will accept this connection and
115 as a reaction open a reverse connection channel for
116 asynchronous messages. */
118 async_server_sock
= socket(AF_INET
, SOCK_STREAM
, 0);
119 if (async_server_sock
< 0) {
121 "ospf_apiclient_connect: creating async socket failed\n");
125 /* Prepare socket for asynchronous messages */
126 /* Initialize async address structure */
127 memset(&myaddr_async
, 0, sizeof(myaddr_async
));
128 myaddr_async
.sin_family
= AF_INET
;
129 myaddr_async
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
130 myaddr_async
.sin_port
= htons(syncport
+ 1);
131 size
= sizeof(struct sockaddr_in
);
132 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
133 myaddr_async
.sin_len
= size
;
134 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
136 /* This is a server socket, reuse addr and port */
137 ret
= setsockopt(async_server_sock
, SOL_SOCKET
, SO_REUSEADDR
,
138 (void *)&on
, sizeof(on
));
141 "ospf_apiclient_connect: SO_REUSEADDR failed\n");
142 close(async_server_sock
);
147 ret
= setsockopt(async_server_sock
, SOL_SOCKET
, SO_REUSEPORT
,
148 (void *)&on
, sizeof(on
));
151 "ospf_apiclient_connect: SO_REUSEPORT failed\n");
152 close(async_server_sock
);
155 #endif /* SO_REUSEPORT */
157 /* Bind socket to address structure */
158 ret
= bind(async_server_sock
, (struct sockaddr
*)&myaddr_async
, size
);
161 "ospf_apiclient_connect: bind async socket failed\n");
162 close(async_server_sock
);
166 /* Wait for reverse channel connection establishment from server */
167 ret
= listen(async_server_sock
, BACKLOG
);
169 fprintf(stderr
, "ospf_apiclient_connect: listen: %s\n",
170 safe_strerror(errno
));
171 close(async_server_sock
);
175 /* Make connection for synchronous requests and connect to server */
176 /* Resolve address of server */
177 hp
= gethostbyname(host
);
179 fprintf(stderr
, "ospf_apiclient_connect: no such host %s\n",
181 close(async_server_sock
);
185 fd1
= socket(AF_INET
, SOCK_STREAM
, 0);
187 close(async_server_sock
);
189 "ospf_apiclient_connect: creating sync socket failed\n");
194 /* Reuse addr and port */
195 ret
= setsockopt(fd1
, SOL_SOCKET
, SO_REUSEADDR
, (void *)&on
,
199 "ospf_apiclient_connect: SO_REUSEADDR failed\n");
201 close(async_server_sock
);
206 ret
= setsockopt(fd1
, SOL_SOCKET
, SO_REUSEPORT
, (void *)&on
,
210 "ospf_apiclient_connect: SO_REUSEPORT failed\n");
212 close(async_server_sock
);
215 #endif /* SO_REUSEPORT */
218 /* Bind sync socket to address structure. This is needed since we
219 want the sync port number on a fixed port number. The reverse
220 async channel will be at this port+1 */
222 memset(&myaddr_sync
, 0, sizeof(myaddr_sync
));
223 myaddr_sync
.sin_family
= AF_INET
;
224 myaddr_sync
.sin_port
= htons(syncport
);
225 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
226 myaddr_sync
.sin_len
= sizeof(struct sockaddr_in
);
227 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
229 ret
= bind(fd1
, (struct sockaddr
*)&myaddr_sync
, size
);
232 "ospf_apiclient_connect: bind sync socket failed\n");
234 close(async_server_sock
);
238 /* Prepare address structure for connect */
239 memcpy(&myaddr_sync
.sin_addr
, hp
->h_addr
, hp
->h_length
);
240 myaddr_sync
.sin_family
= AF_INET
;
241 myaddr_sync
.sin_port
= htons(ospf_apiclient_getport());
242 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
243 myaddr_sync
.sin_len
= sizeof(struct sockaddr_in
);
244 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
246 /* Now establish synchronous channel with OSPF daemon */
247 ret
= connect(fd1
, (struct sockaddr
*)&myaddr_sync
,
248 sizeof(struct sockaddr_in
));
251 "ospf_apiclient_connect: sync connect failed\n");
252 close(async_server_sock
);
257 /* Accept reverse connection */
258 peeraddrlen
= sizeof(struct sockaddr_in
);
259 memset(&peeraddr
, 0, peeraddrlen
);
261 fd2
= accept(async_server_sock
, (struct sockaddr
*)&peeraddr
,
265 "ospf_apiclient_connect: accept async failed\n");
266 close(async_server_sock
);
272 /* Server socket is not needed anymore since we are not accepting more
274 close(async_server_sock
);
276 /* Create new client-side instance */
277 new = XCALLOC(MTYPE_OSPF_APICLIENT
, sizeof(struct ospf_apiclient
));
279 /* Initialize socket descriptors for sync and async channels */
286 int ospf_apiclient_close(struct ospf_apiclient
*oclient
)
289 if (oclient
->fd_sync
>= 0) {
290 close(oclient
->fd_sync
);
293 if (oclient
->fd_async
>= 0) {
294 close(oclient
->fd_async
);
297 /* Free client structure */
298 XFREE(MTYPE_OSPF_APICLIENT
, oclient
);
302 /* -----------------------------------------------------------
303 * Following are functions to send a request to OSPFd
304 * -----------------------------------------------------------
307 /* Send synchronous request, wait for reply */
308 static int ospf_apiclient_send_request(struct ospf_apiclient
*oclient
,
312 struct msg_reply
*msgreply
;
315 /* NB: Given "msg" is freed inside this function. */
317 /* Remember the sequence number of the request */
318 reqseq
= ntohl(msg
->hdr
.msgseq
);
320 /* Write message to OSPFd */
321 rc
= msg_write(oclient
->fd_sync
, msg
);
328 /* Wait for reply */ /* NB: New "msg" is allocated by "msg_read()". */
329 msg
= msg_read(oclient
->fd_sync
);
333 assert(msg
->hdr
.msgtype
== MSG_REPLY
);
334 assert(ntohl(msg
->hdr
.msgseq
) == reqseq
);
336 msgreply
= (struct msg_reply
*)STREAM_DATA(msg
->s
);
337 rc
= msgreply
->errcode
;
344 /* -----------------------------------------------------------
346 * -----------------------------------------------------------
349 static uint32_t ospf_apiclient_get_seqnr(void)
351 static uint32_t seqnr
= MIN_SEQ
;
355 /* Increment sequence number */
356 if (seqnr
< MAX_SEQ
) {
364 /* -----------------------------------------------------------
365 * API to access OSPF daemon by client applications.
366 * -----------------------------------------------------------
370 * Synchronous request to register opaque type.
372 int ospf_apiclient_register_opaque_type(struct ospf_apiclient
*cl
,
373 uint8_t ltype
, uint8_t otype
)
378 /* just put 1 as a sequence number. */
379 msg
= new_msg_register_opaque_type(ospf_apiclient_get_seqnr(), ltype
,
382 fprintf(stderr
, "new_msg_register_opaque_type failed\n");
386 rc
= ospf_apiclient_send_request(cl
, msg
);
391 * Synchronous request to synchronize with OSPF's LSDB.
392 * Two steps required: register_event in order to get
393 * dynamic updates and LSDB_Sync.
395 int ospf_apiclient_sync_lsdb(struct ospf_apiclient
*oclient
)
399 struct lsa_filter_type filter
;
401 filter
.typemask
= 0xFFFF; /* all LSAs */
402 filter
.origin
= ANY_ORIGIN
;
403 filter
.num_areas
= 0; /* all Areas. */
405 msg
= new_msg_register_event(ospf_apiclient_get_seqnr(), &filter
);
407 fprintf(stderr
, "new_msg_register_event failed\n");
410 rc
= ospf_apiclient_send_request(oclient
, msg
);
415 msg
= new_msg_sync_lsdb(ospf_apiclient_get_seqnr(), &filter
);
417 fprintf(stderr
, "new_msg_sync_lsdb failed\n");
420 rc
= ospf_apiclient_send_request(oclient
, msg
);
427 * Synchronous request to originate or update an LSA.
430 int ospf_apiclient_lsa_originate(struct ospf_apiclient
*oclient
,
431 struct in_addr ifaddr
, struct in_addr area_id
,
432 uint8_t lsa_type
, uint8_t opaque_type
,
433 uint32_t opaque_id
, void *opaquedata
,
438 uint8_t buf
[OSPF_MAX_LSA_SIZE
];
439 struct lsa_header
*lsah
;
442 /* Validate opaque LSA length */
443 if ((size_t)opaquelen
> sizeof(buf
) - sizeof(struct lsa_header
)) {
444 fprintf(stderr
, "opaquelen(%d) is larger than buf size %zu\n",
445 opaquelen
, sizeof(buf
));
446 return OSPF_API_NOMEMORY
;
449 /* We can only originate opaque LSAs */
450 if (!IS_OPAQUE_LSA(lsa_type
)) {
451 fprintf(stderr
, "Cannot originate non-opaque LSA type %d\n",
453 return OSPF_API_ILLEGALLSATYPE
;
456 /* Make a new LSA from parameters */
457 lsah
= (struct lsa_header
*)buf
;
460 lsah
->type
= lsa_type
;
462 tmp
= SET_OPAQUE_LSID(opaque_type
, opaque_id
);
463 lsah
->id
.s_addr
= htonl(tmp
);
464 lsah
->adv_router
.s_addr
= INADDR_ANY
;
467 lsah
->length
= htons(sizeof(struct lsa_header
) + opaquelen
);
469 memcpy(((uint8_t *)lsah
) + sizeof(struct lsa_header
), opaquedata
,
472 msg
= new_msg_originate_request(ospf_apiclient_get_seqnr(), ifaddr
,
475 fprintf(stderr
, "new_msg_originate_request failed\n");
476 return OSPF_API_NOMEMORY
;
479 rc
= ospf_apiclient_send_request(oclient
, msg
);
483 int ospf_apiclient_lsa_delete(struct ospf_apiclient
*oclient
,
484 struct in_addr addr
, uint8_t lsa_type
,
485 uint8_t opaque_type
, uint32_t opaque_id
,
491 /* Only opaque LSA can be deleted */
492 if (!IS_OPAQUE_LSA(lsa_type
)) {
493 fprintf(stderr
, "Cannot delete non-opaque LSA type %d\n",
495 return OSPF_API_ILLEGALLSATYPE
;
498 /* opaque_id is in host byte order and will be converted
499 * to network byte order by new_msg_delete_request */
500 msg
= new_msg_delete_request(ospf_apiclient_get_seqnr(), addr
, lsa_type
,
501 opaque_type
, opaque_id
, flags
);
503 rc
= ospf_apiclient_send_request(oclient
, msg
);
507 /* -----------------------------------------------------------
508 * Following are handlers for messages from OSPF daemon
509 * -----------------------------------------------------------
512 static void ospf_apiclient_handle_ready(struct ospf_apiclient
*oclient
,
515 struct msg_ready_notify
*r
;
516 r
= (struct msg_ready_notify
*)STREAM_DATA(msg
->s
);
518 /* Invoke registered callback function. */
519 if (oclient
->ready_notify
) {
520 (oclient
->ready_notify
)(r
->lsa_type
, r
->opaque_type
, r
->addr
);
524 static void ospf_apiclient_handle_new_if(struct ospf_apiclient
*oclient
,
527 struct msg_new_if
*n
;
528 n
= (struct msg_new_if
*)STREAM_DATA(msg
->s
);
530 /* Invoke registered callback function. */
531 if (oclient
->new_if
) {
532 (oclient
->new_if
)(n
->ifaddr
, n
->area_id
);
536 static void ospf_apiclient_handle_del_if(struct ospf_apiclient
*oclient
,
539 struct msg_del_if
*d
;
540 d
= (struct msg_del_if
*)STREAM_DATA(msg
->s
);
542 /* Invoke registered callback function. */
543 if (oclient
->del_if
) {
544 (oclient
->del_if
)(d
->ifaddr
);
548 static void 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
) {
556 (oclient
->ism_change
)(m
->ifaddr
, m
->area_id
, m
->status
);
560 static void ospf_apiclient_handle_nsm_change(struct ospf_apiclient
*oclient
,
563 struct msg_nsm_change
*m
;
564 m
= (struct msg_nsm_change
*)STREAM_DATA(msg
->s
);
566 /* Invoke registered callback function. */
567 if (oclient
->nsm_change
) {
568 (oclient
->nsm_change
)(m
->ifaddr
, m
->nbraddr
, m
->router_id
,
573 static void ospf_apiclient_handle_lsa_update(struct ospf_apiclient
*oclient
,
576 struct msg_lsa_change_notify
*cn
;
577 struct lsa_header
*lsa
;
581 cn
= (struct msg_lsa_change_notify
*)STREAM_DATA(msg
->s
);
583 /* Extract LSA from message */
584 lsalen
= ntohs(cn
->data
.length
);
585 if (lsalen
> OSPF_MAX_LSA_SIZE
) {
588 "%s: message received size: %d is greater than a LSA size: %d",
589 __func__
, lsalen
, OSPF_MAX_LSA_SIZE
);
593 p
= XMALLOC(MTYPE_OSPF_APICLIENT
, lsalen
);
595 memcpy(p
, &(cn
->data
), lsalen
);
598 /* Invoke registered update callback function */
599 if (oclient
->update_notify
) {
600 (oclient
->update_notify
)(cn
->ifaddr
, cn
->area_id
,
601 cn
->is_self_originated
, lsa
);
604 /* free memory allocated by ospf apiclient library */
605 XFREE(MTYPE_OSPF_APICLIENT
, p
);
608 static void ospf_apiclient_handle_lsa_delete(struct ospf_apiclient
*oclient
,
611 struct msg_lsa_change_notify
*cn
;
612 struct lsa_header
*lsa
;
616 cn
= (struct msg_lsa_change_notify
*)STREAM_DATA(msg
->s
);
618 /* Extract LSA from message */
619 lsalen
= ntohs(cn
->data
.length
);
620 if (lsalen
> OSPF_MAX_LSA_SIZE
) {
623 "%s: message received size: %d is greater than a LSA size: %d",
624 __func__
, lsalen
, OSPF_MAX_LSA_SIZE
);
628 p
= XMALLOC(MTYPE_OSPF_APICLIENT
, lsalen
);
630 memcpy(p
, &(cn
->data
), lsalen
);
633 /* Invoke registered update callback function */
634 if (oclient
->delete_notify
) {
635 (oclient
->delete_notify
)(cn
->ifaddr
, cn
->area_id
,
636 cn
->is_self_originated
, lsa
);
639 /* free memory allocated by ospf apiclient library */
640 XFREE(MTYPE_OSPF_APICLIENT
, p
);
643 static void ospf_apiclient_msghandle(struct ospf_apiclient
*oclient
,
646 /* Call message handler function. */
647 switch (msg
->hdr
.msgtype
) {
648 case MSG_READY_NOTIFY
:
649 ospf_apiclient_handle_ready(oclient
, msg
);
652 ospf_apiclient_handle_new_if(oclient
, msg
);
655 ospf_apiclient_handle_del_if(oclient
, msg
);
658 ospf_apiclient_handle_ism_change(oclient
, msg
);
661 ospf_apiclient_handle_nsm_change(oclient
, msg
);
663 case MSG_LSA_UPDATE_NOTIFY
:
664 ospf_apiclient_handle_lsa_update(oclient
, msg
);
666 case MSG_LSA_DELETE_NOTIFY
:
667 ospf_apiclient_handle_lsa_delete(oclient
, msg
);
671 "ospf_apiclient_read: Unknown message type: %d\n",
677 /* -----------------------------------------------------------
678 * Callback handler registration
679 * -----------------------------------------------------------
682 void ospf_apiclient_register_callback(
683 struct ospf_apiclient
*oclient
,
684 void (*ready_notify
)(uint8_t lsa_type
, uint8_t opaque_type
,
685 struct in_addr addr
),
686 void (*new_if
)(struct in_addr ifaddr
, struct in_addr area_id
),
687 void (*del_if
)(struct in_addr ifaddr
),
688 void (*ism_change
)(struct in_addr ifaddr
, struct in_addr area_id
,
690 void (*nsm_change
)(struct in_addr ifaddr
, struct in_addr nbraddr
,
691 struct in_addr router_id
, uint8_t status
),
692 void (*update_notify
)(struct in_addr ifaddr
, struct in_addr area_id
,
693 uint8_t self_origin
, struct lsa_header
*lsa
),
694 void (*delete_notify
)(struct in_addr ifaddr
, struct in_addr area_id
,
695 uint8_t self_origin
, struct lsa_header
*lsa
))
698 assert(update_notify
);
700 /* Register callback function */
701 oclient
->ready_notify
= ready_notify
;
702 oclient
->new_if
= new_if
;
703 oclient
->del_if
= del_if
;
704 oclient
->ism_change
= ism_change
;
705 oclient
->nsm_change
= nsm_change
;
706 oclient
->update_notify
= update_notify
;
707 oclient
->delete_notify
= delete_notify
;
710 /* -----------------------------------------------------------
711 * Asynchronous message handling
712 * -----------------------------------------------------------
715 int ospf_apiclient_handle_async(struct ospf_apiclient
*oclient
)
720 msg
= msg_read(oclient
->fd_async
);
723 /* Connection broke down */
728 ospf_apiclient_msghandle(oclient
, msg
);
730 /* Don't forget to free this message */