]>
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 | ||
eac6e3f0 | 22 | #include <zebra.h> |
8429abe0 RW |
23 | |
24 | #include "ldpd.h" | |
25 | #include "ldpe.h" | |
26 | #include "lde.h" | |
27 | #include "control.h" | |
28 | #include "log.h" | |
eac6e3f0 RW |
29 | #include "ldp_debug.h" |
30 | ||
31 | #include <lib/log.h> | |
32 | #include "memory.h" | |
33 | #include "privs.h" | |
34 | #include "sigevent.h" | |
35 | ||
36 | static void ldpe_shutdown(void); | |
37 | static int ldpe_dispatch_main(struct thread *); | |
38 | static int ldpe_dispatch_lde(struct thread *); | |
39 | #ifdef __OpenBSD__ | |
40 | static int ldpe_dispatch_pfkey(struct thread *); | |
41 | #endif | |
8429abe0 RW |
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; | |
eac6e3f0 | 47 | #ifdef __OpenBSD__ |
8429abe0 | 48 | struct ldpd_sysdep sysdep; |
eac6e3f0 | 49 | #endif |
8429abe0 | 50 | |
28e8294c | 51 | static struct imsgev *iev_main, *iev_main_sync; |
8429abe0 | 52 | static struct imsgev *iev_lde; |
eac6e3f0 RW |
53 | #ifdef __OpenBSD__ |
54 | static struct thread *pfkey_ev; | |
55 | #endif | |
8429abe0 | 56 | |
eac6e3f0 RW |
57 | /* Master of threads. */ |
58 | struct thread_master *master; | |
59 | ||
60 | /* ldpe privileges */ | |
61 | static zebra_capabilities_t _caps_p [] = | |
62 | { | |
63 | ZCAP_BIND, | |
64 | ZCAP_NET_ADMIN | |
65 | }; | |
66 | ||
67 | struct zebra_privs_t ldpe_privs = | |
68 | { | |
b2f36157 DL |
69 | #if defined(FRR_USER) && defined(FRR_GROUP) |
70 | .user = FRR_USER, | |
71 | .group = FRR_GROUP, | |
eac6e3f0 RW |
72 | #endif |
73 | #if defined(VTY_GROUP) | |
74 | .vty_group = VTY_GROUP, | |
75 | #endif | |
76 | .caps_p = _caps_p, | |
77 | .cap_num_p = array_size(_caps_p), | |
78 | .cap_num_i = 0 | |
79 | }; | |
80 | ||
81 | /* SIGINT / SIGTERM handler. */ | |
8429abe0 | 82 | static void |
eac6e3f0 | 83 | sigint(void) |
8429abe0 | 84 | { |
eac6e3f0 | 85 | ldpe_shutdown(); |
8429abe0 RW |
86 | } |
87 | ||
eac6e3f0 RW |
88 | static struct quagga_signal_t ldpe_signals[] = |
89 | { | |
1e7e440f RW |
90 | { |
91 | .signal = SIGHUP, | |
92 | /* ignore */ | |
93 | }, | |
eac6e3f0 RW |
94 | { |
95 | .signal = SIGINT, | |
96 | .handler = &sigint, | |
97 | }, | |
98 | { | |
99 | .signal = SIGTERM, | |
100 | .handler = &sigint, | |
101 | }, | |
102 | }; | |
103 | ||
8429abe0 RW |
104 | /* label distribution protocol engine */ |
105 | void | |
274f5abf | 106 | ldpe(void) |
8429abe0 | 107 | { |
eac6e3f0 | 108 | struct thread thread; |
8429abe0 | 109 | |
eac6e3f0 | 110 | #ifdef HAVE_SETPROCTITLE |
8429abe0 | 111 | setproctitle("ldp engine"); |
eac6e3f0 | 112 | #endif |
8429abe0 | 113 | ldpd_process = PROC_LDP_ENGINE; |
fa68f9da | 114 | log_procname = log_procnames[ldpd_process]; |
8429abe0 | 115 | |
eac6e3f0 | 116 | master = thread_master_create(); |
8429abe0 RW |
117 | |
118 | /* setup signal handler */ | |
eac6e3f0 | 119 | signal_init(master, array_size(ldpe_signals), ldpe_signals); |
8429abe0 | 120 | |
28e8294c RW |
121 | /* setup pipes and event handlers to the parent process */ |
122 | if ((iev_main = calloc(1, sizeof(struct imsgev))) == NULL) | |
8429abe0 | 123 | fatal(NULL); |
28e8294c | 124 | imsg_init(&iev_main->ibuf, LDPD_FD_ASYNC); |
eac6e3f0 RW |
125 | iev_main->handler_read = ldpe_dispatch_main; |
126 | iev_main->ev_read = thread_add_read(master, iev_main->handler_read, | |
127 | iev_main, iev_main->ibuf.fd); | |
128 | iev_main->handler_write = ldp_write_handler; | |
28e8294c RW |
129 | |
130 | if ((iev_main_sync = calloc(1, sizeof(struct imsgev))) == NULL) | |
131 | fatal(NULL); | |
132 | imsg_init(&iev_main_sync->ibuf, LDPD_FD_SYNC); | |
eac6e3f0 | 133 | |
274f5abf RW |
134 | /* create base configuration */ |
135 | leconf = config_new_empty(); | |
136 | ||
137 | /* Fetch next active thread. */ | |
138 | while (thread_fetch(master, &thread)) | |
139 | thread_call(&thread); | |
140 | } | |
141 | ||
142 | void | |
143 | ldpe_init(struct ldpd_init *init) | |
144 | { | |
145 | /* drop privileges */ | |
146 | if (init->user) | |
147 | ldpe_privs.user = init->user; | |
148 | if (init->group) | |
149 | ldpe_privs.group = init->group; | |
150 | zprivs_init(&ldpe_privs); | |
151 | ||
152 | /* listen on ldpd control socket */ | |
153 | strlcpy(ctl_sock_path, init->ctl_sock_path, sizeof(ctl_sock_path)); | |
154 | if (control_init(ctl_sock_path) == -1) | |
155 | fatalx("control socket setup failed"); | |
156 | TAILQ_INIT(&ctl_conns); | |
157 | control_listen(); | |
158 | ||
159 | #ifdef HAVE_PLEDGE | |
160 | if (pledge("stdio cpath inet mcast recvfd", NULL) == -1) | |
161 | fatal("pledge"); | |
162 | #endif | |
163 | ||
164 | LIST_INIT(&global.addr_list); | |
165 | RB_INIT(&global.adj_tree); | |
166 | TAILQ_INIT(&global.pending_conns); | |
167 | if (inet_pton(AF_INET, AllRouters_v4, &global.mcast_addr_v4) != 1) | |
168 | fatal("inet_pton"); | |
169 | if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1) | |
170 | fatal("inet_pton"); | |
eac6e3f0 | 171 | #ifdef __OpenBSD__ |
274f5abf | 172 | global.pfkeysock = pfkey_init(); |
eac6e3f0 RW |
173 | if (sysdep.no_pfkey == 0) |
174 | pfkey_ev = thread_add_read(master, ldpe_dispatch_pfkey, | |
175 | NULL, global.pfkeysock); | |
176 | #endif | |
8429abe0 RW |
177 | |
178 | /* mark sockets as closed */ | |
179 | global.ipv4.ldp_disc_socket = -1; | |
180 | global.ipv4.ldp_edisc_socket = -1; | |
181 | global.ipv4.ldp_session_socket = -1; | |
182 | global.ipv6.ldp_disc_socket = -1; | |
183 | global.ipv6.ldp_edisc_socket = -1; | |
184 | global.ipv6.ldp_session_socket = -1; | |
185 | ||
8429abe0 RW |
186 | if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL) |
187 | fatal(__func__); | |
188 | ||
274f5abf | 189 | accept_init(); |
8429abe0 RW |
190 | } |
191 | ||
eac6e3f0 | 192 | static void |
8429abe0 RW |
193 | ldpe_shutdown(void) |
194 | { | |
195 | struct if_addr *if_addr; | |
196 | struct adj *adj; | |
197 | ||
198 | /* close pipes */ | |
835a7376 RW |
199 | if (iev_lde) { |
200 | msgbuf_write(&iev_lde->ibuf.w); | |
201 | msgbuf_clear(&iev_lde->ibuf.w); | |
202 | close(iev_lde->ibuf.fd); | |
203 | } | |
8429abe0 RW |
204 | msgbuf_write(&iev_main->ibuf.w); |
205 | msgbuf_clear(&iev_main->ibuf.w); | |
206 | close(iev_main->ibuf.fd); | |
28e8294c RW |
207 | msgbuf_clear(&iev_main_sync->ibuf.w); |
208 | close(iev_main_sync->ibuf.fd); | |
8429abe0 | 209 | |
274f5abf | 210 | control_cleanup(ctl_sock_path); |
8429abe0 RW |
211 | config_clear(leconf); |
212 | ||
eac6e3f0 | 213 | #ifdef __OpenBSD__ |
8429abe0 | 214 | if (sysdep.no_pfkey == 0) { |
eac6e3f0 | 215 | THREAD_READ_OFF(pfkey_ev); |
8429abe0 RW |
216 | close(global.pfkeysock); |
217 | } | |
eac6e3f0 | 218 | #endif |
8429abe0 RW |
219 | ldpe_close_sockets(AF_INET); |
220 | ldpe_close_sockets(AF_INET6); | |
221 | ||
222 | /* remove addresses from global list */ | |
223 | while ((if_addr = LIST_FIRST(&global.addr_list)) != NULL) { | |
224 | LIST_REMOVE(if_addr, entry); | |
225 | free(if_addr); | |
226 | } | |
057d48bd | 227 | while ((adj = RB_ROOT(&global.adj_tree)) != NULL) |
8429abe0 RW |
228 | adj_del(adj, S_SHUTDOWN); |
229 | ||
230 | /* clean up */ | |
835a7376 RW |
231 | if (iev_lde) |
232 | free(iev_lde); | |
8429abe0 | 233 | free(iev_main); |
28e8294c | 234 | free(iev_main_sync); |
8429abe0 RW |
235 | free(pkt_ptr); |
236 | ||
237 | log_info("ldp engine exiting"); | |
238 | exit(0); | |
239 | } | |
240 | ||
241 | /* imesg */ | |
242 | int | |
243 | ldpe_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen) | |
244 | { | |
245 | return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); | |
246 | } | |
247 | ||
f2232fdf RW |
248 | void |
249 | ldpe_imsg_compose_parent_sync(int type, pid_t pid, void *data, uint16_t datalen) | |
250 | { | |
251 | imsg_compose_event(iev_main_sync, type, 0, pid, -1, data, datalen); | |
252 | imsg_flush(&iev_main_sync->ibuf); | |
253 | } | |
254 | ||
8429abe0 RW |
255 | int |
256 | ldpe_imsg_compose_lde(int type, uint32_t peerid, pid_t pid, void *data, | |
257 | uint16_t datalen) | |
258 | { | |
259 | return (imsg_compose_event(iev_lde, type, peerid, pid, -1, | |
260 | data, datalen)); | |
261 | } | |
262 | ||
263 | /* ARGSUSED */ | |
eac6e3f0 RW |
264 | static int |
265 | ldpe_dispatch_main(struct thread *thread) | |
8429abe0 RW |
266 | { |
267 | static struct ldpd_conf *nconf; | |
268 | struct iface *niface; | |
269 | struct tnbr *ntnbr; | |
270 | struct nbr_params *nnbrp; | |
26519d8c | 271 | static struct l2vpn *l2vpn, *nl2vpn; |
52b530fc RW |
272 | struct l2vpn_if *lif, *nlif; |
273 | struct l2vpn_pw *pw, *npw; | |
8429abe0 | 274 | struct imsg imsg; |
eac6e3f0 RW |
275 | int fd = THREAD_FD(thread); |
276 | struct imsgev *iev = THREAD_ARG(thread); | |
8429abe0 RW |
277 | struct imsgbuf *ibuf = &iev->ibuf; |
278 | struct iface *iface = NULL; | |
279 | struct kif *kif; | |
280 | int af; | |
281 | enum socket_type *socket_type; | |
282 | static int disc_socket = -1; | |
283 | static int edisc_socket = -1; | |
284 | static int session_socket = -1; | |
285 | struct nbr *nbr; | |
eac6e3f0 | 286 | #ifdef __OpenBSD__ |
8429abe0 | 287 | struct nbr_params *nbrp; |
eac6e3f0 | 288 | #endif |
8429abe0 RW |
289 | int n, shut = 0; |
290 | ||
eac6e3f0 RW |
291 | iev->ev_read = NULL; |
292 | ||
293 | if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) | |
294 | fatal("imsg_read error"); | |
295 | if (n == 0) /* connection closed */ | |
296 | shut = 1; | |
8429abe0 RW |
297 | |
298 | for (;;) { | |
299 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |
300 | fatal("ldpe_dispatch_main: imsg_get error"); | |
301 | if (n == 0) | |
302 | break; | |
303 | ||
304 | switch (imsg.hdr.type) { | |
305 | case IMSG_IFSTATUS: | |
306 | if (imsg.hdr.len != IMSG_HEADER_SIZE + | |
307 | sizeof(struct kif)) | |
308 | fatalx("IFSTATUS imsg with wrong len"); | |
309 | kif = imsg.data; | |
310 | ||
eac6e3f0 | 311 | iface = if_lookup_name(leconf, kif->ifname); |
26519d8c RW |
312 | if (iface) { |
313 | if_update_info(iface, kif); | |
61cd1100 | 314 | ldp_if_update(iface, AF_UNSPEC); |
8429abe0 | 315 | break; |
26519d8c | 316 | } |
8429abe0 | 317 | |
26519d8c | 318 | RB_FOREACH(l2vpn, l2vpn_head, &leconf->l2vpn_tree) { |
52bd4c23 | 319 | lif = l2vpn_if_find(l2vpn, kif->ifname); |
26519d8c | 320 | if (lif) { |
52b530fc | 321 | l2vpn_if_update_info(lif, kif); |
26519d8c RW |
322 | l2vpn_if_update(lif); |
323 | break; | |
324 | } | |
52b530fc RW |
325 | pw = l2vpn_pw_find(l2vpn, kif->ifname); |
326 | if (pw) { | |
327 | l2vpn_pw_update_info(pw, kif); | |
328 | break; | |
329 | } | |
26519d8c | 330 | } |
8429abe0 RW |
331 | break; |
332 | case IMSG_NEWADDR: | |
333 | if (imsg.hdr.len != IMSG_HEADER_SIZE + | |
334 | sizeof(struct kaddr)) | |
335 | fatalx("NEWADDR imsg with wrong len"); | |
336 | ||
337 | if_addr_add(imsg.data); | |
338 | break; | |
339 | case IMSG_DELADDR: | |
340 | if (imsg.hdr.len != IMSG_HEADER_SIZE + | |
341 | sizeof(struct kaddr)) | |
342 | fatalx("DELADDR imsg with wrong len"); | |
343 | ||
344 | if_addr_del(imsg.data); | |
345 | break; | |
346 | case IMSG_SOCKET_IPC: | |
347 | if (iev_lde) { | |
348 | log_warnx("%s: received unexpected imsg fd " | |
349 | "to lde", __func__); | |
350 | break; | |
351 | } | |
352 | if ((fd = imsg.fd) == -1) { | |
353 | log_warnx("%s: expected to receive imsg fd to " | |
354 | "lde but didn't receive any", __func__); | |
355 | break; | |
356 | } | |
357 | ||
358 | if ((iev_lde = malloc(sizeof(struct imsgev))) == NULL) | |
359 | fatal(NULL); | |
360 | imsg_init(&iev_lde->ibuf, fd); | |
eac6e3f0 RW |
361 | iev_lde->handler_read = ldpe_dispatch_lde; |
362 | iev_lde->ev_read = thread_add_read(master, | |
363 | iev_lde->handler_read, iev_lde, iev_lde->ibuf.fd); | |
364 | iev_lde->handler_write = ldp_write_handler; | |
365 | iev_lde->ev_write = NULL; | |
8429abe0 | 366 | break; |
274f5abf RW |
367 | case IMSG_INIT: |
368 | if (imsg.hdr.len != IMSG_HEADER_SIZE + | |
369 | sizeof(struct ldpd_init)) | |
370 | fatalx("INIT imsg with wrong len"); | |
371 | ||
372 | memcpy(&init, imsg.data, sizeof(init)); | |
373 | ldpe_init(&init); | |
374 | break; | |
8429abe0 RW |
375 | case IMSG_CLOSE_SOCKETS: |
376 | af = imsg.hdr.peerid; | |
377 | ||
378 | RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { | |
379 | if (nbr->af != af) | |
380 | continue; | |
381 | session_shutdown(nbr, S_SHUTDOWN, 0, 0); | |
eac6e3f0 | 382 | #ifdef __OpenBSD__ |
8429abe0 | 383 | pfkey_remove(nbr); |
eac6e3f0 | 384 | #endif |
0f7b5df9 | 385 | nbr->auth.method = AUTH_NONE; |
8429abe0 RW |
386 | } |
387 | ldpe_close_sockets(af); | |
388 | if_update_all(af); | |
389 | tnbr_update_all(af); | |
390 | ||
391 | disc_socket = -1; | |
392 | edisc_socket = -1; | |
393 | session_socket = -1; | |
394 | if ((ldp_af_conf_get(leconf, af))->flags & | |
395 | F_LDPD_AF_ENABLED) | |
396 | ldpe_imsg_compose_parent(IMSG_REQUEST_SOCKETS, | |
397 | af, NULL, 0); | |
398 | break; | |
399 | case IMSG_SOCKET_NET: | |
400 | if (imsg.hdr.len != IMSG_HEADER_SIZE + | |
401 | sizeof(enum socket_type)) | |
402 | fatalx("SOCKET_NET imsg with wrong len"); | |
403 | socket_type = imsg.data; | |
404 | ||
405 | switch (*socket_type) { | |
406 | case LDP_SOCKET_DISC: | |
407 | disc_socket = imsg.fd; | |
408 | break; | |
409 | case LDP_SOCKET_EDISC: | |
410 | edisc_socket = imsg.fd; | |
411 | break; | |
412 | case LDP_SOCKET_SESSION: | |
413 | session_socket = imsg.fd; | |
414 | break; | |
415 | } | |
416 | break; | |
417 | case IMSG_SETUP_SOCKETS: | |
418 | af = imsg.hdr.peerid; | |
419 | if (disc_socket == -1 || edisc_socket == -1 || | |
420 | session_socket == -1) { | |
421 | if (disc_socket != -1) | |
422 | close(disc_socket); | |
423 | if (edisc_socket != -1) | |
424 | close(edisc_socket); | |
425 | if (session_socket != -1) | |
426 | close(session_socket); | |
427 | break; | |
428 | } | |
429 | ||
430 | ldpe_setup_sockets(af, disc_socket, edisc_socket, | |
431 | session_socket); | |
432 | if_update_all(af); | |
433 | tnbr_update_all(af); | |
434 | RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { | |
435 | if (nbr->af != af) | |
436 | continue; | |
437 | nbr->laddr = (ldp_af_conf_get(leconf, | |
438 | af))->trans_addr; | |
eac6e3f0 | 439 | #ifdef __OpenBSD__ |
8429abe0 | 440 | nbrp = nbr_params_find(leconf, nbr->id); |
0f7b5df9 RW |
441 | if (nbrp) { |
442 | nbr->auth.method = nbrp->auth.method; | |
443 | if (pfkey_establish(nbr, nbrp) == -1) | |
444 | fatalx("pfkey setup failed"); | |
445 | } | |
eac6e3f0 | 446 | #endif |
8429abe0 RW |
447 | if (nbr_session_active_role(nbr)) |
448 | nbr_establish_connection(nbr); | |
449 | } | |
450 | break; | |
eac6e3f0 RW |
451 | case IMSG_RTRID_UPDATE: |
452 | memcpy(&global.rtr_id, imsg.data, | |
453 | sizeof(global.rtr_id)); | |
454 | if (leconf->rtr_id.s_addr == INADDR_ANY) { | |
45a8eba9 | 455 | ldpe_reset_nbrs(AF_UNSPEC); |
eac6e3f0 RW |
456 | } |
457 | if_update_all(AF_UNSPEC); | |
458 | tnbr_update_all(AF_UNSPEC); | |
459 | break; | |
8429abe0 RW |
460 | case IMSG_RECONF_CONF: |
461 | if ((nconf = malloc(sizeof(struct ldpd_conf))) == | |
462 | NULL) | |
463 | fatal(NULL); | |
464 | memcpy(nconf, imsg.data, sizeof(struct ldpd_conf)); | |
465 | ||
7d3d7491 | 466 | RB_INIT(&nconf->iface_tree); |
7989cdba | 467 | RB_INIT(&nconf->tnbr_tree); |
76c4abd1 | 468 | RB_INIT(&nconf->nbrp_tree); |
90d7e7bd | 469 | RB_INIT(&nconf->l2vpn_tree); |
8429abe0 RW |
470 | break; |
471 | case IMSG_RECONF_IFACE: | |
472 | if ((niface = malloc(sizeof(struct iface))) == NULL) | |
473 | fatal(NULL); | |
474 | memcpy(niface, imsg.data, sizeof(struct iface)); | |
475 | ||
7d3d7491 | 476 | RB_INSERT(iface_head, &nconf->iface_tree, niface); |
8429abe0 RW |
477 | break; |
478 | case IMSG_RECONF_TNBR: | |
479 | if ((ntnbr = malloc(sizeof(struct tnbr))) == NULL) | |
480 | fatal(NULL); | |
481 | memcpy(ntnbr, imsg.data, sizeof(struct tnbr)); | |
482 | ||
7989cdba | 483 | RB_INSERT(tnbr_head, &nconf->tnbr_tree, ntnbr); |
8429abe0 RW |
484 | break; |
485 | case IMSG_RECONF_NBRP: | |
486 | if ((nnbrp = malloc(sizeof(struct nbr_params))) == NULL) | |
487 | fatal(NULL); | |
488 | memcpy(nnbrp, imsg.data, sizeof(struct nbr_params)); | |
489 | ||
76c4abd1 | 490 | RB_INSERT(nbrp_head, &nconf->nbrp_tree, nnbrp); |
8429abe0 RW |
491 | break; |
492 | case IMSG_RECONF_L2VPN: | |
493 | if ((nl2vpn = malloc(sizeof(struct l2vpn))) == NULL) | |
494 | fatal(NULL); | |
495 | memcpy(nl2vpn, imsg.data, sizeof(struct l2vpn)); | |
496 | ||
029c1958 | 497 | RB_INIT(&nl2vpn->if_tree); |
20bacaeb RW |
498 | RB_INIT(&nl2vpn->pw_tree); |
499 | RB_INIT(&nl2vpn->pw_inactive_tree); | |
8429abe0 | 500 | |
90d7e7bd | 501 | RB_INSERT(l2vpn_head, &nconf->l2vpn_tree, nl2vpn); |
8429abe0 RW |
502 | break; |
503 | case IMSG_RECONF_L2VPN_IF: | |
504 | if ((nlif = malloc(sizeof(struct l2vpn_if))) == NULL) | |
505 | fatal(NULL); | |
506 | memcpy(nlif, imsg.data, sizeof(struct l2vpn_if)); | |
507 | ||
029c1958 | 508 | RB_INSERT(l2vpn_if_head, &nl2vpn->if_tree, nlif); |
8429abe0 RW |
509 | break; |
510 | case IMSG_RECONF_L2VPN_PW: | |
511 | if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL) | |
512 | fatal(NULL); | |
513 | memcpy(npw, imsg.data, sizeof(struct l2vpn_pw)); | |
514 | ||
20bacaeb | 515 | RB_INSERT(l2vpn_pw_head, &nl2vpn->pw_tree, npw); |
8429abe0 | 516 | break; |
eac6e3f0 RW |
517 | case IMSG_RECONF_L2VPN_IPW: |
518 | if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL) | |
519 | fatal(NULL); | |
520 | memcpy(npw, imsg.data, sizeof(struct l2vpn_pw)); | |
521 | ||
20bacaeb | 522 | RB_INSERT(l2vpn_pw_head, &nl2vpn->pw_inactive_tree, npw); |
eac6e3f0 | 523 | break; |
8429abe0 RW |
524 | case IMSG_RECONF_END: |
525 | merge_config(leconf, nconf); | |
1d75a89d | 526 | ldp_clear_config(nconf); |
8429abe0 RW |
527 | nconf = NULL; |
528 | global.conf_seqnum++; | |
529 | break; | |
8429abe0 RW |
530 | case IMSG_CTL_END: |
531 | control_imsg_relay(&imsg); | |
532 | break; | |
eac6e3f0 RW |
533 | case IMSG_DEBUG_UPDATE: |
534 | if (imsg.hdr.len != IMSG_HEADER_SIZE + | |
535 | sizeof(ldp_debug)) { | |
536 | log_warnx("%s: wrong imsg len", __func__); | |
537 | break; | |
538 | } | |
539 | memcpy(&ldp_debug, imsg.data, sizeof(ldp_debug)); | |
540 | break; | |
8429abe0 RW |
541 | default: |
542 | log_debug("ldpe_dispatch_main: error handling imsg %d", | |
543 | imsg.hdr.type); | |
544 | break; | |
545 | } | |
546 | imsg_free(&imsg); | |
547 | } | |
548 | if (!shut) | |
549 | imsg_event_add(iev); | |
550 | else { | |
eac6e3f0 RW |
551 | /* this pipe is dead, so remove the event handlers and exit */ |
552 | THREAD_READ_OFF(iev->ev_read); | |
553 | THREAD_WRITE_OFF(iev->ev_write); | |
554 | ldpe_shutdown(); | |
8429abe0 | 555 | } |
eac6e3f0 RW |
556 | |
557 | return (0); | |
8429abe0 RW |
558 | } |
559 | ||
560 | /* ARGSUSED */ | |
eac6e3f0 RW |
561 | static int |
562 | ldpe_dispatch_lde(struct thread *thread) | |
8429abe0 | 563 | { |
eac6e3f0 | 564 | struct imsgev *iev = THREAD_ARG(thread); |
8429abe0 RW |
565 | struct imsgbuf *ibuf = &iev->ibuf; |
566 | struct imsg imsg; | |
236c6935 RW |
567 | struct map *map; |
568 | struct notify_msg *nm; | |
569 | struct nbr *nbr; | |
8429abe0 | 570 | int n, shut = 0; |
8429abe0 | 571 | |
eac6e3f0 RW |
572 | iev->ev_read = NULL; |
573 | ||
574 | if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) | |
575 | fatal("imsg_read error"); | |
576 | if (n == 0) /* connection closed */ | |
577 | shut = 1; | |
8429abe0 RW |
578 | |
579 | for (;;) { | |
580 | if ((n = imsg_get(ibuf, &imsg)) == -1) | |
581 | fatal("ldpe_dispatch_lde: imsg_get error"); | |
582 | if (n == 0) | |
583 | break; | |
584 | ||
585 | switch (imsg.hdr.type) { | |
586 | case IMSG_MAPPING_ADD: | |
587 | case IMSG_RELEASE_ADD: | |
588 | case IMSG_REQUEST_ADD: | |
589 | case IMSG_WITHDRAW_ADD: | |
236c6935 RW |
590 | if (imsg.hdr.len - IMSG_HEADER_SIZE != |
591 | sizeof(struct map)) | |
8429abe0 | 592 | fatalx("invalid size of map request"); |
236c6935 | 593 | map = imsg.data; |
8429abe0 RW |
594 | |
595 | nbr = nbr_find_peerid(imsg.hdr.peerid); | |
596 | if (nbr == NULL) { | |
597 | log_debug("ldpe_dispatch_lde: cannot find " | |
598 | "neighbor"); | |
599 | break; | |
600 | } | |
601 | if (nbr->state != NBR_STA_OPER) | |
602 | break; | |
603 | ||
604 | switch (imsg.hdr.type) { | |
605 | case IMSG_MAPPING_ADD: | |
236c6935 | 606 | mapping_list_add(&nbr->mapping_list, map); |
8429abe0 RW |
607 | break; |
608 | case IMSG_RELEASE_ADD: | |
236c6935 | 609 | mapping_list_add(&nbr->release_list, map); |
8429abe0 RW |
610 | break; |
611 | case IMSG_REQUEST_ADD: | |
236c6935 | 612 | mapping_list_add(&nbr->request_list, map); |
8429abe0 RW |
613 | break; |
614 | case IMSG_WITHDRAW_ADD: | |
236c6935 | 615 | mapping_list_add(&nbr->withdraw_list, map); |
8429abe0 RW |
616 | break; |
617 | } | |
618 | break; | |
619 | case IMSG_MAPPING_ADD_END: | |
620 | case IMSG_RELEASE_ADD_END: | |
621 | case IMSG_REQUEST_ADD_END: | |
622 | case IMSG_WITHDRAW_ADD_END: | |
623 | nbr = nbr_find_peerid(imsg.hdr.peerid); | |
624 | if (nbr == NULL) { | |
625 | log_debug("ldpe_dispatch_lde: cannot find " | |
626 | "neighbor"); | |
627 | break; | |
628 | } | |
629 | if (nbr->state != NBR_STA_OPER) | |
630 | break; | |
631 | ||
632 | switch (imsg.hdr.type) { | |
633 | case IMSG_MAPPING_ADD_END: | |
634 | send_labelmessage(nbr, MSG_TYPE_LABELMAPPING, | |
635 | &nbr->mapping_list); | |
636 | break; | |
637 | case IMSG_RELEASE_ADD_END: | |
638 | send_labelmessage(nbr, MSG_TYPE_LABELRELEASE, | |
639 | &nbr->release_list); | |
640 | break; | |
641 | case IMSG_REQUEST_ADD_END: | |
642 | send_labelmessage(nbr, MSG_TYPE_LABELREQUEST, | |
643 | &nbr->request_list); | |
644 | break; | |
645 | case IMSG_WITHDRAW_ADD_END: | |
646 | send_labelmessage(nbr, MSG_TYPE_LABELWITHDRAW, | |
647 | &nbr->withdraw_list); | |
648 | break; | |
649 | } | |
650 | break; | |
651 | case IMSG_NOTIFICATION_SEND: | |
236c6935 RW |
652 | if (imsg.hdr.len - IMSG_HEADER_SIZE != |
653 | sizeof(struct notify_msg)) | |
8429abe0 | 654 | fatalx("invalid size of OE request"); |
236c6935 | 655 | nm = imsg.data; |
8429abe0 RW |
656 | |
657 | nbr = nbr_find_peerid(imsg.hdr.peerid); | |
658 | if (nbr == NULL) { | |
659 | log_debug("ldpe_dispatch_lde: cannot find " | |
660 | "neighbor"); | |
661 | break; | |
662 | } | |
663 | if (nbr->state != NBR_STA_OPER) | |
664 | break; | |
665 | ||
236c6935 | 666 | send_notification_full(nbr->tcp, nm); |
8429abe0 RW |
667 | break; |
668 | case IMSG_CTL_END: | |
0f7b5df9 RW |
669 | case IMSG_CTL_SHOW_LIB_BEGIN: |
670 | case IMSG_CTL_SHOW_LIB_RCVD: | |
671 | case IMSG_CTL_SHOW_LIB_SENT: | |
672 | case IMSG_CTL_SHOW_LIB_END: | |
8429abe0 RW |
673 | case IMSG_CTL_SHOW_L2VPN_PW: |
674 | case IMSG_CTL_SHOW_L2VPN_BINDING: | |
675 | control_imsg_relay(&imsg); | |
676 | break; | |
677 | default: | |
678 | log_debug("ldpe_dispatch_lde: error handling imsg %d", | |
679 | imsg.hdr.type); | |
680 | break; | |
681 | } | |
682 | imsg_free(&imsg); | |
683 | } | |
684 | if (!shut) | |
685 | imsg_event_add(iev); | |
686 | else { | |
eac6e3f0 RW |
687 | /* this pipe is dead, so remove the event handlers and exit */ |
688 | THREAD_READ_OFF(iev->ev_read); | |
689 | THREAD_WRITE_OFF(iev->ev_write); | |
690 | ldpe_shutdown(); | |
8429abe0 | 691 | } |
eac6e3f0 RW |
692 | |
693 | return (0); | |
8429abe0 RW |
694 | } |
695 | ||
eac6e3f0 | 696 | #ifdef __OpenBSD__ |
8429abe0 | 697 | /* ARGSUSED */ |
eac6e3f0 RW |
698 | static int |
699 | ldpe_dispatch_pfkey(struct thread *thread) | |
8429abe0 | 700 | { |
eac6e3f0 RW |
701 | int fd = THREAD_FD(thread); |
702 | ||
703 | pfkey_ev = thread_add_read(master, ldpe_dispatch_pfkey, | |
704 | NULL, global.pfkeysock); | |
705 | ||
706 | if (pfkey_read(fd, NULL) == -1) | |
707 | fatal("pfkey_read failed, exiting..."); | |
708 | ||
709 | return (0); | |
8429abe0 | 710 | } |
eac6e3f0 | 711 | #endif /* __OpenBSD__ */ |
8429abe0 RW |
712 | |
713 | static void | |
714 | ldpe_setup_sockets(int af, int disc_socket, int edisc_socket, | |
715 | int session_socket) | |
716 | { | |
717 | struct ldpd_af_global *af_global; | |
718 | ||
719 | af_global = ldp_af_global_get(&global, af); | |
720 | ||
721 | /* discovery socket */ | |
722 | af_global->ldp_disc_socket = disc_socket; | |
eac6e3f0 RW |
723 | af_global->disc_ev = thread_add_read(master, disc_recv_packet, |
724 | &af_global->disc_ev, af_global->ldp_disc_socket); | |
8429abe0 RW |
725 | |
726 | /* extended discovery socket */ | |
727 | af_global->ldp_edisc_socket = edisc_socket; | |
eac6e3f0 RW |
728 | af_global->edisc_ev = thread_add_read(master, disc_recv_packet, |
729 | &af_global->edisc_ev, af_global->ldp_edisc_socket); | |
8429abe0 RW |
730 | |
731 | /* session socket */ | |
732 | af_global->ldp_session_socket = session_socket; | |
733 | accept_add(af_global->ldp_session_socket, session_accept, NULL); | |
734 | } | |
735 | ||
736 | static void | |
737 | ldpe_close_sockets(int af) | |
738 | { | |
739 | struct ldpd_af_global *af_global; | |
740 | ||
741 | af_global = ldp_af_global_get(&global, af); | |
742 | ||
743 | /* discovery socket */ | |
eac6e3f0 | 744 | THREAD_READ_OFF(af_global->disc_ev); |
8429abe0 RW |
745 | if (af_global->ldp_disc_socket != -1) { |
746 | close(af_global->ldp_disc_socket); | |
747 | af_global->ldp_disc_socket = -1; | |
748 | } | |
749 | ||
750 | /* extended discovery socket */ | |
eac6e3f0 | 751 | THREAD_READ_OFF(af_global->edisc_ev); |
8429abe0 RW |
752 | if (af_global->ldp_edisc_socket != -1) { |
753 | close(af_global->ldp_edisc_socket); | |
754 | af_global->ldp_edisc_socket = -1; | |
755 | } | |
756 | ||
757 | /* session socket */ | |
758 | if (af_global->ldp_session_socket != -1) { | |
759 | accept_del(af_global->ldp_session_socket); | |
760 | close(af_global->ldp_session_socket); | |
761 | af_global->ldp_session_socket = -1; | |
762 | } | |
763 | } | |
764 | ||
45a8eba9 RW |
765 | int |
766 | ldpe_acl_check(char *acl_name, int af, union ldpd_addr *addr, uint8_t prefixlen) | |
767 | { | |
768 | return ldp_acl_request(iev_main_sync, acl_name, af, addr, prefixlen); | |
769 | } | |
770 | ||
8429abe0 RW |
771 | void |
772 | ldpe_reset_nbrs(int af) | |
773 | { | |
774 | struct nbr *nbr; | |
775 | ||
776 | RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { | |
45a8eba9 | 777 | if (af == AF_UNSPEC || nbr->af == af) |
8429abe0 RW |
778 | session_shutdown(nbr, S_SHUTDOWN, 0, 0); |
779 | } | |
780 | } | |
781 | ||
782 | void | |
783 | ldpe_reset_ds_nbrs(void) | |
784 | { | |
785 | struct nbr *nbr; | |
786 | ||
787 | RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { | |
788 | if (nbr->ds_tlv) | |
789 | session_shutdown(nbr, S_SHUTDOWN, 0, 0); | |
790 | } | |
791 | } | |
792 | ||
793 | void | |
794 | ldpe_remove_dynamic_tnbrs(int af) | |
795 | { | |
796 | struct tnbr *tnbr, *safe; | |
797 | ||
7989cdba | 798 | RB_FOREACH_SAFE(tnbr, tnbr_head, &leconf->tnbr_tree, safe) { |
8429abe0 RW |
799 | if (tnbr->af != af) |
800 | continue; | |
801 | ||
802 | tnbr->flags &= ~F_TNBR_DYNAMIC; | |
7989cdba | 803 | tnbr_check(leconf, tnbr); |
8429abe0 RW |
804 | } |
805 | } | |
806 | ||
807 | void | |
808 | ldpe_stop_init_backoff(int af) | |
809 | { | |
810 | struct nbr *nbr; | |
811 | ||
812 | RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { | |
813 | if (nbr->af == af && nbr_pending_idtimer(nbr)) { | |
814 | nbr_stop_idtimer(nbr); | |
815 | nbr_establish_connection(nbr); | |
816 | } | |
817 | } | |
818 | } | |
819 | ||
820 | static void | |
821 | ldpe_iface_af_ctl(struct ctl_conn *c, int af, unsigned int idx) | |
822 | { | |
823 | struct iface *iface; | |
824 | struct iface_af *ia; | |
825 | struct ctl_iface *ictl; | |
826 | ||
7d3d7491 | 827 | RB_FOREACH(iface, iface_head, &leconf->iface_tree) { |
8429abe0 RW |
828 | if (idx == 0 || idx == iface->ifindex) { |
829 | ia = iface_af_get(iface, af); | |
830 | if (!ia->enabled) | |
831 | continue; | |
832 | ||
833 | ictl = if_to_ctl(ia); | |
05aac414 | 834 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_INTERFACE, |
8429abe0 RW |
835 | 0, 0, -1, ictl, sizeof(struct ctl_iface)); |
836 | } | |
837 | } | |
838 | } | |
839 | ||
840 | void | |
841 | ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx) | |
842 | { | |
843 | ldpe_iface_af_ctl(c, AF_INET, idx); | |
844 | ldpe_iface_af_ctl(c, AF_INET6, idx); | |
845 | } | |
846 | ||
847 | void | |
848 | ldpe_adj_ctl(struct ctl_conn *c) | |
bc0eb287 RW |
849 | { |
850 | struct adj *adj; | |
851 | struct ctl_adj *actl; | |
852 | ||
853 | RB_FOREACH(adj, global_adj_head, &global.adj_tree) { | |
854 | actl = adj_to_ctl(adj); | |
855 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0, | |
856 | -1, actl, sizeof(struct ctl_adj)); | |
857 | } | |
858 | ||
859 | imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); | |
860 | } | |
861 | ||
862 | void | |
863 | ldpe_adj_detail_ctl(struct ctl_conn *c) | |
8429abe0 | 864 | { |
eac6e3f0 RW |
865 | struct iface *iface; |
866 | struct tnbr *tnbr; | |
867 | struct adj *adj; | |
868 | struct ctl_adj *actl; | |
869 | struct ctl_disc_if ictl; | |
870 | struct ctl_disc_tnbr tctl; | |
8429abe0 | 871 | |
eac6e3f0 RW |
872 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0); |
873 | ||
7d3d7491 | 874 | RB_FOREACH(iface, iface_head, &leconf->iface_tree) { |
eac6e3f0 RW |
875 | memset(&ictl, 0, sizeof(ictl)); |
876 | ictl.active_v4 = (iface->ipv4.state == IF_STA_ACTIVE); | |
877 | ictl.active_v6 = (iface->ipv6.state == IF_STA_ACTIVE); | |
878 | ||
879 | if (!ictl.active_v4 && !ictl.active_v6) | |
880 | continue; | |
881 | ||
882 | strlcpy(ictl.name, iface->name, sizeof(ictl.name)); | |
057d48bd RW |
883 | if (RB_EMPTY(&iface->ipv4.adj_tree) && |
884 | RB_EMPTY(&iface->ipv6.adj_tree)) | |
eac6e3f0 RW |
885 | ictl.no_adj = 1; |
886 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_IFACE, 0, 0, | |
887 | -1, &ictl, sizeof(ictl)); | |
888 | ||
057d48bd | 889 | RB_FOREACH(adj, ia_adj_head, &iface->ipv4.adj_tree) { |
8429abe0 | 890 | actl = adj_to_ctl(adj); |
eac6e3f0 RW |
891 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_ADJ, |
892 | 0, 0, -1, actl, sizeof(struct ctl_adj)); | |
893 | } | |
057d48bd | 894 | RB_FOREACH(adj, ia_adj_head, &iface->ipv6.adj_tree) { |
eac6e3f0 RW |
895 | actl = adj_to_ctl(adj); |
896 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_ADJ, | |
8429abe0 RW |
897 | 0, 0, -1, actl, sizeof(struct ctl_adj)); |
898 | } | |
899 | } | |
eac6e3f0 | 900 | |
7989cdba | 901 | RB_FOREACH(tnbr, tnbr_head, &leconf->tnbr_tree) { |
eac6e3f0 RW |
902 | memset(&tctl, 0, sizeof(tctl)); |
903 | tctl.af = tnbr->af; | |
904 | tctl.addr = tnbr->addr; | |
905 | if (tnbr->adj == NULL) | |
906 | tctl.no_adj = 1; | |
907 | ||
908 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_TNBR, 0, 0, | |
909 | -1, &tctl, sizeof(tctl)); | |
910 | ||
911 | if (tnbr->adj == NULL) | |
8429abe0 RW |
912 | continue; |
913 | ||
eac6e3f0 RW |
914 | actl = adj_to_ctl(tnbr->adj); |
915 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_ADJ, 0, 0, | |
8429abe0 RW |
916 | -1, actl, sizeof(struct ctl_adj)); |
917 | } | |
918 | ||
919 | imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); | |
920 | } | |
921 | ||
922 | void | |
923 | ldpe_nbr_ctl(struct ctl_conn *c) | |
924 | { | |
eac6e3f0 RW |
925 | struct adj *adj; |
926 | struct ctl_adj *actl; | |
8429abe0 RW |
927 | struct nbr *nbr; |
928 | struct ctl_nbr *nctl; | |
929 | ||
930 | RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) { | |
eac6e3f0 RW |
931 | if (nbr->state == NBR_STA_PRESENT) |
932 | continue; | |
933 | ||
8429abe0 RW |
934 | nctl = nbr_to_ctl(nbr); |
935 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl, | |
936 | sizeof(struct ctl_nbr)); | |
eac6e3f0 | 937 | |
057d48bd | 938 | RB_FOREACH(adj, nbr_adj_head, &nbr->adj_tree) { |
eac6e3f0 RW |
939 | actl = adj_to_ctl(adj); |
940 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR_DISC, | |
941 | 0, 0, -1, actl, sizeof(struct ctl_adj)); | |
942 | } | |
943 | ||
944 | imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR_END, 0, 0, -1, | |
945 | NULL, 0); | |
8429abe0 RW |
946 | } |
947 | imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); | |
948 | } | |
949 | ||
950 | void | |
951 | mapping_list_add(struct mapping_head *mh, struct map *map) | |
952 | { | |
953 | struct mapping_entry *me; | |
954 | ||
955 | me = calloc(1, sizeof(*me)); | |
956 | if (me == NULL) | |
957 | fatal(__func__); | |
958 | me->map = *map; | |
959 | ||
960 | TAILQ_INSERT_TAIL(mh, me, entry); | |
961 | } | |
962 | ||
963 | void | |
964 | mapping_list_clr(struct mapping_head *mh) | |
965 | { | |
966 | struct mapping_entry *me; | |
967 | ||
968 | while ((me = TAILQ_FIRST(mh)) != NULL) { | |
969 | TAILQ_REMOVE(mh, me, entry); | |
970 | free(me); | |
971 | } | |
972 | } |