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