]> git.proxmox.com Git - mirror_frr.git/blob - ospfclient/ospf_apiclient.c
Merge pull request #2829 from donaldsharp/more_upstream
[mirror_frr.git] / ospfclient / ospf_apiclient.c
1 /*
2 * Client side of OSPF API.
3 * Copyright (C) 2001, 2002, 2003 Ralph Keller
4 *
5 * This file is part of GNU Zebra.
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include <zebra.h>
23
24 #include <lib/version.h>
25 #include "getopt.h"
26 #include "thread.h"
27 #include "prefix.h"
28 #include "linklist.h"
29 #include "if.h"
30 #include "vector.h"
31 #include "vty.h"
32 #include "command.h"
33 #include "filter.h"
34 #include "stream.h"
35 #include "log.h"
36 #include "memory.h"
37
38 /* work around gcc bug 69981, disable MTYPEs in libospf */
39 #define _QUAGGA_OSPF_MEMORY_H
40
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"
51
52 #include "ospf_apiclient.h"
53
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"
57
58 DEFINE_MGROUP(OSPFCLIENT, "libospfapiclient")
59 DEFINE_MTYPE_STATIC(OSPFCLIENT, OSPF_APICLIENT, "OSPF-API client")
60
61 /* Backlog for listen */
62 #define BACKLOG 5
63
64 /* -----------------------------------------------------------
65 * Forward declarations
66 * -----------------------------------------------------------
67 */
68
69 void ospf_apiclient_handle_reply(struct ospf_apiclient *oclient,
70 struct msg *msg);
71 void ospf_apiclient_handle_update_notify(struct ospf_apiclient *oclient,
72 struct msg *msg);
73 void ospf_apiclient_handle_delete_notify(struct ospf_apiclient *oclient,
74 struct msg *msg);
75
76 /* -----------------------------------------------------------
77 * Initialization
78 * -----------------------------------------------------------
79 */
80
81 static unsigned short ospf_apiclient_getport(void)
82 {
83 struct servent *sp = getservbyname("ospfapi", "tcp");
84
85 return sp ? ntohs(sp->s_port) : OSPF_API_SYNC_PORT;
86 }
87
88 /* -----------------------------------------------------------
89 * Followings are functions for connection management
90 * -----------------------------------------------------------
91 */
92
93 struct ospf_apiclient *ospf_apiclient_connect(char *host, int syncport)
94 {
95 struct sockaddr_in myaddr_sync;
96 struct sockaddr_in myaddr_async;
97 struct sockaddr_in peeraddr;
98 struct hostent *hp;
99 struct ospf_apiclient *new;
100 int size = 0;
101 unsigned int peeraddrlen;
102 int async_server_sock;
103 int fd1, fd2;
104 int ret;
105 int on = 1;
106
107 /* There are two connections between the client and the server.
108 First the client opens a connection for synchronous requests/replies
109 to the server. The server will accept this connection and
110 as a reaction open a reverse connection channel for
111 asynchronous messages. */
112
113 async_server_sock = socket(AF_INET, SOCK_STREAM, 0);
114 if (async_server_sock < 0) {
115 fprintf(stderr,
116 "ospf_apiclient_connect: creating async socket failed\n");
117 return NULL;
118 }
119
120 /* Prepare socket for asynchronous messages */
121 /* Initialize async address structure */
122 memset(&myaddr_async, 0, sizeof(struct sockaddr_in));
123 myaddr_async.sin_family = AF_INET;
124 myaddr_async.sin_addr.s_addr = htonl(INADDR_ANY);
125 myaddr_async.sin_port = htons(syncport + 1);
126 size = sizeof(struct sockaddr_in);
127 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
128 myaddr_async.sin_len = size;
129 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
130
131 /* This is a server socket, reuse addr and port */
132 ret = setsockopt(async_server_sock, SOL_SOCKET, SO_REUSEADDR,
133 (void *)&on, sizeof(on));
134 if (ret < 0) {
135 fprintf(stderr,
136 "ospf_apiclient_connect: SO_REUSEADDR failed\n");
137 close(async_server_sock);
138 return NULL;
139 }
140
141 #ifdef SO_REUSEPORT
142 ret = setsockopt(async_server_sock, SOL_SOCKET, SO_REUSEPORT,
143 (void *)&on, sizeof(on));
144 if (ret < 0) {
145 fprintf(stderr,
146 "ospf_apiclient_connect: SO_REUSEPORT failed\n");
147 close(async_server_sock);
148 return NULL;
149 }
150 #endif /* SO_REUSEPORT */
151
152 /* Bind socket to address structure */
153 ret = bind(async_server_sock, (struct sockaddr *)&myaddr_async, size);
154 if (ret < 0) {
155 fprintf(stderr,
156 "ospf_apiclient_connect: bind async socket failed\n");
157 close(async_server_sock);
158 return NULL;
159 }
160
161 /* Wait for reverse channel connection establishment from server */
162 ret = listen(async_server_sock, BACKLOG);
163 if (ret < 0) {
164 fprintf(stderr, "ospf_apiclient_connect: listen: %s\n",
165 safe_strerror(errno));
166 close(async_server_sock);
167 return NULL;
168 }
169
170 /* Make connection for synchronous requests and connect to server */
171 /* Resolve address of server */
172 hp = gethostbyname(host);
173 if (!hp) {
174 fprintf(stderr, "ospf_apiclient_connect: no such host %s\n",
175 host);
176 close(async_server_sock);
177 return NULL;
178 }
179
180 fd1 = socket(AF_INET, SOCK_STREAM, 0);
181 if (fd1 < 0) {
182 close(async_server_sock);
183 fprintf(stderr,
184 "ospf_apiclient_connect: creating sync socket failed\n");
185 return NULL;
186 }
187
188
189 /* Reuse addr and port */
190 ret = setsockopt(fd1, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
191 sizeof(on));
192 if (ret < 0) {
193 fprintf(stderr,
194 "ospf_apiclient_connect: SO_REUSEADDR failed\n");
195 close(fd1);
196 close(async_server_sock);
197 return NULL;
198 }
199
200 #ifdef SO_REUSEPORT
201 ret = setsockopt(fd1, SOL_SOCKET, SO_REUSEPORT, (void *)&on,
202 sizeof(on));
203 if (ret < 0) {
204 fprintf(stderr,
205 "ospf_apiclient_connect: SO_REUSEPORT failed\n");
206 close(fd1);
207 close(async_server_sock);
208 return NULL;
209 }
210 #endif /* SO_REUSEPORT */
211
212
213 /* Bind sync socket to address structure. This is needed since we
214 want the sync port number on a fixed port number. The reverse
215 async channel will be at this port+1 */
216
217 memset(&myaddr_sync, 0, sizeof(struct sockaddr_in));
218 myaddr_sync.sin_family = AF_INET;
219 myaddr_sync.sin_port = htons(syncport);
220 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
221 myaddr_sync.sin_len = sizeof(struct sockaddr_in);
222 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
223
224 ret = bind(fd1, (struct sockaddr *)&myaddr_sync, size);
225 if (ret < 0) {
226 fprintf(stderr,
227 "ospf_apiclient_connect: bind sync socket failed\n");
228 close(fd1);
229 close(async_server_sock);
230 return NULL;
231 }
232
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 */
240
241 /* Now establish synchronous channel with OSPF daemon */
242 ret = connect(fd1, (struct sockaddr *)&myaddr_sync,
243 sizeof(struct sockaddr_in));
244 if (ret < 0) {
245 fprintf(stderr,
246 "ospf_apiclient_connect: sync connect failed\n");
247 close(async_server_sock);
248 close(fd1);
249 return NULL;
250 }
251
252 /* Accept reverse connection */
253 peeraddrlen = sizeof(struct sockaddr_in);
254 memset(&peeraddr, 0, peeraddrlen);
255
256 fd2 = accept(async_server_sock, (struct sockaddr *)&peeraddr,
257 &peeraddrlen);
258 if (fd2 < 0) {
259 fprintf(stderr,
260 "ospf_apiclient_connect: accept async failed\n");
261 close(async_server_sock);
262 close(fd1);
263 close(fd2);
264 return NULL;
265 }
266
267 /* Server socket is not needed anymore since we are not accepting more
268 connections */
269 close(async_server_sock);
270
271 /* Create new client-side instance */
272 new = XCALLOC(MTYPE_OSPF_APICLIENT, sizeof(struct ospf_apiclient));
273
274 /* Initialize socket descriptors for sync and async channels */
275 new->fd_sync = fd1;
276 new->fd_async = fd2;
277
278 return new;
279 }
280
281 int ospf_apiclient_close(struct ospf_apiclient *oclient)
282 {
283
284 if (oclient->fd_sync >= 0) {
285 close(oclient->fd_sync);
286 }
287
288 if (oclient->fd_async >= 0) {
289 close(oclient->fd_async);
290 }
291
292 /* Free client structure */
293 XFREE(MTYPE_OSPF_APICLIENT, oclient);
294 return 0;
295 }
296
297 /* -----------------------------------------------------------
298 * Followings are functions to send a request to OSPFd
299 * -----------------------------------------------------------
300 */
301
302 /* Send synchronous request, wait for reply */
303 static int ospf_apiclient_send_request(struct ospf_apiclient *oclient,
304 struct msg *msg)
305 {
306 uint32_t reqseq;
307 struct msg_reply *msgreply;
308 int rc;
309
310 /* NB: Given "msg" is freed inside this function. */
311
312 /* Remember the sequence number of the request */
313 reqseq = ntohl(msg->hdr.msgseq);
314
315 /* Write message to OSPFd */
316 rc = msg_write(oclient->fd_sync, msg);
317 msg_free(msg);
318
319 if (rc < 0) {
320 return -1;
321 }
322
323 /* Wait for reply */ /* NB: New "msg" is allocated by "msg_read()". */
324 msg = msg_read(oclient->fd_sync);
325 if (!msg)
326 return -1;
327
328 assert(msg->hdr.msgtype == MSG_REPLY);
329 assert(ntohl(msg->hdr.msgseq) == reqseq);
330
331 msgreply = (struct msg_reply *)STREAM_DATA(msg->s);
332 rc = msgreply->errcode;
333 msg_free(msg);
334
335 return rc;
336 }
337
338
339 /* -----------------------------------------------------------
340 * Helper functions
341 * -----------------------------------------------------------
342 */
343
344 static uint32_t ospf_apiclient_get_seqnr(void)
345 {
346 static uint32_t seqnr = MIN_SEQ;
347 uint32_t tmp;
348
349 tmp = seqnr;
350 /* Increment sequence number */
351 if (seqnr < MAX_SEQ) {
352 seqnr++;
353 } else {
354 seqnr = MIN_SEQ;
355 }
356 return tmp;
357 }
358
359 /* -----------------------------------------------------------
360 * API to access OSPF daemon by client applications.
361 * -----------------------------------------------------------
362 */
363
364 /*
365 * Synchronous request to register opaque type.
366 */
367 int ospf_apiclient_register_opaque_type(struct ospf_apiclient *cl,
368 uint8_t ltype, uint8_t otype)
369 {
370 struct msg *msg;
371 int rc;
372
373 /* just put 1 as a sequence number. */
374 msg = new_msg_register_opaque_type(ospf_apiclient_get_seqnr(), ltype,
375 otype);
376 if (!msg) {
377 fprintf(stderr, "new_msg_register_opaque_type failed\n");
378 return -1;
379 }
380
381 rc = ospf_apiclient_send_request(cl, msg);
382 return rc;
383 }
384
385 /*
386 * Synchronous request to synchronize with OSPF's LSDB.
387 * Two steps required: register_event in order to get
388 * dynamic updates and LSDB_Sync.
389 */
390 int ospf_apiclient_sync_lsdb(struct ospf_apiclient *oclient)
391 {
392 struct msg *msg;
393 int rc;
394 struct lsa_filter_type filter;
395
396 filter.typemask = 0xFFFF; /* all LSAs */
397 filter.origin = ANY_ORIGIN;
398 filter.num_areas = 0; /* all Areas. */
399
400 msg = new_msg_register_event(ospf_apiclient_get_seqnr(), &filter);
401 if (!msg) {
402 fprintf(stderr, "new_msg_register_event failed\n");
403 return -1;
404 }
405 rc = ospf_apiclient_send_request(oclient, msg);
406
407 if (rc != 0)
408 goto out;
409
410 msg = new_msg_sync_lsdb(ospf_apiclient_get_seqnr(), &filter);
411 if (!msg) {
412 fprintf(stderr, "new_msg_sync_lsdb failed\n");
413 return -1;
414 }
415 rc = ospf_apiclient_send_request(oclient, msg);
416
417 out:
418 return rc;
419 }
420
421 /*
422 * Synchronous request to originate or update an LSA.
423 */
424
425 int ospf_apiclient_lsa_originate(struct ospf_apiclient *oclient,
426 struct in_addr ifaddr, struct in_addr area_id,
427 uint8_t lsa_type, uint8_t opaque_type,
428 uint32_t opaque_id, void *opaquedata,
429 int opaquelen)
430 {
431 struct msg *msg;
432 int rc;
433 uint8_t buf[OSPF_MAX_LSA_SIZE];
434 struct lsa_header *lsah;
435 uint32_t tmp;
436
437
438 /* We can only originate opaque LSAs */
439 if (!IS_OPAQUE_LSA(lsa_type)) {
440 fprintf(stderr, "Cannot originate non-opaque LSA type %d\n",
441 lsa_type);
442 return OSPF_API_ILLEGALLSATYPE;
443 }
444
445 /* Make a new LSA from parameters */
446 lsah = (struct lsa_header *)buf;
447 lsah->ls_age = 0;
448 lsah->options = 0;
449 lsah->type = lsa_type;
450
451 tmp = SET_OPAQUE_LSID(opaque_type, opaque_id);
452 lsah->id.s_addr = htonl(tmp);
453 lsah->adv_router.s_addr = 0;
454 lsah->ls_seqnum = 0;
455 lsah->checksum = 0;
456 lsah->length = htons(sizeof(struct lsa_header) + opaquelen);
457
458 memcpy(((uint8_t *)lsah) + sizeof(struct lsa_header), opaquedata,
459 opaquelen);
460
461 msg = new_msg_originate_request(ospf_apiclient_get_seqnr(), ifaddr,
462 area_id, lsah);
463 if (!msg) {
464 fprintf(stderr, "new_msg_originate_request failed\n");
465 return OSPF_API_NOMEMORY;
466 }
467
468 rc = ospf_apiclient_send_request(oclient, msg);
469 return rc;
470 }
471
472 int ospf_apiclient_lsa_delete(struct ospf_apiclient *oclient,
473 struct in_addr area_id, uint8_t lsa_type,
474 uint8_t opaque_type, uint32_t opaque_id)
475 {
476 struct msg *msg;
477 int rc;
478
479 /* Only opaque LSA can be deleted */
480 if (!IS_OPAQUE_LSA(lsa_type)) {
481 fprintf(stderr, "Cannot delete non-opaque LSA type %d\n",
482 lsa_type);
483 return OSPF_API_ILLEGALLSATYPE;
484 }
485
486 /* opaque_id is in host byte order and will be converted
487 * to network byte order by new_msg_delete_request */
488 msg = new_msg_delete_request(ospf_apiclient_get_seqnr(), area_id,
489 lsa_type, opaque_type, opaque_id);
490
491 rc = ospf_apiclient_send_request(oclient, msg);
492 return rc;
493 }
494
495 /* -----------------------------------------------------------
496 * Followings are handlers for messages from OSPF daemon
497 * -----------------------------------------------------------
498 */
499
500 static void ospf_apiclient_handle_ready(struct ospf_apiclient *oclient,
501 struct msg *msg)
502 {
503 struct msg_ready_notify *r;
504 r = (struct msg_ready_notify *)STREAM_DATA(msg->s);
505
506 /* Invoke registered callback function. */
507 if (oclient->ready_notify) {
508 (oclient->ready_notify)(r->lsa_type, r->opaque_type, r->addr);
509 }
510 }
511
512 static void ospf_apiclient_handle_new_if(struct ospf_apiclient *oclient,
513 struct msg *msg)
514 {
515 struct msg_new_if *n;
516 n = (struct msg_new_if *)STREAM_DATA(msg->s);
517
518 /* Invoke registered callback function. */
519 if (oclient->new_if) {
520 (oclient->new_if)(n->ifaddr, n->area_id);
521 }
522 }
523
524 static void ospf_apiclient_handle_del_if(struct ospf_apiclient *oclient,
525 struct msg *msg)
526 {
527 struct msg_del_if *d;
528 d = (struct msg_del_if *)STREAM_DATA(msg->s);
529
530 /* Invoke registered callback function. */
531 if (oclient->del_if) {
532 (oclient->del_if)(d->ifaddr);
533 }
534 }
535
536 static void ospf_apiclient_handle_ism_change(struct ospf_apiclient *oclient,
537 struct msg *msg)
538 {
539 struct msg_ism_change *m;
540 m = (struct msg_ism_change *)STREAM_DATA(msg->s);
541
542 /* Invoke registered callback function. */
543 if (oclient->ism_change) {
544 (oclient->ism_change)(m->ifaddr, m->area_id, m->status);
545 }
546 }
547
548 static void ospf_apiclient_handle_nsm_change(struct ospf_apiclient *oclient,
549 struct msg *msg)
550 {
551 struct msg_nsm_change *m;
552 m = (struct msg_nsm_change *)STREAM_DATA(msg->s);
553
554 /* Invoke registered callback function. */
555 if (oclient->nsm_change) {
556 (oclient->nsm_change)(m->ifaddr, m->nbraddr, m->router_id,
557 m->status);
558 }
559 }
560
561 static void ospf_apiclient_handle_lsa_update(struct ospf_apiclient *oclient,
562 struct msg *msg)
563 {
564 struct msg_lsa_change_notify *cn;
565 struct lsa_header *lsa;
566 int lsalen;
567
568 cn = (struct msg_lsa_change_notify *)STREAM_DATA(msg->s);
569
570 /* Extract LSA from message */
571 lsalen = ntohs(cn->data.length);
572 lsa = XMALLOC(MTYPE_OSPF_APICLIENT, lsalen);
573
574 memcpy(lsa, &(cn->data), lsalen);
575
576 /* Invoke registered update callback function */
577 if (oclient->update_notify) {
578 (oclient->update_notify)(cn->ifaddr, cn->area_id,
579 cn->is_self_originated, lsa);
580 }
581
582 /* free memory allocated by ospf apiclient library */
583 XFREE(MTYPE_OSPF_APICLIENT, lsa);
584 }
585
586 static void ospf_apiclient_handle_lsa_delete(struct ospf_apiclient *oclient,
587 struct msg *msg)
588 {
589 struct msg_lsa_change_notify *cn;
590 struct lsa_header *lsa;
591 int lsalen;
592
593 cn = (struct msg_lsa_change_notify *)STREAM_DATA(msg->s);
594
595 /* Extract LSA from message */
596 lsalen = ntohs(cn->data.length);
597 lsa = XMALLOC(MTYPE_OSPF_APICLIENT, lsalen);
598
599 memcpy(lsa, &(cn->data), lsalen);
600
601 /* Invoke registered update callback function */
602 if (oclient->delete_notify) {
603 (oclient->delete_notify)(cn->ifaddr, cn->area_id,
604 cn->is_self_originated, lsa);
605 }
606
607 /* free memory allocated by ospf apiclient library */
608 XFREE(MTYPE_OSPF_APICLIENT, lsa);
609 }
610
611 static void ospf_apiclient_msghandle(struct ospf_apiclient *oclient,
612 struct msg *msg)
613 {
614 /* Call message handler function. */
615 switch (msg->hdr.msgtype) {
616 case MSG_READY_NOTIFY:
617 ospf_apiclient_handle_ready(oclient, msg);
618 break;
619 case MSG_NEW_IF:
620 ospf_apiclient_handle_new_if(oclient, msg);
621 break;
622 case MSG_DEL_IF:
623 ospf_apiclient_handle_del_if(oclient, msg);
624 break;
625 case MSG_ISM_CHANGE:
626 ospf_apiclient_handle_ism_change(oclient, msg);
627 break;
628 case MSG_NSM_CHANGE:
629 ospf_apiclient_handle_nsm_change(oclient, msg);
630 break;
631 case MSG_LSA_UPDATE_NOTIFY:
632 ospf_apiclient_handle_lsa_update(oclient, msg);
633 break;
634 case MSG_LSA_DELETE_NOTIFY:
635 ospf_apiclient_handle_lsa_delete(oclient, msg);
636 break;
637 default:
638 fprintf(stderr,
639 "ospf_apiclient_read: Unknown message type: %d\n",
640 msg->hdr.msgtype);
641 break;
642 }
643 }
644
645 /* -----------------------------------------------------------
646 * Callback handler registration
647 * -----------------------------------------------------------
648 */
649
650 void ospf_apiclient_register_callback(
651 struct ospf_apiclient *oclient,
652 void (*ready_notify)(uint8_t lsa_type, uint8_t opaque_type,
653 struct in_addr addr),
654 void (*new_if)(struct in_addr ifaddr, struct in_addr area_id),
655 void (*del_if)(struct in_addr ifaddr),
656 void (*ism_change)(struct in_addr ifaddr, struct in_addr area_id,
657 uint8_t status),
658 void (*nsm_change)(struct in_addr ifaddr, struct in_addr nbraddr,
659 struct in_addr router_id, uint8_t status),
660 void (*update_notify)(struct in_addr ifaddr, struct in_addr area_id,
661 uint8_t self_origin, struct lsa_header *lsa),
662 void (*delete_notify)(struct in_addr ifaddr, struct in_addr area_id,
663 uint8_t self_origin, struct lsa_header *lsa))
664 {
665 assert(oclient);
666 assert(update_notify);
667
668 /* Register callback function */
669 oclient->ready_notify = ready_notify;
670 oclient->new_if = new_if;
671 oclient->del_if = del_if;
672 oclient->ism_change = ism_change;
673 oclient->nsm_change = nsm_change;
674 oclient->update_notify = update_notify;
675 oclient->delete_notify = delete_notify;
676 }
677
678 /* -----------------------------------------------------------
679 * Asynchronous message handling
680 * -----------------------------------------------------------
681 */
682
683 int ospf_apiclient_handle_async(struct ospf_apiclient *oclient)
684 {
685 struct msg *msg;
686
687 /* Get a message */
688 msg = msg_read(oclient->fd_async);
689
690 if (!msg) {
691 /* Connection broke down */
692 return -1;
693 }
694
695 /* Handle message */
696 ospf_apiclient_msghandle(oclient, msg);
697
698 /* Don't forget to free this message */
699 msg_free(msg);
700
701 return 0;
702 }