]>
git.proxmox.com Git - mirror_frr.git/blob - ospfclient/ospf_apiclient.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Client side of OSPF API.
4 * Copyright (C) 2001, 2002, 2003 Ralph Keller
9 #include <lib/version.h>
24 /* work around gcc bug 69981, disable MTYPEs in libospf */
25 #define _QUAGGA_OSPF_MEMORY_H
27 #include "ospfd/ospfd.h"
28 #include "ospfd/ospf_interface.h"
29 #include "ospfd/ospf_asbr.h"
30 #include "ospfd/ospf_lsa.h"
31 #include "ospfd/ospf_opaque.h"
32 #include "ospfd/ospf_lsdb.h"
33 #include "ospfd/ospf_neighbor.h"
34 #include "ospfd/ospf_dump.h"
35 #include "ospfd/ospf_route.h"
36 #include "ospfd/ospf_zebra.h"
37 #include "ospfd/ospf_api.h"
38 #include "ospfd/ospf_errors.h"
40 #include "ospf_apiclient.h"
44 DEFINE_MGROUP(OSPFCLIENT
, "libospfapiclient");
45 DEFINE_MTYPE_STATIC(OSPFCLIENT
, OSPF_APICLIENT
, "OSPF-API client");
47 /* Backlog for listen */
50 /* -----------------------------------------------------------
51 * Forward declarations
52 * -----------------------------------------------------------
55 void ospf_apiclient_handle_reply(struct ospf_apiclient
*oclient
,
57 void ospf_apiclient_handle_update_notify(struct ospf_apiclient
*oclient
,
59 void ospf_apiclient_handle_delete_notify(struct ospf_apiclient
*oclient
,
62 /* -----------------------------------------------------------
64 * -----------------------------------------------------------
67 static unsigned short ospf_apiclient_getport(void)
69 struct servent
*sp
= getservbyname("ospfapi", "tcp");
71 return sp
? ntohs(sp
->s_port
) : OSPF_API_SYNC_PORT
;
74 /* -----------------------------------------------------------
75 * Following are functions for connection management
76 * -----------------------------------------------------------
79 struct ospf_apiclient
*ospf_apiclient_connect(char *host
, int syncport
)
81 struct sockaddr_in myaddr_sync
;
82 struct sockaddr_in myaddr_async
;
83 struct sockaddr_in peeraddr
;
85 struct ospf_apiclient
*new;
87 unsigned int peeraddrlen
;
88 int async_server_sock
;
93 /* There are two connections between the client and the server.
94 First the client opens a connection for synchronous requests/replies
95 to the server. The server will accept this connection and
96 as a reaction open a reverse connection channel for
97 asynchronous messages. */
99 async_server_sock
= socket(AF_INET
, SOCK_STREAM
, 0);
100 if (async_server_sock
< 0) {
102 "ospf_apiclient_connect: creating async socket failed\n");
106 /* Prepare socket for asynchronous messages */
107 /* Initialize async address structure */
108 memset(&myaddr_async
, 0, sizeof(myaddr_async
));
109 myaddr_async
.sin_family
= AF_INET
;
110 myaddr_async
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
111 myaddr_async
.sin_port
= htons(syncport
+ 1);
112 size
= sizeof(struct sockaddr_in
);
113 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
114 myaddr_async
.sin_len
= size
;
115 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
117 /* This is a server socket, reuse addr and port */
118 ret
= setsockopt(async_server_sock
, SOL_SOCKET
, SO_REUSEADDR
,
119 (void *)&on
, sizeof(on
));
122 "ospf_apiclient_connect: SO_REUSEADDR failed\n");
123 close(async_server_sock
);
128 ret
= setsockopt(async_server_sock
, SOL_SOCKET
, SO_REUSEPORT
,
129 (void *)&on
, sizeof(on
));
132 "ospf_apiclient_connect: SO_REUSEPORT failed\n");
133 close(async_server_sock
);
136 #endif /* SO_REUSEPORT */
138 /* Bind socket to address structure */
139 ret
= bind(async_server_sock
, (struct sockaddr
*)&myaddr_async
, size
);
142 "ospf_apiclient_connect: bind async socket failed\n");
143 close(async_server_sock
);
147 /* Wait for reverse channel connection establishment from server */
148 ret
= listen(async_server_sock
, BACKLOG
);
150 fprintf(stderr
, "ospf_apiclient_connect: listen: %s\n",
151 safe_strerror(errno
));
152 close(async_server_sock
);
156 /* Make connection for synchronous requests and connect to server */
157 /* Resolve address of server */
158 hp
= gethostbyname(host
);
160 fprintf(stderr
, "ospf_apiclient_connect: no such host %s\n",
162 close(async_server_sock
);
166 fd1
= socket(AF_INET
, SOCK_STREAM
, 0);
168 close(async_server_sock
);
170 "ospf_apiclient_connect: creating sync socket failed\n");
175 /* Reuse addr and port */
176 ret
= setsockopt(fd1
, SOL_SOCKET
, SO_REUSEADDR
, (void *)&on
,
180 "ospf_apiclient_connect: SO_REUSEADDR failed\n");
182 close(async_server_sock
);
187 ret
= setsockopt(fd1
, SOL_SOCKET
, SO_REUSEPORT
, (void *)&on
,
191 "ospf_apiclient_connect: SO_REUSEPORT failed\n");
193 close(async_server_sock
);
196 #endif /* SO_REUSEPORT */
199 /* Bind sync socket to address structure. This is needed since we
200 want the sync port number on a fixed port number. The reverse
201 async channel will be at this port+1 */
203 memset(&myaddr_sync
, 0, sizeof(myaddr_sync
));
204 myaddr_sync
.sin_family
= AF_INET
;
205 myaddr_sync
.sin_port
= htons(syncport
);
206 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
207 myaddr_sync
.sin_len
= sizeof(struct sockaddr_in
);
208 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
210 ret
= bind(fd1
, (struct sockaddr
*)&myaddr_sync
, size
);
213 "ospf_apiclient_connect: bind sync socket failed\n");
215 close(async_server_sock
);
219 /* Prepare address structure for connect */
220 memcpy(&myaddr_sync
.sin_addr
, hp
->h_addr
, hp
->h_length
);
221 myaddr_sync
.sin_family
= AF_INET
;
222 myaddr_sync
.sin_port
= htons(ospf_apiclient_getport());
223 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
224 myaddr_sync
.sin_len
= sizeof(struct sockaddr_in
);
225 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
227 /* Now establish synchronous channel with OSPF daemon */
228 ret
= connect(fd1
, (struct sockaddr
*)&myaddr_sync
,
229 sizeof(struct sockaddr_in
));
232 "ospf_apiclient_connect: sync connect failed\n");
233 close(async_server_sock
);
238 /* Accept reverse connection */
239 peeraddrlen
= sizeof(struct sockaddr_in
);
240 memset(&peeraddr
, 0, peeraddrlen
);
242 fd2
= accept(async_server_sock
, (struct sockaddr
*)&peeraddr
,
246 "ospf_apiclient_connect: accept async failed\n");
247 close(async_server_sock
);
253 /* Server socket is not needed anymore since we are not accepting more
255 close(async_server_sock
);
257 /* Create new client-side instance */
258 new = XCALLOC(MTYPE_OSPF_APICLIENT
, sizeof(struct ospf_apiclient
));
260 /* Initialize socket descriptors for sync and async channels */
267 int ospf_apiclient_close(struct ospf_apiclient
*oclient
)
270 if (oclient
->fd_sync
>= 0) {
271 close(oclient
->fd_sync
);
274 if (oclient
->fd_async
>= 0) {
275 close(oclient
->fd_async
);
278 /* Free client structure */
279 XFREE(MTYPE_OSPF_APICLIENT
, oclient
);
283 /* -----------------------------------------------------------
284 * Following are functions to send a request to OSPFd
285 * -----------------------------------------------------------
288 /* Send synchronous request, wait for reply */
289 static int ospf_apiclient_send_request(struct ospf_apiclient
*oclient
,
293 struct msg_reply
*msgreply
;
296 /* NB: Given "msg" is freed inside this function. */
298 /* Remember the sequence number of the request */
299 reqseq
= ntohl(msg
->hdr
.msgseq
);
301 /* Write message to OSPFd */
302 rc
= msg_write(oclient
->fd_sync
, msg
);
309 /* Wait for reply */ /* NB: New "msg" is allocated by "msg_read()". */
310 msg
= msg_read(oclient
->fd_sync
);
314 assert(msg
->hdr
.msgtype
== MSG_REPLY
);
315 assert(ntohl(msg
->hdr
.msgseq
) == reqseq
);
317 msgreply
= (struct msg_reply
*)STREAM_DATA(msg
->s
);
318 rc
= msgreply
->errcode
;
325 /* -----------------------------------------------------------
327 * -----------------------------------------------------------
330 static uint32_t ospf_apiclient_get_seqnr(void)
332 static uint32_t seqnr
= MIN_SEQ
;
336 /* Increment sequence number */
337 if (seqnr
< MAX_SEQ
) {
345 /* -----------------------------------------------------------
346 * API to access OSPF daemon by client applications.
347 * -----------------------------------------------------------
351 * Synchronous request to register opaque type.
353 int ospf_apiclient_register_opaque_type(struct ospf_apiclient
*cl
,
354 uint8_t ltype
, uint8_t otype
)
359 /* just put 1 as a sequence number. */
360 msg
= new_msg_register_opaque_type(ospf_apiclient_get_seqnr(), ltype
,
363 fprintf(stderr
, "new_msg_register_opaque_type failed\n");
367 rc
= ospf_apiclient_send_request(cl
, msg
);
372 * Synchronous request to synchronize with OSPF's LSDB.
373 * Two steps required: register_event in order to get
374 * dynamic updates and LSDB_Sync.
376 int ospf_apiclient_sync_lsdb(struct ospf_apiclient
*oclient
)
380 struct lsa_filter_type filter
;
382 filter
.typemask
= 0xFFFF; /* all LSAs */
383 filter
.origin
= ANY_ORIGIN
;
384 filter
.num_areas
= 0; /* all Areas. */
386 msg
= new_msg_register_event(ospf_apiclient_get_seqnr(), &filter
);
388 fprintf(stderr
, "new_msg_register_event failed\n");
391 rc
= ospf_apiclient_send_request(oclient
, msg
);
396 msg
= new_msg_sync_lsdb(ospf_apiclient_get_seqnr(), &filter
);
398 fprintf(stderr
, "new_msg_sync_lsdb failed\n");
401 rc
= ospf_apiclient_send_request(oclient
, msg
);
408 * Synchronous request to originate or update an LSA.
411 int ospf_apiclient_lsa_originate(struct ospf_apiclient
*oclient
,
412 struct in_addr ifaddr
, struct in_addr area_id
,
413 uint8_t lsa_type
, uint8_t opaque_type
,
414 uint32_t opaque_id
, void *opaquedata
,
419 uint8_t buf
[OSPF_MAX_LSA_SIZE
];
420 struct lsa_header
*lsah
;
423 /* Validate opaque LSA length */
424 if ((size_t)opaquelen
> sizeof(buf
) - sizeof(struct lsa_header
)) {
425 fprintf(stderr
, "opaquelen(%d) is larger than buf size %zu\n",
426 opaquelen
, sizeof(buf
));
427 return OSPF_API_NOMEMORY
;
430 /* We can only originate opaque LSAs */
431 if (!IS_OPAQUE_LSA(lsa_type
)) {
432 fprintf(stderr
, "Cannot originate non-opaque LSA type %d\n",
434 return OSPF_API_ILLEGALLSATYPE
;
437 /* Make a new LSA from parameters */
438 lsah
= (struct lsa_header
*)buf
;
441 lsah
->type
= lsa_type
;
443 tmp
= SET_OPAQUE_LSID(opaque_type
, opaque_id
);
444 lsah
->id
.s_addr
= htonl(tmp
);
445 lsah
->adv_router
.s_addr
= INADDR_ANY
;
448 lsah
->length
= htons(sizeof(struct lsa_header
) + opaquelen
);
450 memcpy(((uint8_t *)lsah
) + sizeof(struct lsa_header
), opaquedata
,
453 msg
= new_msg_originate_request(ospf_apiclient_get_seqnr(), ifaddr
,
456 fprintf(stderr
, "new_msg_originate_request failed\n");
457 return OSPF_API_NOMEMORY
;
460 rc
= ospf_apiclient_send_request(oclient
, msg
);
464 int ospf_apiclient_lsa_delete(struct ospf_apiclient
*oclient
,
465 struct in_addr addr
, uint8_t lsa_type
,
466 uint8_t opaque_type
, uint32_t opaque_id
,
472 /* Only opaque LSA can be deleted */
473 if (!IS_OPAQUE_LSA(lsa_type
)) {
474 fprintf(stderr
, "Cannot delete non-opaque LSA type %d\n",
476 return OSPF_API_ILLEGALLSATYPE
;
479 /* opaque_id is in host byte order and will be converted
480 * to network byte order by new_msg_delete_request */
481 msg
= new_msg_delete_request(ospf_apiclient_get_seqnr(), addr
, lsa_type
,
482 opaque_type
, opaque_id
, flags
);
484 rc
= ospf_apiclient_send_request(oclient
, msg
);
488 /* -----------------------------------------------------------
489 * Following are handlers for messages from OSPF daemon
490 * -----------------------------------------------------------
493 static void ospf_apiclient_handle_ready(struct ospf_apiclient
*oclient
,
496 struct msg_ready_notify
*r
;
497 r
= (struct msg_ready_notify
*)STREAM_DATA(msg
->s
);
499 /* Invoke registered callback function. */
500 if (oclient
->ready_notify
) {
501 (oclient
->ready_notify
)(r
->lsa_type
, r
->opaque_type
, r
->addr
);
505 static void ospf_apiclient_handle_new_if(struct ospf_apiclient
*oclient
,
508 struct msg_new_if
*n
;
509 n
= (struct msg_new_if
*)STREAM_DATA(msg
->s
);
511 /* Invoke registered callback function. */
512 if (oclient
->new_if
) {
513 (oclient
->new_if
)(n
->ifaddr
, n
->area_id
);
517 static void ospf_apiclient_handle_del_if(struct ospf_apiclient
*oclient
,
520 struct msg_del_if
*d
;
521 d
= (struct msg_del_if
*)STREAM_DATA(msg
->s
);
523 /* Invoke registered callback function. */
524 if (oclient
->del_if
) {
525 (oclient
->del_if
)(d
->ifaddr
);
529 static void ospf_apiclient_handle_ism_change(struct ospf_apiclient
*oclient
,
532 struct msg_ism_change
*m
;
533 m
= (struct msg_ism_change
*)STREAM_DATA(msg
->s
);
535 /* Invoke registered callback function. */
536 if (oclient
->ism_change
) {
537 (oclient
->ism_change
)(m
->ifaddr
, m
->area_id
, m
->status
);
541 static void ospf_apiclient_handle_nsm_change(struct ospf_apiclient
*oclient
,
544 struct msg_nsm_change
*m
;
545 m
= (struct msg_nsm_change
*)STREAM_DATA(msg
->s
);
547 /* Invoke registered callback function. */
548 if (oclient
->nsm_change
) {
549 (oclient
->nsm_change
)(m
->ifaddr
, m
->nbraddr
, m
->router_id
,
554 static void ospf_apiclient_handle_lsa_update(struct ospf_apiclient
*oclient
,
557 struct msg_lsa_change_notify
*cn
;
558 struct lsa_header
*lsa
;
562 cn
= (struct msg_lsa_change_notify
*)STREAM_DATA(msg
->s
);
564 /* Extract LSA from message */
565 lsalen
= ntohs(cn
->data
.length
);
566 if (lsalen
> OSPF_MAX_LSA_SIZE
) {
569 "%s: message received size: %d is greater than a LSA size: %d",
570 __func__
, lsalen
, OSPF_MAX_LSA_SIZE
);
574 p
= XMALLOC(MTYPE_OSPF_APICLIENT
, lsalen
);
576 memcpy(p
, &(cn
->data
), lsalen
);
579 /* Invoke registered update callback function */
580 if (oclient
->update_notify
) {
581 (oclient
->update_notify
)(cn
->ifaddr
, cn
->area_id
,
582 cn
->is_self_originated
, lsa
);
585 /* free memory allocated by ospf apiclient library */
586 XFREE(MTYPE_OSPF_APICLIENT
, p
);
589 static void ospf_apiclient_handle_lsa_delete(struct ospf_apiclient
*oclient
,
592 struct msg_lsa_change_notify
*cn
;
593 struct lsa_header
*lsa
;
597 cn
= (struct msg_lsa_change_notify
*)STREAM_DATA(msg
->s
);
599 /* Extract LSA from message */
600 lsalen
= ntohs(cn
->data
.length
);
601 if (lsalen
> OSPF_MAX_LSA_SIZE
) {
604 "%s: message received size: %d is greater than a LSA size: %d",
605 __func__
, lsalen
, OSPF_MAX_LSA_SIZE
);
609 p
= XMALLOC(MTYPE_OSPF_APICLIENT
, lsalen
);
611 memcpy(p
, &(cn
->data
), lsalen
);
614 /* Invoke registered update callback function */
615 if (oclient
->delete_notify
) {
616 (oclient
->delete_notify
)(cn
->ifaddr
, cn
->area_id
,
617 cn
->is_self_originated
, lsa
);
620 /* free memory allocated by ospf apiclient library */
621 XFREE(MTYPE_OSPF_APICLIENT
, p
);
624 static void ospf_apiclient_msghandle(struct ospf_apiclient
*oclient
,
627 /* Call message handler function. */
628 switch (msg
->hdr
.msgtype
) {
629 case MSG_READY_NOTIFY
:
630 ospf_apiclient_handle_ready(oclient
, msg
);
633 ospf_apiclient_handle_new_if(oclient
, msg
);
636 ospf_apiclient_handle_del_if(oclient
, msg
);
639 ospf_apiclient_handle_ism_change(oclient
, msg
);
642 ospf_apiclient_handle_nsm_change(oclient
, msg
);
644 case MSG_LSA_UPDATE_NOTIFY
:
645 ospf_apiclient_handle_lsa_update(oclient
, msg
);
647 case MSG_LSA_DELETE_NOTIFY
:
648 ospf_apiclient_handle_lsa_delete(oclient
, msg
);
652 "ospf_apiclient_read: Unknown message type: %d\n",
658 /* -----------------------------------------------------------
659 * Callback handler registration
660 * -----------------------------------------------------------
663 void ospf_apiclient_register_callback(
664 struct ospf_apiclient
*oclient
,
665 void (*ready_notify
)(uint8_t lsa_type
, uint8_t opaque_type
,
666 struct in_addr addr
),
667 void (*new_if
)(struct in_addr ifaddr
, struct in_addr area_id
),
668 void (*del_if
)(struct in_addr ifaddr
),
669 void (*ism_change
)(struct in_addr ifaddr
, struct in_addr area_id
,
671 void (*nsm_change
)(struct in_addr ifaddr
, struct in_addr nbraddr
,
672 struct in_addr router_id
, uint8_t status
),
673 void (*update_notify
)(struct in_addr ifaddr
, struct in_addr area_id
,
674 uint8_t self_origin
, struct lsa_header
*lsa
),
675 void (*delete_notify
)(struct in_addr ifaddr
, struct in_addr area_id
,
676 uint8_t self_origin
, struct lsa_header
*lsa
))
679 assert(update_notify
);
681 /* Register callback function */
682 oclient
->ready_notify
= ready_notify
;
683 oclient
->new_if
= new_if
;
684 oclient
->del_if
= del_if
;
685 oclient
->ism_change
= ism_change
;
686 oclient
->nsm_change
= nsm_change
;
687 oclient
->update_notify
= update_notify
;
688 oclient
->delete_notify
= delete_notify
;
691 /* -----------------------------------------------------------
692 * Asynchronous message handling
693 * -----------------------------------------------------------
696 int ospf_apiclient_handle_async(struct ospf_apiclient
*oclient
)
701 msg
= msg_read(oclient
->fd_async
);
704 /* Connection broke down */
709 ospf_apiclient_msghandle(oclient
, msg
);
711 /* Don't forget to free this message */