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