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