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