]>
Commit | Line | Data |
---|---|---|
8429abe0 RW |
1 | /* $OpenBSD$ */ |
2 | ||
3 | /* | |
4 | * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org> | |
5 | * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> | |
6 | * Copyright (c) 2004, 2008 Esben Norby <norby@openbsd.org> | |
7 | * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> | |
8 | * | |
9 | * Permission to use, copy, modify, and distribute this software for any | |
10 | * purpose with or without fee is hereby granted, provided that the above | |
11 | * copyright notice and this permission notice appear in all copies. | |
12 | * | |
13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
20 | */ | |
21 | ||
22 | #include <sys/types.h> | |
23 | #include <stdlib.h> | |
24 | #include <signal.h> | |
25 | #include <string.h> | |
26 | #include <pwd.h> | |
27 | #include <unistd.h> | |
28 | #include <arpa/inet.h> | |
29 | #include <errno.h> | |
30 | ||
31 | #include "ldpd.h" | |
32 | #include "ldpe.h" | |
33 | #include "lde.h" | |
34 | #include "control.h" | |
35 | #include "log.h" | |
36 | ||
37 | static void ldpe_sig_handler(int, short, void *); | |
38 | static __dead void ldpe_shutdown(void); | |
39 | static void ldpe_dispatch_main(int, short, void *); | |
40 | static void ldpe_dispatch_lde(int, short, void *); | |
41 | static void ldpe_dispatch_pfkey(int, short, void *); | |
42 | static void ldpe_setup_sockets(int, int, int, int); | |
43 | static void ldpe_close_sockets(int); | |
44 | static void ldpe_iface_af_ctl(struct ctl_conn *, int, unsigned int); | |
45 | ||
46 | struct ldpd_conf *leconf; | |
47 | struct ldpd_sysdep sysdep; | |
48 | ||
49 | static struct imsgev *iev_main; | |
50 | static struct imsgev *iev_lde; | |
51 | static struct event pfkey_ev; | |
52 | ||
53 | /* ARGSUSED */ | |
54 | static void | |
55 | ldpe_sig_handler(int sig, short event, void *bula) | |
56 | { | |
57 | switch (sig) { | |
58 | case SIGINT: | |
59 | case SIGTERM: | |
60 | ldpe_shutdown(); | |
61 | /* NOTREACHED */ | |
62 | default: | |
63 | fatalx("unexpected signal"); | |
64 | } | |
65 | } | |
66 | ||
67 | /* label distribution protocol engine */ | |
68 | void | |
69 | ldpe(int debug, int verbose) | |
70 | { | |
71 | struct passwd *pw; | |
72 | struct event ev_sigint, ev_sigterm; | |
73 | ||
74 | leconf = config_new_empty(); | |
75 | ||
76 | log_init(debug); | |
77 | log_verbose(verbose); | |
78 | ||
79 | setproctitle("ldp engine"); | |
80 | ldpd_process = PROC_LDP_ENGINE; | |
81 | ||
82 | /* create ldpd control socket outside chroot */ | |
83 | if (control_init() == -1) | |
84 | fatalx("control socket setup failed"); | |
85 | ||
86 | LIST_INIT(&global.addr_list); | |
87 | LIST_INIT(&global.adj_list); | |
88 | TAILQ_INIT(&global.pending_conns); | |
89 | if (inet_pton(AF_INET, AllRouters_v4, &global.mcast_addr_v4) != 1) | |
90 | fatal("inet_pton"); | |
91 | if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1) | |
92 | fatal("inet_pton"); | |
93 | global.pfkeysock = pfkey_init(); | |
94 | ||
95 | if ((pw = getpwnam(LDPD_USER)) == NULL) | |
96 | fatal("getpwnam"); | |
97 | ||
98 | if (chroot(pw->pw_dir) == -1) | |
99 | fatal("chroot"); | |
100 | if (chdir("/") == -1) | |
101 | fatal("chdir(\"/\")"); | |
102 | ||
103 | if (setgroups(1, &pw->pw_gid) || | |
104 | setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || | |
105 | setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) | |
106 | fatal("can't drop privileges"); | |
107 | ||
108 | if (pledge("stdio cpath inet mcast recvfd", NULL) == -1) | |
109 | fatal("pledge"); | |
110 | ||
111 | event_init(); | |
112 | accept_init(); | |
113 | ||
114 | /* setup signal handler */ | |
115 | signal_set(&ev_sigint, SIGINT, ldpe_sig_handler, NULL); | |
116 | signal_set(&ev_sigterm, SIGTERM, ldpe_sig_handler, NULL); | |
117 | signal_add(&ev_sigint, NULL); | |
118 | signal_add(&ev_sigterm, NULL); | |
119 | signal(SIGPIPE, SIG_IGN); | |
120 | signal(SIGHUP, SIG_IGN); | |
121 | ||
122 | /* setup pipe and event handler to the parent process */ | |
123 | if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) | |
124 | fatal(NULL); | |
125 | imsg_init(&iev_main->ibuf, 3); | |
126 | iev_main->handler = ldpe_dispatch_main; | |
127 | iev_main->events = EV_READ; | |
128 | event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, | |
129 | iev_main->handler, iev_main); | |
130 | event_add(&iev_main->ev, NULL); | |
131 | ||
132 | if (sysdep.no_pfkey == 0) { | |
133 | event_set(&pfkey_ev, global.pfkeysock, EV_READ | EV_PERSIST, | |
134 | ldpe_dispatch_pfkey, NULL); | |
135 | event_add(&pfkey_ev, NULL); | |
136 | } | |
137 | ||
138 | /* mark sockets as closed */ | |
139 | global.ipv4.ldp_disc_socket = -1; | |
140 | global.ipv4.ldp_edisc_socket = -1; | |
141 | global.ipv4.ldp_session_socket = -1; | |
142 | global.ipv6.ldp_disc_socket = -1; | |
143 | global.ipv6.ldp_edisc_socket = -1; | |
144 | global.ipv6.ldp_session_socket = -1; | |
145 | ||
146 | /* listen on ldpd control socket */ | |
147 | TAILQ_INIT(&ctl_conns); | |
148 | control_listen(); | |
149 | ||
150 | if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL) | |
151 | fatal(__func__); | |
152 | ||
153 | event_dispatch(); | |
154 | ||
155 | ldpe_shutdown(); | |
156 | } | |
157 | ||
158 | static __dead void | |
159 | ldpe_shutdown(void) | |
160 | { | |
161 | struct if_addr *if_addr; | |
162 | struct adj *adj; | |
163 | ||
164 | /* close pipes */ | |
165 | msgbuf_write(&iev_lde->ibuf.w); | |
166 | msgbuf_clear(&iev_lde->ibuf.w); | |
167 | close(iev_lde->ibuf.fd); | |
168 | msgbuf_write(&iev_main->ibuf.w); | |
169 | msgbuf_clear(&iev_main->ibuf.w); | |
170 | close(iev_main->ibuf.fd); | |
171 | ||
172 | control_cleanup(); | |
173 | config_clear(leconf); | |
174 | ||
175 | if (sysdep.no_pfkey == 0) { | |
176 | event_del(&pfkey_ev); | |
177 | close(global.pfkeysock); | |
178 | } | |
179 | ldpe_close_sockets(AF_INET); | |
180 | ldpe_close_sockets(AF_INET6); | |
181 | ||
182 | /* remove addresses from global list */ | |
183 | while ((if_addr = LIST_FIRST(&global.addr_list)) != NULL) { | |
184 | LIST_REMOVE(if_addr, entry); | |
185 | free(if_addr); | |
186 | } | |
187 | while ((adj = LIST_FIRST(&global.adj_list)) != NULL) | |
188 | adj_del(adj, S_SHUTDOWN); | |
189 | ||
190 | /* clean up */ | |
191 | free(iev_lde); | |
192 | free(iev_main); | |
193 | free(pkt_ptr); | |
194 | ||
195 | log_info("ldp engine exiting"); | |
196 | exit(0); | |
197 | } | |
198 | ||
199 | /* imesg */ | |
200 | int | |
201 | ldpe_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen) | |
202 | { | |
203 | return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); | |
204 | } | |
205 | ||
206 | int | |
207 | ldpe_imsg_compose_lde(int type, uint32_t peerid, pid_t pid, void *data, | |
208 | uint16_t datalen) | |
209 | { | |
210 | return (imsg_compose_event(iev_lde, type, peerid, pid, -1, | |
211 | data, datalen)); | |
212 | } | |
213 | ||
214 | /* ARGSUSED */ | |
215 | static void | |
216 | ldpe_dispatch_main(int fd, short event, void *bula) | |
217 | { | |
218 | static struct ldpd_conf *nconf; | |
219 | struct iface *niface; | |
220 | struct tnbr *ntnbr; | |
221 | struct nbr_params *nnbrp; | |
222 | static struct l2vpn *nl2vpn; | |
223 | struct l2vpn_if *nlif; | |
224 | struct l2vpn_pw *npw; | |
225 | struct imsg imsg; | |
226 | struct imsgev *iev = bula; | |
227 | struct imsgbuf *ibuf = &iev->ibuf; | |
228 | struct iface *iface = NULL; | |
229 | struct kif *kif; | |
230 | int af; | |
231 | enum socket_type *socket_type; | |
232 | static int disc_socket = -1; | |
233 | static int edisc_socket = -1; | |
234 | static int session_socket = -1; | |
235 | struct nbr *nbr; | |
236 | struct nbr_params *nbrp; | |
237 | int n, shut = 0; | |
238 | ||
239 | if (event & EV_READ) { | |
240 | if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) | |
241 | fatal("imsg_read error"); | |
242 | if (n == 0) /* connection closed */ | |
243 | shut = 1; | |
244 | } | |
245 | if (event & EV_WRITE) { | |
246 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) | |
247 | fatal("ldpe_dispatch_main: msgbuf_write"); | |
248 | if (n == 0) | |
249 | shut = 1; | |
250 | } | |
251 | ||
252 | for (;;) { | |
253 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |
254 | fatal("ldpe_dispatch_main: imsg_get error"); | |
255 | if (n == 0) | |
256 | break; | |
257 | ||
258 | switch (imsg.hdr.type) { | |
259 | case IMSG_IFSTATUS: | |
260 | if (imsg.hdr.len != IMSG_HEADER_SIZE + | |
261 | sizeof(struct kif)) | |
262 | fatalx("IFSTATUS imsg with wrong len"); | |
263 | kif = imsg.data; | |
264 | ||
265 | iface = if_lookup(leconf, kif->ifindex); | |
266 | if (!iface) | |
267 | break; | |
268 | ||
269 | iface->flags = kif->flags; | |
270 | iface->linkstate = kif->link_state; | |
271 | if_update(iface, AF_UNSPEC); | |
272 | break; | |
273 | case IMSG_NEWADDR: | |
274 | if (imsg.hdr.len != IMSG_HEADER_SIZE + | |
275 | sizeof(struct kaddr)) | |
276 | fatalx("NEWADDR imsg with wrong len"); | |
277 | ||
278 | if_addr_add(imsg.data); | |
279 | break; | |
280 | case IMSG_DELADDR: | |
281 | if (imsg.hdr.len != IMSG_HEADER_SIZE + | |
282 | sizeof(struct kaddr)) | |
283 | fatalx("DELADDR imsg with wrong len"); | |
284 | ||
285 | if_addr_del(imsg.data); | |
286 | break; | |
287 | case IMSG_SOCKET_IPC: | |
288 | if (iev_lde) { | |
289 | log_warnx("%s: received unexpected imsg fd " | |
290 | "to lde", __func__); | |
291 | break; | |
292 | } | |
293 | if ((fd = imsg.fd) == -1) { | |
294 | log_warnx("%s: expected to receive imsg fd to " | |
295 | "lde but didn't receive any", __func__); | |
296 | break; | |
297 | } | |
298 | ||
299 | if ((iev_lde = malloc(sizeof(struct imsgev))) == NULL) | |
300 | fatal(NULL); | |
301 | imsg_init(&iev_lde->ibuf, fd); | |
302 | iev_lde->handler = ldpe_dispatch_lde; | |
303 | iev_lde->events = EV_READ; | |
304 | event_set(&iev_lde->ev, iev_lde->ibuf.fd, | |
305 | iev_lde->events, iev_lde->handler, iev_lde); | |
306 | event_add(&iev_lde->ev, NULL); | |
307 | break; | |
308 | case IMSG_CLOSE_SOCKETS: | |
309 | af = imsg.hdr.peerid; | |
310 | ||
311 | RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { | |
312 | if (nbr->af != af) | |
313 | continue; | |
314 | session_shutdown(nbr, S_SHUTDOWN, 0, 0); | |
315 | pfkey_remove(nbr); | |
316 | } | |
317 | ldpe_close_sockets(af); | |
318 | if_update_all(af); | |
319 | tnbr_update_all(af); | |
320 | ||
321 | disc_socket = -1; | |
322 | edisc_socket = -1; | |
323 | session_socket = -1; | |
324 | if ((ldp_af_conf_get(leconf, af))->flags & | |
325 | F_LDPD_AF_ENABLED) | |
326 | ldpe_imsg_compose_parent(IMSG_REQUEST_SOCKETS, | |
327 | af, NULL, 0); | |
328 | break; | |
329 | case IMSG_SOCKET_NET: | |
330 | if (imsg.hdr.len != IMSG_HEADER_SIZE + | |
331 | sizeof(enum socket_type)) | |
332 | fatalx("SOCKET_NET imsg with wrong len"); | |
333 | socket_type = imsg.data; | |
334 | ||
335 | switch (*socket_type) { | |
336 | case LDP_SOCKET_DISC: | |
337 | disc_socket = imsg.fd; | |
338 | break; | |
339 | case LDP_SOCKET_EDISC: | |
340 | edisc_socket = imsg.fd; | |
341 | break; | |
342 | case LDP_SOCKET_SESSION: | |
343 | session_socket = imsg.fd; | |
344 | break; | |
345 | } | |
346 | break; | |
347 | case IMSG_SETUP_SOCKETS: | |
348 | af = imsg.hdr.peerid; | |
349 | if (disc_socket == -1 || edisc_socket == -1 || | |
350 | session_socket == -1) { | |
351 | if (disc_socket != -1) | |
352 | close(disc_socket); | |
353 | if (edisc_socket != -1) | |
354 | close(edisc_socket); | |
355 | if (session_socket != -1) | |
356 | close(session_socket); | |
357 | break; | |
358 | } | |
359 | ||
360 | ldpe_setup_sockets(af, disc_socket, edisc_socket, | |
361 | session_socket); | |
362 | if_update_all(af); | |
363 | tnbr_update_all(af); | |
364 | RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { | |
365 | if (nbr->af != af) | |
366 | continue; | |
367 | nbr->laddr = (ldp_af_conf_get(leconf, | |
368 | af))->trans_addr; | |
369 | nbrp = nbr_params_find(leconf, nbr->id); | |
370 | if (nbrp && pfkey_establish(nbr, nbrp) == -1) | |
371 | fatalx("pfkey setup failed"); | |
372 | if (nbr_session_active_role(nbr)) | |
373 | nbr_establish_connection(nbr); | |
374 | } | |
375 | break; | |
376 | case IMSG_RECONF_CONF: | |
377 | if ((nconf = malloc(sizeof(struct ldpd_conf))) == | |
378 | NULL) | |
379 | fatal(NULL); | |
380 | memcpy(nconf, imsg.data, sizeof(struct ldpd_conf)); | |
381 | ||
382 | LIST_INIT(&nconf->iface_list); | |
383 | LIST_INIT(&nconf->tnbr_list); | |
384 | LIST_INIT(&nconf->nbrp_list); | |
385 | LIST_INIT(&nconf->l2vpn_list); | |
386 | break; | |
387 | case IMSG_RECONF_IFACE: | |
388 | if ((niface = malloc(sizeof(struct iface))) == NULL) | |
389 | fatal(NULL); | |
390 | memcpy(niface, imsg.data, sizeof(struct iface)); | |
391 | ||
392 | LIST_INIT(&niface->addr_list); | |
393 | LIST_INIT(&niface->ipv4.adj_list); | |
394 | LIST_INIT(&niface->ipv6.adj_list); | |
395 | niface->ipv4.iface = niface; | |
396 | niface->ipv6.iface = niface; | |
397 | ||
398 | LIST_INSERT_HEAD(&nconf->iface_list, niface, entry); | |
399 | break; | |
400 | case IMSG_RECONF_TNBR: | |
401 | if ((ntnbr = malloc(sizeof(struct tnbr))) == NULL) | |
402 | fatal(NULL); | |
403 | memcpy(ntnbr, imsg.data, sizeof(struct tnbr)); | |
404 | ||
405 | LIST_INSERT_HEAD(&nconf->tnbr_list, ntnbr, entry); | |
406 | break; | |
407 | case IMSG_RECONF_NBRP: | |
408 | if ((nnbrp = malloc(sizeof(struct nbr_params))) == NULL) | |
409 | fatal(NULL); | |
410 | memcpy(nnbrp, imsg.data, sizeof(struct nbr_params)); | |
411 | ||
412 | LIST_INSERT_HEAD(&nconf->nbrp_list, nnbrp, entry); | |
413 | break; | |
414 | case IMSG_RECONF_L2VPN: | |
415 | if ((nl2vpn = malloc(sizeof(struct l2vpn))) == NULL) | |
416 | fatal(NULL); | |
417 | memcpy(nl2vpn, imsg.data, sizeof(struct l2vpn)); | |
418 | ||
419 | LIST_INIT(&nl2vpn->if_list); | |
420 | LIST_INIT(&nl2vpn->pw_list); | |
421 | ||
422 | LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry); | |
423 | break; | |
424 | case IMSG_RECONF_L2VPN_IF: | |
425 | if ((nlif = malloc(sizeof(struct l2vpn_if))) == NULL) | |
426 | fatal(NULL); | |
427 | memcpy(nlif, imsg.data, sizeof(struct l2vpn_if)); | |
428 | ||
429 | nlif->l2vpn = nl2vpn; | |
430 | LIST_INSERT_HEAD(&nl2vpn->if_list, nlif, entry); | |
431 | break; | |
432 | case IMSG_RECONF_L2VPN_PW: | |
433 | if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL) | |
434 | fatal(NULL); | |
435 | memcpy(npw, imsg.data, sizeof(struct l2vpn_pw)); | |
436 | ||
437 | npw->l2vpn = nl2vpn; | |
438 | LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry); | |
439 | break; | |
440 | case IMSG_RECONF_END: | |
441 | merge_config(leconf, nconf); | |
442 | nconf = NULL; | |
443 | global.conf_seqnum++; | |
444 | break; | |
445 | case IMSG_CTL_KROUTE: | |
446 | case IMSG_CTL_KROUTE_ADDR: | |
447 | case IMSG_CTL_IFINFO: | |
448 | case IMSG_CTL_END: | |
449 | control_imsg_relay(&imsg); | |
450 | break; | |
451 | default: | |
452 | log_debug("ldpe_dispatch_main: error handling imsg %d", | |
453 | imsg.hdr.type); | |
454 | break; | |
455 | } | |
456 | imsg_free(&imsg); | |
457 | } | |
458 | if (!shut) | |
459 | imsg_event_add(iev); | |
460 | else { | |
461 | /* this pipe is dead, so remove the event handler */ | |
462 | event_del(&iev->ev); | |
463 | event_loopexit(NULL); | |
464 | } | |
465 | } | |
466 | ||
467 | /* ARGSUSED */ | |
468 | static void | |
469 | ldpe_dispatch_lde(int fd, short event, void *bula) | |
470 | { | |
471 | struct imsgev *iev = bula; | |
472 | struct imsgbuf *ibuf = &iev->ibuf; | |
473 | struct imsg imsg; | |
474 | struct map map; | |
475 | struct notify_msg nm; | |
476 | int n, shut = 0; | |
477 | struct nbr *nbr = NULL; | |
478 | ||
479 | if (event & EV_READ) { | |
480 | if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) | |
481 | fatal("imsg_read error"); | |
482 | if (n == 0) /* connection closed */ | |
483 | shut = 1; | |
484 | } | |
485 | if (event & EV_WRITE) { | |
486 | if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) | |
487 | fatal("ldpe_dispatch_lde: msgbuf_write"); | |
488 | if (n == 0) | |
489 | shut = 1; | |
490 | } | |
491 | ||
492 | for (;;) { | |
493 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |
494 | fatal("ldpe_dispatch_lde: imsg_get error"); | |
495 | if (n == 0) | |
496 | break; | |
497 | ||
498 | switch (imsg.hdr.type) { | |
499 | case IMSG_MAPPING_ADD: | |
500 | case IMSG_RELEASE_ADD: | |
501 | case IMSG_REQUEST_ADD: | |
502 | case IMSG_WITHDRAW_ADD: | |
503 | if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map)) | |
504 | fatalx("invalid size of map request"); | |
505 | memcpy(&map, imsg.data, sizeof(map)); | |
506 | ||
507 | nbr = nbr_find_peerid(imsg.hdr.peerid); | |
508 | if (nbr == NULL) { | |
509 | log_debug("ldpe_dispatch_lde: cannot find " | |
510 | "neighbor"); | |
511 | break; | |
512 | } | |
513 | if (nbr->state != NBR_STA_OPER) | |
514 | break; | |
515 | ||
516 | switch (imsg.hdr.type) { | |
517 | case IMSG_MAPPING_ADD: | |
518 | mapping_list_add(&nbr->mapping_list, &map); | |
519 | break; | |
520 | case IMSG_RELEASE_ADD: | |
521 | mapping_list_add(&nbr->release_list, &map); | |
522 | break; | |
523 | case IMSG_REQUEST_ADD: | |
524 | mapping_list_add(&nbr->request_list, &map); | |
525 | break; | |
526 | case IMSG_WITHDRAW_ADD: | |
527 | mapping_list_add(&nbr->withdraw_list, &map); | |
528 | break; | |
529 | } | |
530 | break; | |
531 | case IMSG_MAPPING_ADD_END: | |
532 | case IMSG_RELEASE_ADD_END: | |
533 | case IMSG_REQUEST_ADD_END: | |
534 | case IMSG_WITHDRAW_ADD_END: | |
535 | nbr = nbr_find_peerid(imsg.hdr.peerid); | |
536 | if (nbr == NULL) { | |
537 | log_debug("ldpe_dispatch_lde: cannot find " | |
538 | "neighbor"); | |
539 | break; | |
540 | } | |
541 | if (nbr->state != NBR_STA_OPER) | |
542 | break; | |
543 | ||
544 | switch (imsg.hdr.type) { | |
545 | case IMSG_MAPPING_ADD_END: | |
546 | send_labelmessage(nbr, MSG_TYPE_LABELMAPPING, | |
547 | &nbr->mapping_list); | |
548 | break; | |
549 | case IMSG_RELEASE_ADD_END: | |
550 | send_labelmessage(nbr, MSG_TYPE_LABELRELEASE, | |
551 | &nbr->release_list); | |
552 | break; | |
553 | case IMSG_REQUEST_ADD_END: | |
554 | send_labelmessage(nbr, MSG_TYPE_LABELREQUEST, | |
555 | &nbr->request_list); | |
556 | break; | |
557 | case IMSG_WITHDRAW_ADD_END: | |
558 | send_labelmessage(nbr, MSG_TYPE_LABELWITHDRAW, | |
559 | &nbr->withdraw_list); | |
560 | break; | |
561 | } | |
562 | break; | |
563 | case IMSG_NOTIFICATION_SEND: | |
564 | if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm)) | |
565 | fatalx("invalid size of OE request"); | |
566 | memcpy(&nm, imsg.data, sizeof(nm)); | |
567 | ||
568 | nbr = nbr_find_peerid(imsg.hdr.peerid); | |
569 | if (nbr == NULL) { | |
570 | log_debug("ldpe_dispatch_lde: cannot find " | |
571 | "neighbor"); | |
572 | break; | |
573 | } | |
574 | if (nbr->state != NBR_STA_OPER) | |
575 | break; | |
576 | ||
577 | send_notification_full(nbr->tcp, &nm); | |
578 | break; | |
579 | case IMSG_CTL_END: | |
580 | case IMSG_CTL_SHOW_LIB: | |
581 | case IMSG_CTL_SHOW_L2VPN_PW: | |
582 | case IMSG_CTL_SHOW_L2VPN_BINDING: | |
583 | control_imsg_relay(&imsg); | |
584 | break; | |
585 | default: | |
586 | log_debug("ldpe_dispatch_lde: error handling imsg %d", | |
587 | imsg.hdr.type); | |
588 | break; | |
589 | } | |
590 | imsg_free(&imsg); | |
591 | } | |
592 | if (!shut) | |
593 | imsg_event_add(iev); | |
594 | else { | |
595 | /* this pipe is dead, so remove the event handler */ | |
596 | event_del(&iev->ev); | |
597 | event_loopexit(NULL); | |
598 | } | |
599 | } | |
600 | ||
601 | /* ARGSUSED */ | |
602 | static void | |
603 | ldpe_dispatch_pfkey(int fd, short event, void *bula) | |
604 | { | |
605 | if (event & EV_READ) { | |
606 | if (pfkey_read(fd, NULL) == -1) { | |
607 | fatal("pfkey_read failed, exiting..."); | |
608 | } | |
609 | } | |
610 | } | |
611 | ||
612 | static void | |
613 | ldpe_setup_sockets(int af, int disc_socket, int edisc_socket, | |
614 | int session_socket) | |
615 | { | |
616 | struct ldpd_af_global *af_global; | |
617 | ||
618 | af_global = ldp_af_global_get(&global, af); | |
619 | ||
620 | /* discovery socket */ | |
621 | af_global->ldp_disc_socket = disc_socket; | |
622 | event_set(&af_global->disc_ev, af_global->ldp_disc_socket, | |
623 | EV_READ|EV_PERSIST, disc_recv_packet, NULL); | |
624 | event_add(&af_global->disc_ev, NULL); | |
625 | ||
626 | /* extended discovery socket */ | |
627 | af_global->ldp_edisc_socket = edisc_socket; | |
628 | event_set(&af_global->edisc_ev, af_global->ldp_edisc_socket, | |
629 | EV_READ|EV_PERSIST, disc_recv_packet, NULL); | |
630 | event_add(&af_global->edisc_ev, NULL); | |
631 | ||
632 | /* session socket */ | |
633 | af_global->ldp_session_socket = session_socket; | |
634 | accept_add(af_global->ldp_session_socket, session_accept, NULL); | |
635 | } | |
636 | ||
637 | static void | |
638 | ldpe_close_sockets(int af) | |
639 | { | |
640 | struct ldpd_af_global *af_global; | |
641 | ||
642 | af_global = ldp_af_global_get(&global, af); | |
643 | ||
644 | /* discovery socket */ | |
645 | if (event_initialized(&af_global->disc_ev)) | |
646 | event_del(&af_global->disc_ev); | |
647 | if (af_global->ldp_disc_socket != -1) { | |
648 | close(af_global->ldp_disc_socket); | |
649 | af_global->ldp_disc_socket = -1; | |
650 | } | |
651 | ||
652 | /* extended discovery socket */ | |
653 | if (event_initialized(&af_global->edisc_ev)) | |
654 | event_del(&af_global->edisc_ev); | |
655 | if (af_global->ldp_edisc_socket != -1) { | |
656 | close(af_global->ldp_edisc_socket); | |
657 | af_global->ldp_edisc_socket = -1; | |
658 | } | |
659 | ||
660 | /* session socket */ | |
661 | if (af_global->ldp_session_socket != -1) { | |
662 | accept_del(af_global->ldp_session_socket); | |
663 | close(af_global->ldp_session_socket); | |
664 | af_global->ldp_session_socket = -1; | |
665 | } | |
666 | } | |
667 | ||
668 | void | |
669 | ldpe_reset_nbrs(int af) | |
670 | { | |
671 | struct nbr *nbr; | |
672 | ||
673 | RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { | |
674 | if (nbr->af == af) | |
675 | session_shutdown(nbr, S_SHUTDOWN, 0, 0); | |
676 | } | |
677 | } | |
678 | ||
679 | void | |
680 | ldpe_reset_ds_nbrs(void) | |
681 | { | |
682 | struct nbr *nbr; | |
683 | ||
684 | RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { | |
685 | if (nbr->ds_tlv) | |
686 | session_shutdown(nbr, S_SHUTDOWN, 0, 0); | |
687 | } | |
688 | } | |
689 | ||
690 | void | |
691 | ldpe_remove_dynamic_tnbrs(int af) | |
692 | { | |
693 | struct tnbr *tnbr, *safe; | |
694 | ||
695 | LIST_FOREACH_SAFE(tnbr, &leconf->tnbr_list, entry, safe) { | |
696 | if (tnbr->af != af) | |
697 | continue; | |
698 | ||
699 | tnbr->flags &= ~F_TNBR_DYNAMIC; | |
700 | tnbr_check(tnbr); | |
701 | } | |
702 | } | |
703 | ||
704 | void | |
705 | ldpe_stop_init_backoff(int af) | |
706 | { | |
707 | struct nbr *nbr; | |
708 | ||
709 | RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { | |
710 | if (nbr->af == af && nbr_pending_idtimer(nbr)) { | |
711 | nbr_stop_idtimer(nbr); | |
712 | nbr_establish_connection(nbr); | |
713 | } | |
714 | } | |
715 | } | |
716 | ||
717 | static void | |
718 | ldpe_iface_af_ctl(struct ctl_conn *c, int af, unsigned int idx) | |
719 | { | |
720 | struct iface *iface; | |
721 | struct iface_af *ia; | |
722 | struct ctl_iface *ictl; | |
723 | ||
724 | LIST_FOREACH(iface, &leconf->iface_list, entry) { | |
725 | if (idx == 0 || idx == iface->ifindex) { | |
726 | ia = iface_af_get(iface, af); | |
727 | if (!ia->enabled) | |
728 | continue; | |
729 | ||
730 | ictl = if_to_ctl(ia); | |
731 | imsg_compose_event(&c->iev, | |
732 | IMSG_CTL_SHOW_INTERFACE, | |
733 | 0, 0, -1, ictl, sizeof(struct ctl_iface)); | |
734 | } | |
735 | } | |
736 | } | |
737 | ||
738 | void | |
739 | ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx) | |
740 | { | |
741 | ldpe_iface_af_ctl(c, AF_INET, idx); | |
742 | ldpe_iface_af_ctl(c, AF_INET6, idx); | |
743 | } | |
744 | ||
745 | void | |
746 | ldpe_adj_ctl(struct ctl_conn *c) | |
747 | { | |
748 | struct nbr *nbr; | |
749 | struct adj *adj; | |
750 | struct ctl_adj *actl; | |
751 | ||
752 | RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) { | |
753 | LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) { | |
754 | actl = adj_to_ctl(adj); | |
755 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, | |
756 | 0, 0, -1, actl, sizeof(struct ctl_adj)); | |
757 | } | |
758 | } | |
759 | /* show adjacencies not associated with any neighbor */ | |
760 | LIST_FOREACH(adj, &global.adj_list, global_entry) { | |
761 | if (adj->nbr != NULL) | |
762 | continue; | |
763 | ||
764 | actl = adj_to_ctl(adj); | |
765 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0, | |
766 | -1, actl, sizeof(struct ctl_adj)); | |
767 | } | |
768 | ||
769 | imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); | |
770 | } | |
771 | ||
772 | void | |
773 | ldpe_nbr_ctl(struct ctl_conn *c) | |
774 | { | |
775 | struct nbr *nbr; | |
776 | struct ctl_nbr *nctl; | |
777 | ||
778 | RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) { | |
779 | nctl = nbr_to_ctl(nbr); | |
780 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl, | |
781 | sizeof(struct ctl_nbr)); | |
782 | } | |
783 | imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); | |
784 | } | |
785 | ||
786 | void | |
787 | mapping_list_add(struct mapping_head *mh, struct map *map) | |
788 | { | |
789 | struct mapping_entry *me; | |
790 | ||
791 | me = calloc(1, sizeof(*me)); | |
792 | if (me == NULL) | |
793 | fatal(__func__); | |
794 | me->map = *map; | |
795 | ||
796 | TAILQ_INSERT_TAIL(mh, me, entry); | |
797 | } | |
798 | ||
799 | void | |
800 | mapping_list_clr(struct mapping_head *mh) | |
801 | { | |
802 | struct mapping_entry *me; | |
803 | ||
804 | while ((me = TAILQ_FIRST(mh)) != NULL) { | |
805 | TAILQ_REMOVE(mh, me, entry); | |
806 | free(me); | |
807 | } | |
808 | } |