xref: /openbsd-src/usr.sbin/bgpd/bgpd.c (revision 3a99c822f73d6d86da6f9b890c7203b41725ec27)
1*3a99c822Sclaudio /*	$OpenBSD: bgpd.c,v 1.280 2024/12/03 13:46:53 claudio Exp $ */
2a16c0992Shenning 
3a16c0992Shenning /*
4050527e1Shenning  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5a16c0992Shenning  *
6a16c0992Shenning  * Permission to use, copy, modify, and distribute this software for any
7a16c0992Shenning  * purpose with or without fee is hereby granted, provided that the above
8a16c0992Shenning  * copyright notice and this permission notice appear in all copies.
9a16c0992Shenning  *
10a16c0992Shenning  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a16c0992Shenning  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a16c0992Shenning  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a16c0992Shenning  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a16c0992Shenning  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a16c0992Shenning  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a16c0992Shenning  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a16c0992Shenning  */
18a16c0992Shenning 
19a16c0992Shenning #include <sys/types.h>
20a16c0992Shenning #include <sys/socket.h>
21348731e4Shenning #include <sys/wait.h>
22a16c0992Shenning #include <netinet/in.h>
23f7421e07Sjob #include <netinet/ip.h>
24f7421e07Sjob #include <netinet/tcp.h>
25a16c0992Shenning #include <arpa/inet.h>
26a16c0992Shenning #include <err.h>
27a16c0992Shenning #include <errno.h>
28a16c0992Shenning #include <fcntl.h>
29a16c0992Shenning #include <poll.h>
30b1c91f4fShenning #include <pwd.h>
31a16c0992Shenning #include <signal.h>
32ff84f55eSclaudio #include <stddef.h>
33a16c0992Shenning #include <stdio.h>
34a16c0992Shenning #include <stdlib.h>
35a16c0992Shenning #include <string.h>
365e3f6f95Sbenno #include <syslog.h>
37a16c0992Shenning #include <unistd.h>
38a16c0992Shenning 
39a16c0992Shenning #include "bgpd.h"
409d3ea286Shenning #include "session.h"
415e3f6f95Sbenno #include "log.h"
423eb1af85Sjob #include "version.h"
43a16c0992Shenning 
44a16c0992Shenning void		sighdlr(int);
45cbb557dbShenning __dead void	usage(void);
46a16c0992Shenning int		main(int, char *[]);
4713ff36d2Sclaudio pid_t		start_child(enum bgpd_process, char *, int, int, int);
487910aaa2Sclaudio int		send_filterset(struct imsgbuf *, struct filter_set_head *);
4982fc6237Sclaudio int		reconfigure(char *, struct bgpd_config *);
50bf3956d0Sclaudio int		send_config(struct bgpd_config *);
51178e089aSflorian int		dispatch_imsg(struct imsgbuf *, int, struct bgpd_config *);
521daa807cSclaudio int		control_setup(struct bgpd_config *);
53e8beb5b5Sclaudio static void	getsockpair(int [2]);
54bd9df44eSclaudio int		imsg_send_sockets(struct imsgbuf *, struct imsgbuf *,
55bd9df44eSclaudio 		    struct imsgbuf *);
56cd16358eSclaudio void		bgpd_rtr_conn_setup(struct rtr_config *);
57cd16358eSclaudio void		bgpd_rtr_conn_setup_done(int, struct bgpd_config *);
58cd16358eSclaudio void		bgpd_rtr_conn_teardown(uint32_t);
59a16c0992Shenning 
60610bcb44Sclaudio int			 cflags;
61610bcb44Sclaudio volatile sig_atomic_t	 mrtdump;
62610bcb44Sclaudio volatile sig_atomic_t	 quit;
63610bcb44Sclaudio volatile sig_atomic_t	 reconfig;
64610bcb44Sclaudio pid_t			 reconfpid;
658a2bb8d5Sclaudio int			 reconfpending;
6600f90be3Shenning struct imsgbuf		*ibuf_se;
6700f90be3Shenning struct imsgbuf		*ibuf_rde;
68bd9df44eSclaudio struct imsgbuf		*ibuf_rtr;
69da23cf14Sclaudio struct rib_names	 ribnames = SIMPLEQ_HEAD_INITIALIZER(ribnames);
701daa807cSclaudio char			*cname;
711daa807cSclaudio char			*rcname;
72a16c0992Shenning 
73571b47daSclaudio struct connect_elm {
74571b47daSclaudio 	TAILQ_ENTRY(connect_elm)	entry;
75cd16358eSclaudio 	struct auth_state		auth_state;
7639386878Sclaudio 	uint32_t			id;
77571b47daSclaudio 	int				fd;
78571b47daSclaudio };
79571b47daSclaudio 
80571b47daSclaudio TAILQ_HEAD(, connect_elm)	connect_queue = \
81cd16358eSclaudio 				    TAILQ_HEAD_INITIALIZER(connect_queue),
82cd16358eSclaudio 				socket_queue = \
83cd16358eSclaudio 				    TAILQ_HEAD_INITIALIZER(socket_queue);
84571b47daSclaudio u_int				connect_cnt;
857bb4de2bSclaudio #define MAX_CONNECT_CNT		32
86571b47daSclaudio 
87a16c0992Shenning void
88a16c0992Shenning sighdlr(int sig)
89a16c0992Shenning {
90a16c0992Shenning 	switch (sig) {
91a16c0992Shenning 	case SIGTERM:
92a16c0992Shenning 	case SIGINT:
930e5579dbShenning 		quit = 1;
94a16c0992Shenning 		break;
95a16c0992Shenning 	case SIGHUP:
96a16c0992Shenning 		reconfig = 1;
97a16c0992Shenning 		break;
98a16c0992Shenning 	case SIGALRM:
99a16c0992Shenning 	case SIGUSR1:
1002a51171bSclaudio 		mrtdump = 1;
101a16c0992Shenning 		break;
102a16c0992Shenning 	}
103a16c0992Shenning }
104a16c0992Shenning 
105cbb557dbShenning __dead void
106a16c0992Shenning usage(void)
107a16c0992Shenning {
108a16c0992Shenning 	extern char *__progname;
109a16c0992Shenning 
110ad2baa1aSclaudio 	fprintf(stderr, "usage: %s [-cdnvV] [-D macro=value] [-f file]\n",
11171e275dfSsobrado 	    __progname);
112a16c0992Shenning 	exit(1);
113a16c0992Shenning }
114a16c0992Shenning 
115a16c0992Shenning #define PFD_PIPE_SESSION	0
116dfda3de3Sclaudio #define PFD_PIPE_RDE		1
117bd9df44eSclaudio #define PFD_PIPE_RTR		2
118bd9df44eSclaudio #define PFD_SOCK_ROUTE		3
119bd9df44eSclaudio #define PFD_SOCK_PFKEY		4
120571b47daSclaudio #define PFD_CONNECT_START	5
1213ac41105Sclaudio #define MAX_TIMEOUT		3600
122a16c0992Shenning 
12339229b69Sclaudio int	 cmd_opts;
12439229b69Sclaudio 
125a16c0992Shenning int
126a16c0992Shenning main(int argc, char *argv[])
127a16c0992Shenning {
128d288d268Sclaudio 	struct bgpd_config	*conf;
129dfda3de3Sclaudio 	enum bgpd_process	 proc = PROC_MAIN;
130e8d21d8aSclaudio 	struct rde_rib		*rr;
131c2bef38bSclaudio 	struct peer		*p;
132571b47daSclaudio 	struct pollfd		*pfd = NULL;
133571b47daSclaudio 	struct connect_elm	*ce;
134b673e165Sclaudio 	time_t			 timeout;
135bd9df44eSclaudio 	pid_t			 se_pid = 0, rde_pid = 0, rtr_pid = 0, pid;
136a16c0992Shenning 	char			*conffile;
13713ff36d2Sclaudio 	char			*saved_argv0;
138571b47daSclaudio 	u_int			 pfd_elms = 0, npfd, i;
139a16c0992Shenning 	int			 debug = 0;
140c2bef38bSclaudio 	int			 rfd, keyfd;
141b673e165Sclaudio 	int			 ch, status;
142a16c0992Shenning 	int			 pipe_m2s[2];
143a16c0992Shenning 	int			 pipe_m2r[2];
144bd9df44eSclaudio 	int			 pipe_m2roa[2];
145a16c0992Shenning 
146a16c0992Shenning 	conffile = CONFFILE;
147a16c0992Shenning 
1485e3f6f95Sbenno 	log_init(1, LOG_DAEMON);	/* log to stderr until daemonized */
1494bd13066Sclaudio 	log_procinit(log_procnames[PROC_MAIN]);
1505e3f6f95Sbenno 	log_setverbose(1);
151a16c0992Shenning 
15213ff36d2Sclaudio 	saved_argv0 = argv[0];
15313ff36d2Sclaudio 	if (saved_argv0 == NULL)
15413ff36d2Sclaudio 		saved_argv0 = "bgpd";
15513ff36d2Sclaudio 
1563eb1af85Sjob 	while ((ch = getopt(argc, argv, "cdD:f:nRSTvV")) != -1) {
157a16c0992Shenning 		switch (ch) {
1587f5c1560Shenning 		case 'c':
15939229b69Sclaudio 			cmd_opts |= BGPD_OPT_FORCE_DEMOTE;
1607f5c1560Shenning 			break;
161a16c0992Shenning 		case 'd':
162a16c0992Shenning 			debug = 1;
163a16c0992Shenning 			break;
164a16c0992Shenning 		case 'D':
165a16c0992Shenning 			if (cmdline_symset(optarg) < 0)
166553e6efdShenning 				log_warnx("could not parse macro definition %s",
167a16c0992Shenning 				    optarg);
168a16c0992Shenning 			break;
169a16c0992Shenning 		case 'f':
170a16c0992Shenning 			conffile = optarg;
171a16c0992Shenning 			break;
172ea5db239Shenning 		case 'n':
17339229b69Sclaudio 			cmd_opts |= BGPD_OPT_NOACTION;
174ea5db239Shenning 			break;
175a16c0992Shenning 		case 'v':
17639229b69Sclaudio 			if (cmd_opts & BGPD_OPT_VERBOSE)
17739229b69Sclaudio 				cmd_opts |= BGPD_OPT_VERBOSE2;
17839229b69Sclaudio 			cmd_opts |= BGPD_OPT_VERBOSE;
179a16c0992Shenning 			break;
18013ff36d2Sclaudio 		case 'R':
181dfda3de3Sclaudio 			proc = PROC_RDE;
18213ff36d2Sclaudio 			break;
18313ff36d2Sclaudio 		case 'S':
184dfda3de3Sclaudio 			proc = PROC_SE;
18513ff36d2Sclaudio 			break;
186bd9df44eSclaudio 		case 'T':
187bd9df44eSclaudio 			proc = PROC_RTR;
188bd9df44eSclaudio 			break;
1893eb1af85Sjob 		case 'V':
1903eb1af85Sjob 			fprintf(stderr, "OpenBGPD %s\n", BGPD_VERSION);
1913eb1af85Sjob 			return 0;
192a16c0992Shenning 		default:
193a16c0992Shenning 			usage();
194a16c0992Shenning 			/* NOTREACHED */
195a16c0992Shenning 		}
196a16c0992Shenning 	}
197a16c0992Shenning 
198fde55bc4Spyr 	argc -= optind;
199fde55bc4Spyr 	argv += optind;
200dfda3de3Sclaudio 	if (argc > 0)
201fde55bc4Spyr 		usage();
202fde55bc4Spyr 
20339229b69Sclaudio 	if (cmd_opts & BGPD_OPT_NOACTION) {
204bd9df44eSclaudio 		if ((conf = parse_config(conffile, NULL, NULL)) == NULL)
205113167adShenning 			exit(1);
206a16c0992Shenning 
20739229b69Sclaudio 		if (cmd_opts & BGPD_OPT_VERBOSE)
20882fc6237Sclaudio 			print_config(conf, &ribnames);
209ed0f4decShenning 		else
210ea5db239Shenning 			fprintf(stderr, "configuration OK\n");
211e8d21d8aSclaudio 
212e8d21d8aSclaudio 		while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) {
213e8d21d8aSclaudio 			SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
214e8d21d8aSclaudio 			free(rr);
215e8d21d8aSclaudio 		}
216e8d21d8aSclaudio 		free_config(conf);
217ea5db239Shenning 		exit(0);
218ea5db239Shenning 	}
219ea5db239Shenning 
220dfda3de3Sclaudio 	switch (proc) {
221dfda3de3Sclaudio 	case PROC_MAIN:
222dfda3de3Sclaudio 		break;
223dfda3de3Sclaudio 	case PROC_RDE:
22413ff36d2Sclaudio 		rde_main(debug, cmd_opts & BGPD_OPT_VERBOSE);
225dfda3de3Sclaudio 		/* NOTREACHED */
226dfda3de3Sclaudio 	case PROC_SE:
22713ff36d2Sclaudio 		session_main(debug, cmd_opts & BGPD_OPT_VERBOSE);
228dfda3de3Sclaudio 		/* NOTREACHED */
229bd9df44eSclaudio 	case PROC_RTR:
230bd9df44eSclaudio 		rtr_main(debug, cmd_opts & BGPD_OPT_VERBOSE);
231bd9df44eSclaudio 		/* NOTREACHED */
232dfda3de3Sclaudio 	}
23313ff36d2Sclaudio 
234425e4d19Shenning 	if (geteuid())
235425e4d19Shenning 		errx(1, "need root privileges");
236425e4d19Shenning 
237b1c91f4fShenning 	if (getpwnam(BGPD_USER) == NULL)
238b1c91f4fShenning 		errx(1, "unknown user %s", BGPD_USER);
239b1c91f4fShenning 
240bd9df44eSclaudio 	if ((conf = parse_config(conffile, NULL, NULL)) == NULL) {
241bf3956d0Sclaudio 		log_warnx("config file %s has errors", conffile);
242bf3956d0Sclaudio 		exit(1);
243bf3956d0Sclaudio 	}
244bf3956d0Sclaudio 
245bf3956d0Sclaudio 	if (prepare_listeners(conf) == -1)
246bf3956d0Sclaudio 		exit(1);
247bf3956d0Sclaudio 
2485e3f6f95Sbenno 	log_init(debug, LOG_DAEMON);
2495e3f6f95Sbenno 	log_setverbose(cmd_opts & BGPD_OPT_VERBOSE);
250a16c0992Shenning 
251a16c0992Shenning 	if (!debug)
252a16c0992Shenning 		daemon(1, 0);
253a16c0992Shenning 
254553e6efdShenning 	log_info("startup");
255a16c0992Shenning 
256e8beb5b5Sclaudio 	getsockpair(pipe_m2s);
257e8beb5b5Sclaudio 	getsockpair(pipe_m2r);
258bd9df44eSclaudio 	getsockpair(pipe_m2roa);
259a16c0992Shenning 
260fb228fc3Shenning 	/* fork children */
26113ff36d2Sclaudio 	rde_pid = start_child(PROC_RDE, saved_argv0, pipe_m2r[1], debug,
26213ff36d2Sclaudio 	    cmd_opts & BGPD_OPT_VERBOSE);
2631d32dc34Sbcook 	se_pid = start_child(PROC_SE, saved_argv0, pipe_m2s[1], debug,
26413ff36d2Sclaudio 	    cmd_opts & BGPD_OPT_VERBOSE);
265bd9df44eSclaudio 	rtr_pid = start_child(PROC_RTR, saved_argv0, pipe_m2roa[1], debug,
266bd9df44eSclaudio 	    cmd_opts & BGPD_OPT_VERBOSE);
267a16c0992Shenning 
2684ed49481Shenning 	signal(SIGTERM, sighdlr);
2694ed49481Shenning 	signal(SIGINT, sighdlr);
2704ed49481Shenning 	signal(SIGHUP, sighdlr);
2714ed49481Shenning 	signal(SIGALRM, sighdlr);
2724ed49481Shenning 	signal(SIGUSR1, sighdlr);
273ff5e9715Shenning 	signal(SIGPIPE, SIG_IGN);
2744ed49481Shenning 
27500f90be3Shenning 	if ((ibuf_se = malloc(sizeof(struct imsgbuf))) == NULL ||
276bd9df44eSclaudio 	    (ibuf_rde = malloc(sizeof(struct imsgbuf))) == NULL ||
277bd9df44eSclaudio 	    (ibuf_rtr = malloc(sizeof(struct imsgbuf))) == NULL)
27800f90be3Shenning 		fatal(NULL);
279f1b790a5Sclaudio 	if (imsgbuf_init(ibuf_se, pipe_m2s[0]) == -1 ||
28004e12482Sclaudio 	    imsgbuf_set_maxsize(ibuf_se, MAX_BGPD_IMSGSIZE) == -1 ||
281f1b790a5Sclaudio 	    imsgbuf_init(ibuf_rde, pipe_m2r[0]) == -1 ||
28204e12482Sclaudio 	    imsgbuf_set_maxsize(ibuf_rde, MAX_BGPD_IMSGSIZE) == -1 ||
28304e12482Sclaudio 	    imsgbuf_init(ibuf_rtr, pipe_m2roa[0]) == -1 ||
28404e12482Sclaudio 	    imsgbuf_set_maxsize(ibuf_rtr, MAX_BGPD_IMSGSIZE) == -1)
285f1b790a5Sclaudio 		fatal(NULL);
286f1b790a5Sclaudio 	imsgbuf_allow_fdpass(ibuf_se);
287f1b790a5Sclaudio 	imsgbuf_allow_fdpass(ibuf_rde);
288f1b790a5Sclaudio 	imsgbuf_allow_fdpass(ibuf_rtr);
28900f90be3Shenning 	mrt_init(ibuf_rde, ibuf_se);
290859a8563Sclaudio 	if (kr_init(&rfd, conf->fib_priority) == -1)
291791ad0e7Shenning 		quit = 1;
292c2bef38bSclaudio 	keyfd = pfkey_init();
2935621664bSbenno 
2945621664bSbenno 	/*
2955621664bSbenno 	 * rpath, read config file
2965621664bSbenno 	 * cpath, unlink control socket
2975621664bSbenno 	 * fattr, chmod on control socket
2985621664bSbenno 	 * wpath, needed if we are doing mrt dumps
2995621664bSbenno 	 *
3005621664bSbenno 	 * pledge placed here because kr_init() does a setsockopt on the
3015621664bSbenno 	 * routing socket thats not allowed at all.
3025621664bSbenno 	 */
30337aca3b7Sbenno #if 0
30437aca3b7Sbenno 	/*
30537aca3b7Sbenno 	 * disabled because we do ioctls on /dev/pf and SIOCSIFGATTR
30637aca3b7Sbenno 	 * this needs some redesign of bgpd to be fixed.
30737aca3b7Sbenno 	 */
308ae113753Sflorian BROKEN	if (pledge("stdio rpath wpath cpath fattr unix route recvfd sendfd",
30951512aa9Srenato 	    NULL) == -1)
3105621664bSbenno 		fatal("pledge");
31137aca3b7Sbenno #endif
3125621664bSbenno 
313bd9df44eSclaudio 	if (imsg_send_sockets(ibuf_se, ibuf_rde, ibuf_rtr))
31413ff36d2Sclaudio 		fatal("could not establish imsg links");
315bf3956d0Sclaudio 	/* control setup needs to happen late since it sends imsgs */
316bf3956d0Sclaudio 	if (control_setup(conf) == -1)
317bf3956d0Sclaudio 		quit = 1;
318bf3956d0Sclaudio 	if (send_config(conf) != 0)
319bf3956d0Sclaudio 		quit = 1;
320972b7d94Sdjm 	if (pftable_clear_all() != 0)
321972b7d94Sdjm 		quit = 1;
3223ac41105Sclaudio 
3230e5579dbShenning 	while (quit == 0) {
324571b47daSclaudio 		if (pfd_elms < PFD_CONNECT_START + connect_cnt) {
325571b47daSclaudio 			struct pollfd *newp;
326571b47daSclaudio 
327571b47daSclaudio 			if ((newp = reallocarray(pfd,
328571b47daSclaudio 			    PFD_CONNECT_START + connect_cnt,
329571b47daSclaudio 			    sizeof(struct pollfd))) == NULL) {
330571b47daSclaudio 				log_warn("could not resize pfd from %u -> %u"
331571b47daSclaudio 				    " entries", pfd_elms, PFD_CONNECT_START +
332571b47daSclaudio 				    connect_cnt);
333571b47daSclaudio 				fatalx("exiting");
334571b47daSclaudio 			}
335571b47daSclaudio 			pfd = newp;
336571b47daSclaudio 			pfd_elms = PFD_CONNECT_START + connect_cnt;
337571b47daSclaudio 		}
338eafe309eSclaudio 		memset(pfd, 0, sizeof(struct pollfd) * pfd_elms);
33913ff36d2Sclaudio 
34036a1d6a5Sclaudio 		timeout = mrt_timeout(conf->mrt);
34113ff36d2Sclaudio 
342405b6500Shenning 		pfd[PFD_SOCK_ROUTE].fd = rfd;
343405b6500Shenning 		pfd[PFD_SOCK_ROUTE].events = POLLIN;
344a16c0992Shenning 
345c2bef38bSclaudio 		pfd[PFD_SOCK_PFKEY].fd = keyfd;
346c2bef38bSclaudio 		pfd[PFD_SOCK_PFKEY].events = POLLIN;
347c2bef38bSclaudio 
34836a1d6a5Sclaudio 		set_pollfd(&pfd[PFD_PIPE_SESSION], ibuf_se);
349dfda3de3Sclaudio 		set_pollfd(&pfd[PFD_PIPE_RDE], ibuf_rde);
350bd9df44eSclaudio 		set_pollfd(&pfd[PFD_PIPE_RTR], ibuf_rtr);
3513ac41105Sclaudio 
352571b47daSclaudio 		npfd = PFD_CONNECT_START;
353571b47daSclaudio 		TAILQ_FOREACH(ce, &connect_queue, entry) {
354571b47daSclaudio 			pfd[npfd].fd = ce->fd;
355571b47daSclaudio 			pfd[npfd++].events = POLLOUT;
356571b47daSclaudio 			if (npfd > pfd_elms)
357571b47daSclaudio 				fatalx("polli pfd overflow");
358571b47daSclaudio 		}
359571b47daSclaudio 
360b673e165Sclaudio 		if (timeout < 0 || timeout > MAX_TIMEOUT)
361b673e165Sclaudio 			timeout = MAX_TIMEOUT;
362468ac036Sclaudio 		if (poll(pfd, npfd, timeout * 1000) == -1) {
363fb228fc3Shenning 			if (errno != EINTR) {
3648013a801Shenning 				log_warn("poll error");
365fb228fc3Shenning 				quit = 1;
366fb228fc3Shenning 			}
36762af2417Sclaudio 			goto next_loop;
368468ac036Sclaudio 		}
369a16c0992Shenning 
37013ff36d2Sclaudio 		if (handle_pollfd(&pfd[PFD_PIPE_SESSION], ibuf_se) == -1) {
371ed5bc85cSphessler 			log_warnx("main: Lost connection to SE");
3729cbf9e90Sclaudio 			imsgbuf_clear(ibuf_se);
37313ff36d2Sclaudio 			free(ibuf_se);
37413ff36d2Sclaudio 			ibuf_se = NULL;
37529ee8e11Sclaudio 			quit = 1;
37613ff36d2Sclaudio 		} else {
377d288d268Sclaudio 			if (dispatch_imsg(ibuf_se, PFD_PIPE_SESSION, conf) ==
378178e089aSflorian 			    -1)
37929ee8e11Sclaudio 				quit = 1;
38029ee8e11Sclaudio 		}
38129ee8e11Sclaudio 
382dfda3de3Sclaudio 		if (handle_pollfd(&pfd[PFD_PIPE_RDE], ibuf_rde) == -1) {
383ed5bc85cSphessler 			log_warnx("main: Lost connection to RDE");
3849cbf9e90Sclaudio 			imsgbuf_clear(ibuf_rde);
38513ff36d2Sclaudio 			free(ibuf_rde);
38613ff36d2Sclaudio 			ibuf_rde = NULL;
38713ff36d2Sclaudio 			quit = 1;
38813ff36d2Sclaudio 		} else {
389bd9df44eSclaudio 			if (dispatch_imsg(ibuf_rde, PFD_PIPE_RDE, conf) == -1)
390bd9df44eSclaudio 				quit = 1;
391bd9df44eSclaudio 		}
392bd9df44eSclaudio 
393bd9df44eSclaudio 		if (handle_pollfd(&pfd[PFD_PIPE_RTR], ibuf_rtr) == -1) {
394bd9df44eSclaudio 			log_warnx("main: Lost connection to RTR");
3959cbf9e90Sclaudio 			imsgbuf_clear(ibuf_rtr);
396bd9df44eSclaudio 			free(ibuf_rtr);
397bd9df44eSclaudio 			ibuf_rtr = NULL;
398bd9df44eSclaudio 			quit = 1;
399bd9df44eSclaudio 		} else {
400bd9df44eSclaudio 			if (dispatch_imsg(ibuf_rtr, PFD_PIPE_RTR, conf) == -1)
40129ee8e11Sclaudio 				quit = 1;
40229ee8e11Sclaudio 		}
40329ee8e11Sclaudio 
40413ff36d2Sclaudio 		if (pfd[PFD_SOCK_ROUTE].revents & POLLIN) {
4056ec75fbeSclaudio 			if (kr_dispatch_msg() == -1)
40629ee8e11Sclaudio 				quit = 1;
40729ee8e11Sclaudio 		}
40829ee8e11Sclaudio 
409c2bef38bSclaudio 		if (pfd[PFD_SOCK_PFKEY].revents & POLLIN) {
410c2bef38bSclaudio 			if (pfkey_read(keyfd, NULL) == -1) {
411c2bef38bSclaudio 				log_warnx("pfkey_read failed, exiting...");
412c2bef38bSclaudio 				quit = 1;
413c2bef38bSclaudio 			}
414c2bef38bSclaudio 		}
415c2bef38bSclaudio 
416571b47daSclaudio 		for (i = PFD_CONNECT_START; i < npfd; i++)
417571b47daSclaudio 			if (pfd[i].revents != 0)
418cd16358eSclaudio 				bgpd_rtr_conn_setup_done(pfd[i].fd, conf);
419571b47daSclaudio 
42062af2417Sclaudio  next_loop:
4217ef6e1feSclaudio 		if (reconfig) {
4221721f25bSclaudio 			u_int	error;
4231721f25bSclaudio 
4247ef6e1feSclaudio 			reconfig = 0;
42582fc6237Sclaudio 			switch (reconfigure(conffile, conf)) {
4261721f25bSclaudio 			case -1:	/* fatal error */
4271721f25bSclaudio 				quit = 1;
4281721f25bSclaudio 				break;
4291721f25bSclaudio 			case 0:		/* all OK */
4301721f25bSclaudio 				error = 0;
4311721f25bSclaudio 				break;
4328a2bb8d5Sclaudio 			case 2:
433bf3956d0Sclaudio 				log_info("previous reload still running");
4348a2bb8d5Sclaudio 				error = CTL_RES_PENDING;
4358a2bb8d5Sclaudio 				break;
4361721f25bSclaudio 			default:	/* parse error */
437bf3956d0Sclaudio 				log_warnx("config file %s has errors, "
438bf3956d0Sclaudio 				    "not reloading", conffile);
4391721f25bSclaudio 				error = CTL_RES_PARSE_ERROR;
4401721f25bSclaudio 				break;
4411721f25bSclaudio 			}
4421721f25bSclaudio 			if (reconfpid != 0) {
4431721f25bSclaudio 				send_imsg_session(IMSG_CTL_RESULT, reconfpid,
4441721f25bSclaudio 				    &error, sizeof(error));
4451721f25bSclaudio 				reconfpid = 0;
4461721f25bSclaudio 			}
4477ef6e1feSclaudio 		}
4487ef6e1feSclaudio 
44929ee8e11Sclaudio 		if (mrtdump) {
4507ef6e1feSclaudio 			mrtdump = 0;
451d288d268Sclaudio 			mrt_handler(conf->mrt);
4527ef6e1feSclaudio 		}
453a16c0992Shenning 	}
454a16c0992Shenning 
45551512aa9Srenato 	/* close pipes */
45651512aa9Srenato 	if (ibuf_se) {
4579cbf9e90Sclaudio 		imsgbuf_clear(ibuf_se);
45851512aa9Srenato 		close(ibuf_se->fd);
45951512aa9Srenato 		free(ibuf_se);
460e8d21d8aSclaudio 		ibuf_se = NULL;
46151512aa9Srenato 	}
46251512aa9Srenato 	if (ibuf_rde) {
4639cbf9e90Sclaudio 		imsgbuf_clear(ibuf_rde);
46451512aa9Srenato 		close(ibuf_rde->fd);
46551512aa9Srenato 		free(ibuf_rde);
466e8d21d8aSclaudio 		ibuf_rde = NULL;
46751512aa9Srenato 	}
468bd9df44eSclaudio 	if (ibuf_rtr) {
4699cbf9e90Sclaudio 		imsgbuf_clear(ibuf_rtr);
470bd9df44eSclaudio 		close(ibuf_rtr->fd);
471bd9df44eSclaudio 		free(ibuf_rtr);
472bd9df44eSclaudio 		ibuf_rtr = NULL;
473bd9df44eSclaudio 	}
474a16c0992Shenning 
475c2bef38bSclaudio 	/* cleanup kernel data structures */
4767f5c1560Shenning 	carp_demote_shutdown();
4776ec75fbeSclaudio 	kr_shutdown();
478972b7d94Sdjm 	pftable_clear_all();
479d288d268Sclaudio 
4807876190cSclaudio 	RB_FOREACH(p, peer_head, &conf->peers)
481d7629114Sclaudio 		pfkey_remove(&p->auth_state);
482c2bef38bSclaudio 
483c2bef38bSclaudio 	while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) {
484c2bef38bSclaudio 		SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
485c2bef38bSclaudio 		free(rr);
486c2bef38bSclaudio 	}
487d288d268Sclaudio 	free_config(conf);
48829f5f954Shenning 
48951512aa9Srenato 	log_debug("waiting for children to terminate");
4904c131d3fShenning 	do {
49151512aa9Srenato 		pid = wait(&status);
49251512aa9Srenato 		if (pid == -1) {
49351512aa9Srenato 			if (errno != EINTR && errno != ECHILD)
4944c131d3fShenning 				fatal("wait");
4951d32dc34Sbcook 		} else if (WIFSIGNALED(status)) {
4961d32dc34Sbcook 			char *name = "unknown process";
4971d32dc34Sbcook 			if (pid == rde_pid)
4981d32dc34Sbcook 				name = "route decision engine";
4991d32dc34Sbcook 			else if (pid == se_pid)
5001d32dc34Sbcook 				name = "session engine";
501bd9df44eSclaudio 			else if (pid == rtr_pid)
502bd9df44eSclaudio 				name = "rtr engine";
5031d32dc34Sbcook 			log_warnx("%s terminated; signal %d", name,
5041d32dc34Sbcook 				WTERMSIG(status));
5051d32dc34Sbcook 		}
5064c131d3fShenning 	} while (pid != -1 || (pid == -1 && errno == EINTR));
5074c131d3fShenning 
508c9079677Sclaudio 	free(rcname);
509c9079677Sclaudio 	free(cname);
51000f90be3Shenning 
51151512aa9Srenato 	log_info("terminating");
512a16c0992Shenning 	return (0);
513a16c0992Shenning }
514a16c0992Shenning 
51513ff36d2Sclaudio pid_t
51613ff36d2Sclaudio start_child(enum bgpd_process p, char *argv0, int fd, int debug, int verbose)
51713ff36d2Sclaudio {
51813ff36d2Sclaudio 	char *argv[5];
51913ff36d2Sclaudio 	int argc = 0;
52013ff36d2Sclaudio 	pid_t pid;
52113ff36d2Sclaudio 
52213ff36d2Sclaudio 	switch (pid = fork()) {
52313ff36d2Sclaudio 	case -1:
52413ff36d2Sclaudio 		fatal("cannot fork");
52513ff36d2Sclaudio 	case 0:
52613ff36d2Sclaudio 		break;
52713ff36d2Sclaudio 	default:
52813ff36d2Sclaudio 		close(fd);
52913ff36d2Sclaudio 		return (pid);
53013ff36d2Sclaudio 	}
53113ff36d2Sclaudio 
532ef4f5895Syasuoka 	if (fd != 3) {
53313ff36d2Sclaudio 		if (dup2(fd, 3) == -1)
53413ff36d2Sclaudio 			fatal("cannot setup imsg fd");
535ef4f5895Syasuoka 	} else if (fcntl(fd, F_SETFD, 0) == -1)
536ef4f5895Syasuoka 		fatal("cannot setup imsg fd");
53713ff36d2Sclaudio 
53813ff36d2Sclaudio 	argv[argc++] = argv0;
53913ff36d2Sclaudio 	switch (p) {
54013ff36d2Sclaudio 	case PROC_MAIN:
54113ff36d2Sclaudio 		fatalx("Can not start main process");
54213ff36d2Sclaudio 	case PROC_RDE:
54313ff36d2Sclaudio 		argv[argc++] = "-R";
54413ff36d2Sclaudio 		break;
54513ff36d2Sclaudio 	case PROC_SE:
54613ff36d2Sclaudio 		argv[argc++] = "-S";
54713ff36d2Sclaudio 		break;
548bd9df44eSclaudio 	case PROC_RTR:
549bd9df44eSclaudio 		argv[argc++] = "-T";
550bd9df44eSclaudio 		break;
55113ff36d2Sclaudio 	}
55213ff36d2Sclaudio 	if (debug)
55313ff36d2Sclaudio 		argv[argc++] = "-d";
55413ff36d2Sclaudio 	if (verbose)
55513ff36d2Sclaudio 		argv[argc++] = "-v";
55613ff36d2Sclaudio 	argv[argc++] = NULL;
55713ff36d2Sclaudio 
55813ff36d2Sclaudio 	execvp(argv0, argv);
55913ff36d2Sclaudio 	fatal("execvp");
56013ff36d2Sclaudio }
56113ff36d2Sclaudio 
562a16c0992Shenning int
5637910aaa2Sclaudio send_filterset(struct imsgbuf *i, struct filter_set_head *set)
56498d902b5Sclaudio {
56598d902b5Sclaudio 	struct filter_set	*s;
56698d902b5Sclaudio 
56776630fdaSclaudio 	TAILQ_FOREACH(s, set, entry)
5687910aaa2Sclaudio 		if (imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s,
56998d902b5Sclaudio 		    sizeof(struct filter_set)) == -1)
57098d902b5Sclaudio 			return (-1);
57198d902b5Sclaudio 	return (0);
57298d902b5Sclaudio }
57398d902b5Sclaudio 
57498d902b5Sclaudio int
57582fc6237Sclaudio reconfigure(char *conffile, struct bgpd_config *conf)
576a16c0992Shenning {
57782fc6237Sclaudio 	struct bgpd_config	*new_conf;
578bf3956d0Sclaudio 
579bf3956d0Sclaudio 	if (reconfpending)
580bf3956d0Sclaudio 		return (2);
581bf3956d0Sclaudio 
582bf3956d0Sclaudio 	log_info("rereading config");
583bd9df44eSclaudio 	if ((new_conf = parse_config(conffile, &conf->peers,
584bd9df44eSclaudio 	    &conf->rtrs)) == NULL)
585bf3956d0Sclaudio 		return (1);
586bf3956d0Sclaudio 
587bf3956d0Sclaudio 	merge_config(conf, new_conf);
588bf3956d0Sclaudio 
5897f893e0cSclaudio 	if (prepare_listeners(conf) == -1)
590bf3956d0Sclaudio 		return (1);
591bf3956d0Sclaudio 
5927f893e0cSclaudio 	if (control_setup(conf) == -1)
593bf3956d0Sclaudio 		return (1);
594bf3956d0Sclaudio 
595bf3956d0Sclaudio 	return send_config(conf);
596bf3956d0Sclaudio }
597bf3956d0Sclaudio 
598bf3956d0Sclaudio int
599bf3956d0Sclaudio send_config(struct bgpd_config *conf)
600bf3956d0Sclaudio {
60130f744d3Shenning 	struct peer		*p;
602594d4df8Shenning 	struct filter_rule	*r;
603f99a9452Shenning 	struct listen_addr	*la;
60425e17ce8Sclaudio 	struct rde_rib		*rr;
6054e0c4e97Sclaudio 	struct l3vpn		*vpn;
60659e404fbSclaudio 	struct as_set		*aset;
607441aaadcSbenno 	struct prefixset	*ps;
608d32b24c8Sclaudio 	struct prefixset_item	*psi, *npsi;
609ff84f55eSclaudio 	struct roa		*roa;
610ff84f55eSclaudio 	struct aspa_set		*aspa;
611bd9df44eSclaudio 	struct rtr_config	*rtr;
6129ed3e6d0Sclaudio 	struct flowspec_config	*f, *nf;
613a16c0992Shenning 
614bd9df44eSclaudio 	reconfpending = 3;	/* one per child */
6158a2bb8d5Sclaudio 
6168bf72ef0Sclaudio 	expand_networks(conf, &conf->networks);
6178bf72ef0Sclaudio 	SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry)
6188bf72ef0Sclaudio 		expand_networks(conf, &vpn->net_l);
619e913e203Shenning 
6207fedd3ccSclaudio 	cflags = conf->flags;
6219584c7ffShenning 
622968fc0f3Sclaudio 	/* start reconfiguration */
623709b991aShenning 	if (imsg_compose(ibuf_se, IMSG_RECONF_CONF, 0, 0, -1,
624988ac39fSclaudio 	    conf, sizeof(*conf)) == -1)
6250f0d58f8Shenning 		return (-1);
626709b991aShenning 	if (imsg_compose(ibuf_rde, IMSG_RECONF_CONF, 0, 0, -1,
627988ac39fSclaudio 	    conf, sizeof(*conf)) == -1)
6280f0d58f8Shenning 		return (-1);
629bd9df44eSclaudio 	if (imsg_compose(ibuf_rtr, IMSG_RECONF_CONF, 0, 0, -1,
630bd9df44eSclaudio 	    conf, sizeof(*conf)) == -1)
631bd9df44eSclaudio 		return (-1);
632968fc0f3Sclaudio 
633968fc0f3Sclaudio 	TAILQ_FOREACH(la, conf->listen_addrs, entry) {
634968fc0f3Sclaudio 		if (imsg_compose(ibuf_se, IMSG_RECONF_LISTENER, 0, 0, la->fd,
635988ac39fSclaudio 		    la, sizeof(*la)) == -1)
636968fc0f3Sclaudio 			return (-1);
637968fc0f3Sclaudio 		la->fd = -1;
63898d902b5Sclaudio 	}
639968fc0f3Sclaudio 
640459fcfe4Sclaudio 	/* adjust fib syncing on reload */
641459fcfe4Sclaudio 	ktable_preload();
642459fcfe4Sclaudio 
64325e17ce8Sclaudio 	/* RIBs for the RDE */
64425e17ce8Sclaudio 	while ((rr = SIMPLEQ_FIRST(&ribnames))) {
64525e17ce8Sclaudio 		SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
646859a8563Sclaudio 		if (ktable_update(rr->rtableid, rr->name, rr->flags) == -1) {
647311b0850Sclaudio 			log_warnx("failed to load routing table %d",
648459fcfe4Sclaudio 			    rr->rtableid);
649459fcfe4Sclaudio 			return (-1);
650459fcfe4Sclaudio 		}
65125e17ce8Sclaudio 		if (imsg_compose(ibuf_rde, IMSG_RECONF_RIB, 0, 0, -1,
652988ac39fSclaudio 		    rr, sizeof(*rr)) == -1)
65325e17ce8Sclaudio 			return (-1);
65425e17ce8Sclaudio 		free(rr);
65525e17ce8Sclaudio 	}
65625e17ce8Sclaudio 
65717098ec8Sclaudio 	/* send peer list to the SE */
6587876190cSclaudio 	RB_FOREACH(p, peer_head, &conf->peers) {
6597f893e0cSclaudio 		if (p->reconf_action == RECONF_DELETE)
6607f893e0cSclaudio 			continue;
6617f893e0cSclaudio 
66269b2eb81Sclaudio 		if (imsg_compose(ibuf_se, IMSG_RECONF_PEER, p->conf.id, 0, -1,
663988ac39fSclaudio 		    &p->conf, sizeof(p->conf)) == -1)
66469b2eb81Sclaudio 			return (-1);
665d7629114Sclaudio 		if (pfkey_send_conf(ibuf_se, p->conf.id, &p->auth_conf) == -1)
666d7629114Sclaudio 			return (-1);
667c2bef38bSclaudio 
668c2bef38bSclaudio 		if (p->reconf_action == RECONF_REINIT)
669d7629114Sclaudio 			if (pfkey_establish(&p->auth_state, &p->auth_conf,
670d7629114Sclaudio 			    session_localaddr(p), &p->conf.remote_addr) == -1)
671cd16358eSclaudio 				log_peer_warnx(&p->conf, "auth setup failed");
67269b2eb81Sclaudio 	}
67369b2eb81Sclaudio 
674610bcb44Sclaudio 	/* networks go via kroute to the RDE */
6754e0c4e97Sclaudio 	kr_net_reload(conf->default_tableid, 0, &conf->networks);
676968fc0f3Sclaudio 
6779ed3e6d0Sclaudio 	/* flowspec goes directly to the RDE, also remove old objects */
6789ed3e6d0Sclaudio 	RB_FOREACH_SAFE(f, flowspec_tree, &conf->flowspecs, nf) {
6799ed3e6d0Sclaudio 		if (f->reconf_action != RECONF_DELETE) {
6809ed3e6d0Sclaudio 			if (imsg_compose(ibuf_rde, IMSG_FLOWSPEC_ADD, 0, 0, -1,
6819ed3e6d0Sclaudio 			    f->flow, FLOWSPEC_SIZE + f->flow->len) == -1)
6829ed3e6d0Sclaudio 				return (-1);
6839ed3e6d0Sclaudio 			if (send_filterset(ibuf_rde, &f->attrset) == -1)
6849ed3e6d0Sclaudio 				return (-1);
6859ed3e6d0Sclaudio 			if (imsg_compose(ibuf_rde, IMSG_FLOWSPEC_DONE, 0, 0, -1,
6869ed3e6d0Sclaudio 			    NULL, 0) == -1)
6879ed3e6d0Sclaudio 				return (-1);
6889ed3e6d0Sclaudio 		} else {
6899ed3e6d0Sclaudio 			if (imsg_compose(ibuf_rde, IMSG_FLOWSPEC_REMOVE, 0, 0,
6909ed3e6d0Sclaudio 			    -1, f->flow, FLOWSPEC_SIZE + f->flow->len) == -1)
6919ed3e6d0Sclaudio 				return (-1);
6929ed3e6d0Sclaudio 			RB_REMOVE(flowspec_tree, &conf->flowspecs, f);
6939ed3e6d0Sclaudio 			flowspec_free(f);
6949ed3e6d0Sclaudio 		}
6959ed3e6d0Sclaudio 	}
6969ed3e6d0Sclaudio 
697441aaadcSbenno 	/* prefixsets for filters in the RDE */
6986f1dba6eSclaudio 	while ((ps = SIMPLEQ_FIRST(&conf->prefixsets)) != NULL) {
6996f1dba6eSclaudio 		SIMPLEQ_REMOVE_HEAD(&conf->prefixsets, entry);
7006f1dba6eSclaudio 		if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIX_SET, 0, 0, -1,
701a02daaddSclaudio 		    ps->name, sizeof(ps->name)) == -1)
702441aaadcSbenno 			return (-1);
703d32b24c8Sclaudio 		RB_FOREACH_SAFE(psi, prefixset_tree, &ps->psitems, npsi) {
704d32b24c8Sclaudio 			RB_REMOVE(prefixset_tree, &ps->psitems, psi);
7056f1dba6eSclaudio 			if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIX_SET_ITEM,
7066f1dba6eSclaudio 			    0, 0, -1, psi, sizeof(*psi)) == -1)
707441aaadcSbenno 				return (-1);
708502ece1dSclaudio 			free(psi);
709502ece1dSclaudio 		}
710502ece1dSclaudio 		free(ps);
711502ece1dSclaudio 	}
712502ece1dSclaudio 
7136f1dba6eSclaudio 	/* originsets for filters in the RDE */
7146f1dba6eSclaudio 	while ((ps = SIMPLEQ_FIRST(&conf->originsets)) != NULL) {
7156f1dba6eSclaudio 		SIMPLEQ_REMOVE_HEAD(&conf->originsets, entry);
7166f1dba6eSclaudio 		if (imsg_compose(ibuf_rde, IMSG_RECONF_ORIGIN_SET, 0, 0, -1,
717502ece1dSclaudio 		    ps->name, sizeof(ps->name)) == -1)
718502ece1dSclaudio 			return (-1);
719ff84f55eSclaudio 		RB_FOREACH(roa, roa_tree, &ps->roaitems) {
7206aa533f4Sclaudio 			if (imsg_compose(ibuf_rde, IMSG_RECONF_ROA_ITEM, 0, 0,
7216aa533f4Sclaudio 			    -1, roa, sizeof(*roa)) == -1)
722502ece1dSclaudio 				return (-1);
723441aaadcSbenno 		}
724ff84f55eSclaudio 		free_roatree(&ps->roaitems);
725441aaadcSbenno 		free(ps);
726441aaadcSbenno 	}
727441aaadcSbenno 
728ff84f55eSclaudio 	/* roa table, aspa table and rtr config are sent to the RTR engine */
729ff84f55eSclaudio 	RB_FOREACH(roa, roa_tree, &conf->roa) {
730bd9df44eSclaudio 		if (imsg_compose(ibuf_rtr, IMSG_RECONF_ROA_ITEM, 0, 0,
7316aa533f4Sclaudio 		    -1, roa, sizeof(*roa)) == -1)
7326f1dba6eSclaudio 			return (-1);
7336f1dba6eSclaudio 	}
734ff84f55eSclaudio 	free_roatree(&conf->roa);
735ff84f55eSclaudio 	RB_FOREACH(aspa, aspa_tree, &conf->aspa) {
736ff84f55eSclaudio 		if (imsg_compose(ibuf_rtr, IMSG_RECONF_ASPA, 0, 0,
737ff84f55eSclaudio 		    -1, aspa, offsetof(struct aspa_set, tas)) == -1)
738ff84f55eSclaudio 			return (-1);
739ff84f55eSclaudio 		if (imsg_compose(ibuf_rtr, IMSG_RECONF_ASPA_TAS, 0, 0,
740bb1a6d1aSclaudio 		    -1, aspa->tas, aspa->num * sizeof(*aspa->tas)) == -1)
741ff84f55eSclaudio 			return (-1);
742ff84f55eSclaudio 		if (imsg_compose(ibuf_rtr, IMSG_RECONF_ASPA_DONE, 0, 0, -1,
743ff84f55eSclaudio 		    NULL, 0) == -1)
744ff84f55eSclaudio 			return -1;
745ff84f55eSclaudio 	}
746ff84f55eSclaudio 	free_aspatree(&conf->aspa);
747bd9df44eSclaudio 	SIMPLEQ_FOREACH(rtr, &conf->rtrs, entry) {
748d87cfbccSclaudio 		struct rtr_config_msg rtrconf = { 0 };
749d87cfbccSclaudio 
750d87cfbccSclaudio 		strlcpy(rtrconf.descr, rtr->descr, sizeof(rtrconf.descr));
751d87cfbccSclaudio 		rtrconf.min_version = rtr->min_version;
752bd9df44eSclaudio 		if (imsg_compose(ibuf_rtr, IMSG_RECONF_RTR_CONFIG, rtr->id,
753d87cfbccSclaudio 		    0, -1, &rtrconf, sizeof(rtrconf)) == -1)
754bd9df44eSclaudio 			return (-1);
7556f1dba6eSclaudio 	}
7566f1dba6eSclaudio 
757a8e18e82Sclaudio 	/* as-sets for filters in the RDE */
758965dc109Sclaudio 	while ((aset = SIMPLEQ_FIRST(&conf->as_sets)) != NULL) {
75959e404fbSclaudio 		struct ibuf *wbuf;
76039386878Sclaudio 		uint32_t *as;
76159e404fbSclaudio 		size_t i, l, n;
76259e404fbSclaudio 
763965dc109Sclaudio 		SIMPLEQ_REMOVE_HEAD(&conf->as_sets, entry);
76459e404fbSclaudio 
76559e404fbSclaudio 		as = set_get(aset->set, &n);
76659e404fbSclaudio 		if ((wbuf = imsg_create(ibuf_rde, IMSG_RECONF_AS_SET, 0, 0,
76759e404fbSclaudio 		    sizeof(n) + sizeof(aset->name))) == NULL)
76859e404fbSclaudio 			return -1;
76959e404fbSclaudio 		if (imsg_add(wbuf, &n, sizeof(n)) == -1 ||
77059e404fbSclaudio 		    imsg_add(wbuf, aset->name, sizeof(aset->name)) == -1)
77159e404fbSclaudio 			return -1;
77259e404fbSclaudio 		imsg_close(ibuf_rde, wbuf);
77359e404fbSclaudio 
77459e404fbSclaudio 		for (i = 0; i < n; i += l) {
77559e404fbSclaudio 			l = (n - i > 1024 ? 1024 : n - i);
77659e404fbSclaudio 			if (imsg_compose(ibuf_rde, IMSG_RECONF_AS_SET_ITEMS,
777b05c4194Sclaudio 			    0, 0, -1, as + i, l * sizeof(*as)) == -1)
77859e404fbSclaudio 				return -1;
77959e404fbSclaudio 		}
78059e404fbSclaudio 
78159e404fbSclaudio 		if (imsg_compose(ibuf_rde, IMSG_RECONF_AS_SET_DONE, 0, 0, -1,
78259e404fbSclaudio 		    NULL, 0) == -1)
78359e404fbSclaudio 			return -1;
78459e404fbSclaudio 
78559e404fbSclaudio 		set_free(aset->set);
78659e404fbSclaudio 		free(aset);
78759e404fbSclaudio 	}
788a8e18e82Sclaudio 
789968fc0f3Sclaudio 	/* filters for the RDE */
790d288d268Sclaudio 	while ((r = TAILQ_FIRST(conf->filters)) != NULL) {
791d288d268Sclaudio 		TAILQ_REMOVE(conf->filters, r, entry);
792d8d31ef0Sclaudio 		if (send_filterset(ibuf_rde, &r->set) == -1)
793d8d31ef0Sclaudio 			return (-1);
794709b991aShenning 		if (imsg_compose(ibuf_rde, IMSG_RECONF_FILTER, 0, 0, -1,
7951514db5aShenning 		    r, sizeof(struct filter_rule)) == -1)
7961514db5aShenning 			return (-1);
79715aea9d4Sclaudio 		filterset_free(&r->set);
798594d4df8Shenning 		free(r);
799594d4df8Shenning 	}
800f99a9452Shenning 
8014e0c4e97Sclaudio 	while ((vpn = SIMPLEQ_FIRST(&conf->l3vpns)) != NULL) {
8024e0c4e97Sclaudio 		SIMPLEQ_REMOVE_HEAD(&conf->l3vpns, entry);
803859a8563Sclaudio 		if (ktable_update(vpn->rtableid, vpn->descr, vpn->flags) ==
804859a8563Sclaudio 		    -1) {
805311b0850Sclaudio 			log_warnx("failed to load routing table %d",
8064e0c4e97Sclaudio 			    vpn->rtableid);
807610bcb44Sclaudio 			return (-1);
808610bcb44Sclaudio 		}
809610bcb44Sclaudio 		/* networks go via kroute to the RDE */
8104e0c4e97Sclaudio 		kr_net_reload(vpn->rtableid, vpn->rd, &vpn->net_l);
811610bcb44Sclaudio 
8124e0c4e97Sclaudio 		if (imsg_compose(ibuf_rde, IMSG_RECONF_VPN, 0, 0, -1,
8134e0c4e97Sclaudio 		    vpn, sizeof(*vpn)) == -1)
814610bcb44Sclaudio 			return (-1);
815610bcb44Sclaudio 
816610bcb44Sclaudio 		/* export targets */
817d8d31ef0Sclaudio 		if (send_filterset(ibuf_rde, &vpn->export) == -1)
818d8d31ef0Sclaudio 			return (-1);
8194e0c4e97Sclaudio 		if (imsg_compose(ibuf_rde, IMSG_RECONF_VPN_EXPORT, 0, 0,
820610bcb44Sclaudio 		    -1, NULL, 0) == -1)
821610bcb44Sclaudio 			return (-1);
8224e0c4e97Sclaudio 		filterset_free(&vpn->export);
823610bcb44Sclaudio 
824610bcb44Sclaudio 		/* import targets */
825d8d31ef0Sclaudio 		if (send_filterset(ibuf_rde, &vpn->import) == -1)
826d8d31ef0Sclaudio 			return (-1);
8274e0c4e97Sclaudio 		if (imsg_compose(ibuf_rde, IMSG_RECONF_VPN_IMPORT, 0, 0,
828610bcb44Sclaudio 		    -1, NULL, 0) == -1)
829610bcb44Sclaudio 			return (-1);
8304e0c4e97Sclaudio 		filterset_free(&vpn->import);
831610bcb44Sclaudio 
8324e0c4e97Sclaudio 		if (imsg_compose(ibuf_rde, IMSG_RECONF_VPN_DONE, 0, 0,
833610bcb44Sclaudio 		    -1, NULL, 0) == -1)
834610bcb44Sclaudio 			return (-1);
835610bcb44Sclaudio 
8364e0c4e97Sclaudio 		free(vpn);
837610bcb44Sclaudio 	}
838610bcb44Sclaudio 
839e05c8e68Sclaudio 	/* send a drain message to know when all messages where processed */
840e05c8e68Sclaudio 	if (imsg_compose(ibuf_se, IMSG_RECONF_DRAIN, 0, 0, -1, NULL, 0) == -1)
841e05c8e68Sclaudio 		return (-1);
842e05c8e68Sclaudio 	if (imsg_compose(ibuf_rde, IMSG_RECONF_DRAIN, 0, 0, -1, NULL, 0) == -1)
8430f0d58f8Shenning 		return (-1);
844bd9df44eSclaudio 	if (imsg_compose(ibuf_rtr, IMSG_RECONF_DRAIN, 0, 0, -1, NULL, 0) == -1)
845bd9df44eSclaudio 		return (-1);
846a16c0992Shenning 
8473ac41105Sclaudio 	/* mrt changes can be sent out of bound */
848d288d268Sclaudio 	mrt_reconfigure(conf->mrt);
849a16c0992Shenning 	return (0);
850a16c0992Shenning }
851a16c0992Shenning 
852a16c0992Shenning int
853d1ee0d19Sclaudio dispatch_imsg(struct imsgbuf *imsgbuf, int idx, struct bgpd_config *conf)
854a16c0992Shenning {
855dc5dffceShenning 	struct imsg		 imsg;
856c2bef38bSclaudio 	struct peer		*p;
857bd9df44eSclaudio 	struct rtr_config	*r;
858be25e90dSclaudio 	struct kroute_full	 kf;
859be25e90dSclaudio 	struct bgpd_addr	 addr;
860be25e90dSclaudio 	struct pftable_msg	 pfmsg;
861be25e90dSclaudio 	struct demote_msg	 demote;
862be25e90dSclaudio 	char			 reason[REASON_LEN], ifname[IFNAMSIZ];
863d6b35cfbSclaudio 	ssize_t			 n;
8646ec75fbeSclaudio 	u_int			 rtableid;
865d6b35cfbSclaudio 	int			 rv, verbose;
866a16c0992Shenning 
86760ed8a64Stedu 	rv = 0;
868d1ee0d19Sclaudio 	while (imsgbuf) {
869d1ee0d19Sclaudio 		if ((n = imsg_get(imsgbuf, &imsg)) == -1)
8700f0d58f8Shenning 			return (-1);
8710f0d58f8Shenning 
8729a03ff31Shenning 		if (n == 0)
8739a03ff31Shenning 			break;
8749a03ff31Shenning 
875be25e90dSclaudio 		switch (imsg_get_type(&imsg)) {
8763eef66beShenning 		case IMSG_KROUTE_CHANGE:
877dfda3de3Sclaudio 			if (idx != PFD_PIPE_RDE)
878553e6efdShenning 				log_warnx("route request not from RDE");
879be25e90dSclaudio 			else if (imsg_get_data(&imsg, &kf, sizeof(kf)) == -1)
880be25e90dSclaudio 				log_warn("wrong imsg len");
881be25e90dSclaudio 			else if (kr_change(imsg_get_id(&imsg), &kf))
88260ed8a64Stedu 				rv = -1;
8838976e495Shenning 			break;
8843eef66beShenning 		case IMSG_KROUTE_DELETE:
885dfda3de3Sclaudio 			if (idx != PFD_PIPE_RDE)
886553e6efdShenning 				log_warnx("route request not from RDE");
887be25e90dSclaudio 			else if (imsg_get_data(&imsg, &kf, sizeof(kf)) == -1)
888be25e90dSclaudio 				log_warn("wrong imsg len");
889be25e90dSclaudio 			else if (kr_delete(imsg_get_id(&imsg), &kf))
89060ed8a64Stedu 				rv = -1;
8913eef66beShenning 			break;
8925d2d0304Sclaudio 		case IMSG_KROUTE_FLUSH:
893dfda3de3Sclaudio 			if (idx != PFD_PIPE_RDE)
8945d2d0304Sclaudio 				log_warnx("route request not from RDE");
895be25e90dSclaudio 			else if (kr_flush(imsg_get_id(&imsg)))
8965d2d0304Sclaudio 				rv = -1;
8975d2d0304Sclaudio 			break;
898d54e22baShenning 		case IMSG_NEXTHOP_ADD:
899dfda3de3Sclaudio 			if (idx != PFD_PIPE_RDE)
900553e6efdShenning 				log_warnx("nexthop request not from RDE");
901be25e90dSclaudio 			else if (imsg_get_data(&imsg, &addr, sizeof(addr)) ==
902be25e90dSclaudio 			    -1)
903be25e90dSclaudio 				log_warn("wrong imsg len");
9046ec75fbeSclaudio 			else {
9056ec75fbeSclaudio 				rtableid = conf->default_tableid;
906be25e90dSclaudio 				if (kr_nexthop_add(rtableid, &addr) == -1)
90760ed8a64Stedu 					rv = -1;
9086ec75fbeSclaudio 			}
909d54e22baShenning 			break;
910d54e22baShenning 		case IMSG_NEXTHOP_REMOVE:
911dfda3de3Sclaudio 			if (idx != PFD_PIPE_RDE)
912553e6efdShenning 				log_warnx("nexthop request not from RDE");
913be25e90dSclaudio 			else if (imsg_get_data(&imsg, &addr, sizeof(addr)) ==
914be25e90dSclaudio 			    -1)
915be25e90dSclaudio 				log_warn("wrong imsg len");
9166ec75fbeSclaudio 			else {
9176ec75fbeSclaudio 				rtableid = conf->default_tableid;
918be25e90dSclaudio 				kr_nexthop_delete(rtableid, &addr);
9196ec75fbeSclaudio 			}
920d54e22baShenning 			break;
921972b7d94Sdjm 		case IMSG_PFTABLE_ADD:
922dfda3de3Sclaudio 			if (idx != PFD_PIPE_RDE)
923972b7d94Sdjm 				log_warnx("pftable request not from RDE");
924be25e90dSclaudio 			else if (imsg_get_data(&imsg, &pfmsg, sizeof(pfmsg)) ==
925be25e90dSclaudio 			    -1)
926be25e90dSclaudio 				log_warn("wrong imsg len");
927be25e90dSclaudio 			else if (pftable_addr_add(&pfmsg) != 0)
92860ed8a64Stedu 				rv = -1;
929972b7d94Sdjm 			break;
930972b7d94Sdjm 		case IMSG_PFTABLE_REMOVE:
931dfda3de3Sclaudio 			if (idx != PFD_PIPE_RDE)
932972b7d94Sdjm 				log_warnx("pftable request not from RDE");
933be25e90dSclaudio 			else if (imsg_get_data(&imsg, &pfmsg, sizeof(pfmsg)) ==
934be25e90dSclaudio 			    -1)
935be25e90dSclaudio 				log_warn("wrong imsg len");
936be25e90dSclaudio 			else if (pftable_addr_remove(&pfmsg) != 0)
93760ed8a64Stedu 				rv = -1;
938972b7d94Sdjm 			break;
939972b7d94Sdjm 		case IMSG_PFTABLE_COMMIT:
940dfda3de3Sclaudio 			if (idx != PFD_PIPE_RDE)
941972b7d94Sdjm 				log_warnx("pftable request not from RDE");
942972b7d94Sdjm 			else if (pftable_commit() != 0)
94360ed8a64Stedu 				rv = -1;
944972b7d94Sdjm 			break;
945c2bef38bSclaudio 		case IMSG_PFKEY_RELOAD:
946bb06c696Sclaudio 			if (idx != PFD_PIPE_SESSION) {
947c2bef38bSclaudio 				log_warnx("pfkey reload request not from SE");
948bb06c696Sclaudio 				break;
949bb06c696Sclaudio 			}
950be25e90dSclaudio 			p = getpeerbyid(conf, imsg_get_id(&imsg));
951bb06c696Sclaudio 			if (p != NULL) {
952d7629114Sclaudio 				if (pfkey_establish(&p->auth_state,
953d7629114Sclaudio 				    &p->auth_conf, session_localaddr(p),
954d7629114Sclaudio 				    &p->conf.remote_addr) == -1)
955c2bef38bSclaudio 					log_peer_warnx(&p->conf,
956c2bef38bSclaudio 					    "pfkey setup failed");
957c2bef38bSclaudio 			}
958c2bef38bSclaudio 			break;
959f884ff3dShenning 		case IMSG_CTL_RELOAD:
960f884ff3dShenning 			if (idx != PFD_PIPE_SESSION)
961553e6efdShenning 				log_warnx("reload request not from SE");
9628a2bb8d5Sclaudio 			else {
963f884ff3dShenning 				reconfig = 1;
964be25e90dSclaudio 				reconfpid = imsg_get_pid(&imsg);
965be25e90dSclaudio 				if (imsg_get_data(&imsg, reason,
966be25e90dSclaudio 				    sizeof(reason)) == 0 && reason[0] != '\0')
9674bc1d1b7Sclaudio 					log_info("reload due to: %s",
968be25e90dSclaudio 					    log_reason(reason));
9698a2bb8d5Sclaudio 			}
970f884ff3dShenning 			break;
971192b7460Shenning 		case IMSG_CTL_FIB_COUPLE:
972192b7460Shenning 			if (idx != PFD_PIPE_SESSION)
973553e6efdShenning 				log_warnx("couple request not from SE");
974192b7460Shenning 			else
975be25e90dSclaudio 				kr_fib_couple(imsg_get_id(&imsg));
976192b7460Shenning 			break;
977192b7460Shenning 		case IMSG_CTL_FIB_DECOUPLE:
978192b7460Shenning 			if (idx != PFD_PIPE_SESSION)
979553e6efdShenning 				log_warnx("decouple request not from SE");
980192b7460Shenning 			else
981be25e90dSclaudio 				kr_fib_decouple(imsg_get_id(&imsg));
982192b7460Shenning 			break;
983f4ecf7d5Shenning 		case IMSG_CTL_KROUTE:
98452ef641bShenning 		case IMSG_CTL_KROUTE_ADDR:
985e949080fShenning 		case IMSG_CTL_SHOW_NEXTHOP:
9866a72a716Shenning 		case IMSG_CTL_SHOW_INTERFACE:
987459fcfe4Sclaudio 		case IMSG_CTL_SHOW_FIB_TABLES:
988f4ecf7d5Shenning 			if (idx != PFD_PIPE_SESSION)
989553e6efdShenning 				log_warnx("kroute request not from SE");
990f4ecf7d5Shenning 			else
99152ef641bShenning 				kr_show_route(&imsg);
992f4ecf7d5Shenning 			break;
9930195298dSclaudio 		case IMSG_SESSION_DEPENDON:
994dc228c27Shenning 			if (idx != PFD_PIPE_SESSION)
9950195298dSclaudio 				log_warnx("DEPENDON request not from SE");
996be25e90dSclaudio 			else if (imsg_get_data(&imsg, ifname, sizeof(ifname)) ==
997be25e90dSclaudio 			    -1)
998be25e90dSclaudio 				log_warn("wrong imsg len");
999dc228c27Shenning 			else
1000be25e90dSclaudio 				kr_ifinfo(ifname);
1001dc228c27Shenning 			break;
10027f5c1560Shenning 		case IMSG_DEMOTE:
10037f5c1560Shenning 			if (idx != PFD_PIPE_SESSION)
10047f5c1560Shenning 				log_warnx("demote request not from SE");
1005be25e90dSclaudio 			else if (imsg_get_data(&imsg, &demote, sizeof(demote))
1006be25e90dSclaudio 			    == -1)
1007be25e90dSclaudio 				log_warn("wrong imsg len");
1008be25e90dSclaudio 			else
1009be25e90dSclaudio 				carp_demote_set(demote.demote_group,
1010be25e90dSclaudio 				    demote.level);
10117f5c1560Shenning 			break;
1012d6b35cfbSclaudio 		case IMSG_CTL_LOG_VERBOSE:
1013d6b35cfbSclaudio 			/* already checked by SE */
1014be25e90dSclaudio 			if (imsg_get_data(&imsg, &verbose, sizeof(verbose)) ==
1015be25e90dSclaudio 			    -1)
1016be25e90dSclaudio 				log_warn("wrong imsg len");
1017be25e90dSclaudio 			else
10185e3f6f95Sbenno 				log_setverbose(verbose);
1019d6b35cfbSclaudio 			break;
10208a2bb8d5Sclaudio 		case IMSG_RECONF_DONE:
1021e05c8e68Sclaudio 			if (reconfpending == 0) {
10228a2bb8d5Sclaudio 				log_warnx("unexpected RECONF_DONE received");
1023e05c8e68Sclaudio 				break;
1024e05c8e68Sclaudio 			}
1025e05c8e68Sclaudio 			if (idx == PFD_PIPE_SESSION) {
1026fd932e23Sclaudio 				/* RDE and RTR engine can reload concurrently */
1027bd9df44eSclaudio 				imsg_compose(ibuf_rtr, IMSG_RECONF_DONE, 0,
1028bd9df44eSclaudio 				    0, -1, NULL, 0);
102917098ec8Sclaudio 				imsg_compose(ibuf_rde, IMSG_RECONF_DONE, 0,
103017098ec8Sclaudio 				    0, -1, NULL, 0);
1031a3c12c8fSclaudio 
1032a3c12c8fSclaudio 				/* finally fix kroute information */
1033859a8563Sclaudio 				ktable_postload();
1034a3c12c8fSclaudio 
1035a3c12c8fSclaudio 				/* redistribute list needs to be reloaded too */
1036a3c12c8fSclaudio 				kr_reload();
10377f893e0cSclaudio 
10387f893e0cSclaudio 				/* also remove old peers */
10397f893e0cSclaudio 				free_deleted_peers(conf);
1040a3c12c8fSclaudio 			}
10418a2bb8d5Sclaudio 			reconfpending--;
10428a2bb8d5Sclaudio 			break;
1043e05c8e68Sclaudio 		case IMSG_RECONF_DRAIN:
1044e05c8e68Sclaudio 			if (reconfpending == 0) {
1045e05c8e68Sclaudio 				log_warnx("unexpected RECONF_DRAIN received");
1046e05c8e68Sclaudio 				break;
1047e05c8e68Sclaudio 			}
1048e05c8e68Sclaudio 			reconfpending--;
1049e05c8e68Sclaudio 			if (reconfpending == 0) {
1050e05c8e68Sclaudio 				/*
1051e05c8e68Sclaudio 				 * SE goes first to bring templated neighbors
1052e05c8e68Sclaudio 				 * in sync.
1053e05c8e68Sclaudio 				 */
1054e05c8e68Sclaudio 				imsg_compose(ibuf_se, IMSG_RECONF_DONE, 0,
1055e05c8e68Sclaudio 				    0, -1, NULL, 0);
1056bd9df44eSclaudio 				reconfpending = 3; /* expecting 2 DONE msg */
1057e05c8e68Sclaudio 			}
1058e05c8e68Sclaudio 			break;
1059cd16358eSclaudio 		case IMSG_SOCKET_SETUP:
1060bd9df44eSclaudio 			if (idx != PFD_PIPE_RTR) {
1061bd9df44eSclaudio 				log_warnx("connect request not from RTR");
1062bd9df44eSclaudio 			} else {
1063cd16358eSclaudio 				uint32_t rtrid = imsg_get_id(&imsg);
1064bd9df44eSclaudio 				SIMPLEQ_FOREACH(r, &conf->rtrs, entry) {
1065cd16358eSclaudio 					if (rtrid == r->id)
1066bd9df44eSclaudio 						break;
1067bd9df44eSclaudio 				}
1068bd9df44eSclaudio 				if (r == NULL)
1069cd16358eSclaudio 					log_warnx("unknown rtr id %d", rtrid);
1070bd9df44eSclaudio 				else
1071cd16358eSclaudio 					bgpd_rtr_conn_setup(r);
1072cd16358eSclaudio 			}
1073cd16358eSclaudio 			break;
1074cd16358eSclaudio 		case IMSG_SOCKET_TEARDOWN:
1075cd16358eSclaudio 			if (idx != PFD_PIPE_RTR) {
1076cd16358eSclaudio 				log_warnx("connect request not from RTR");
1077cd16358eSclaudio 			} else {
1078cd16358eSclaudio 				uint32_t rtrid = imsg_get_id(&imsg);
1079cd16358eSclaudio 				bgpd_rtr_conn_teardown(rtrid);
1080bd9df44eSclaudio 			}
1081bd9df44eSclaudio 			break;
1082bd9df44eSclaudio 		case IMSG_CTL_SHOW_RTR:
1083bd9df44eSclaudio 			if (idx == PFD_PIPE_SESSION) {
1084bd9df44eSclaudio 				SIMPLEQ_FOREACH(r, &conf->rtrs, entry) {
1085be25e90dSclaudio 					imsg_compose(ibuf_rtr,
1086be25e90dSclaudio 					    IMSG_CTL_SHOW_RTR, r->id,
1087be25e90dSclaudio 					    imsg_get_pid(&imsg), -1, NULL, 0);
1088bd9df44eSclaudio 				}
1089bd9df44eSclaudio 				imsg_compose(ibuf_rtr, IMSG_CTL_END,
1090be25e90dSclaudio 				    0, imsg_get_pid(&imsg), -1, NULL, 0);
1091bd9df44eSclaudio 			} else if (idx == PFD_PIPE_RTR) {
1092be25e90dSclaudio 				struct ctl_show_rtr rtr;
1093be25e90dSclaudio 				if (imsg_get_data(&imsg, &rtr, sizeof(rtr)) ==
1094be25e90dSclaudio 				    -1) {
1095be25e90dSclaudio 					log_warn("wrong imsg len");
1096be25e90dSclaudio 					break;
1097be25e90dSclaudio 				}
1098be25e90dSclaudio 
1099bd9df44eSclaudio 				SIMPLEQ_FOREACH(r, &conf->rtrs, entry) {
1100be25e90dSclaudio 					if (imsg_get_id(&imsg) == r->id)
1101bd9df44eSclaudio 						break;
1102bd9df44eSclaudio 				}
1103bd9df44eSclaudio 				if (r != NULL) {
1104be25e90dSclaudio 					strlcpy(rtr.descr, r->descr,
1105be25e90dSclaudio 					    sizeof(rtr.descr));
1106be25e90dSclaudio 					rtr.local_addr = r->local_addr;
1107be25e90dSclaudio 					rtr.remote_addr = r->remote_addr;
1108be25e90dSclaudio 					rtr.remote_port = r->remote_port;
1109bd9df44eSclaudio 
1110be25e90dSclaudio 					imsg_compose(ibuf_se, IMSG_CTL_SHOW_RTR,
1111be25e90dSclaudio 					    imsg_get_id(&imsg),
1112be25e90dSclaudio 					    imsg_get_pid(&imsg), -1,
1113be25e90dSclaudio 					    &rtr, sizeof(rtr));
1114bd9df44eSclaudio 				}
1115bd9df44eSclaudio 			}
1116bd9df44eSclaudio 			break;
1117bd9df44eSclaudio 		case IMSG_CTL_END:
1118bd9df44eSclaudio 		case IMSG_CTL_SHOW_TIMER:
1119bd9df44eSclaudio 			if (idx != PFD_PIPE_RTR) {
1120bd9df44eSclaudio 				log_warnx("connect request not from RTR");
1121bd9df44eSclaudio 				break;
1122bd9df44eSclaudio 			}
1123be25e90dSclaudio 			imsg_forward(ibuf_se, &imsg);
1124bd9df44eSclaudio 			break;
1125a16c0992Shenning 		default:
11262c882a27Shenning 			break;
1127a16c0992Shenning 		}
1128a16c0992Shenning 		imsg_free(&imsg);
112960ed8a64Stedu 		if (rv != 0)
113060ed8a64Stedu 			return (rv);
1131a16c0992Shenning 	}
1132a16c0992Shenning 	return (0);
1133a16c0992Shenning }
1134a16c0992Shenning 
1135d54e22baShenning void
1136d54e22baShenning send_nexthop_update(struct kroute_nexthop *msg)
1137d54e22baShenning {
11389f2e8708Shenning 	char	*gw = NULL;
11399c7dfd0cShenning 
1140d6c2e4e8Sclaudio 	if (msg->gateway.aid)
11410337ad36Shenning 		if (asprintf(&gw, ": via %s",
11429f2e8708Shenning 		    log_addr(&msg->gateway)) == -1) {
11438013a801Shenning 			log_warn("send_nexthop_update");
11449c7dfd0cShenning 			quit = 1;
11459c7dfd0cShenning 		}
11469c7dfd0cShenning 
114724e168e3Sbenno 	log_debug("nexthop %s now %s%s%s", log_addr(&msg->nexthop),
11486e43c8e4Shenning 	    msg->valid ? "valid" : "invalid",
114998b56b50Shenning 	    msg->connected ? ": directly connected" : "",
1150d6c2e4e8Sclaudio 	    msg->gateway.aid ? gw : "");
11519c7dfd0cShenning 
11529c7dfd0cShenning 	free(gw);
11536e43c8e4Shenning 
1154709b991aShenning 	if (imsg_compose(ibuf_rde, IMSG_NEXTHOP_UPDATE, 0, 0, -1,
11550f0d58f8Shenning 	    msg, sizeof(struct kroute_nexthop)) == -1)
11560f0d58f8Shenning 		quit = 1;
1157d54e22baShenning }
1158f4ecf7d5Shenning 
1159f4ecf7d5Shenning void
116039386878Sclaudio send_imsg_session(int type, pid_t pid, void *data, uint16_t datalen)
1161f4ecf7d5Shenning {
1162709b991aShenning 	imsg_compose(ibuf_se, type, 0, pid, -1, data, datalen);
1163f4ecf7d5Shenning }
11647fedd3ccSclaudio 
11657fedd3ccSclaudio int
1166610bcb44Sclaudio send_network(int type, struct network_config *net, struct filter_set_head *h)
11677fedd3ccSclaudio {
1168e8d21d8aSclaudio 	if (quit)
1169e8d21d8aSclaudio 		return (0);
1170610bcb44Sclaudio 	if (imsg_compose(ibuf_rde, type, 0, 0, -1, net,
11717fedd3ccSclaudio 	    sizeof(struct network_config)) == -1)
11727fedd3ccSclaudio 		return (-1);
11737fedd3ccSclaudio 	/* networks that get deleted don't need to send the filter set */
11747fedd3ccSclaudio 	if (type == IMSG_NETWORK_REMOVE)
1175610bcb44Sclaudio 		return (0);
11767910aaa2Sclaudio 	if (send_filterset(ibuf_rde, h) == -1)
11777fedd3ccSclaudio 		return (-1);
11787fedd3ccSclaudio 	if (imsg_compose(ibuf_rde, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0) == -1)
11797fedd3ccSclaudio 		return (-1);
11807fedd3ccSclaudio 
1181610bcb44Sclaudio 	return (0);
11827fedd3ccSclaudio }
11837fedd3ccSclaudio 
1184b3695291Sclaudio /*
1185b3695291Sclaudio  * Return true if a route can be used for nexthop resolution.
1186b3695291Sclaudio  */
1187faf535a4Sclaudio int
1188b3695291Sclaudio bgpd_oknexthop(struct kroute_full *kf)
1189faf535a4Sclaudio {
1190703f44cfSclaudio 	if (kf->flags & F_BGPD)
1191b3695291Sclaudio 		return ((cflags & BGPD_FLAG_NEXTHOP_BGP) != 0);
1192faf535a4Sclaudio 
1193703f44cfSclaudio 	if (kf->prefixlen == 0)
1194b3695291Sclaudio 		return ((cflags & BGPD_FLAG_NEXTHOP_DEFAULT) != 0);
1195faf535a4Sclaudio 
1196b3695291Sclaudio 	/* any other route is fine */
1197faf535a4Sclaudio 	return (1);
1198faf535a4Sclaudio }
11991daa807cSclaudio 
12001daa807cSclaudio int
12013e516115Sclaudio bgpd_has_bgpnh(void)
12023e516115Sclaudio {
12033e516115Sclaudio 	return ((cflags & BGPD_FLAG_NEXTHOP_BGP) != 0);
12043e516115Sclaudio }
12053e516115Sclaudio 
12063e516115Sclaudio int
12071daa807cSclaudio control_setup(struct bgpd_config *conf)
12081daa807cSclaudio {
12091daa807cSclaudio 	int fd, restricted;
12101daa807cSclaudio 
12111daa807cSclaudio 	/* control socket is outside chroot */
12121daa807cSclaudio 	if (!cname || strcmp(cname, conf->csock)) {
12131daa807cSclaudio 		if (cname) {
12141daa807cSclaudio 			free(cname);
12151daa807cSclaudio 		}
12161daa807cSclaudio 		if ((cname = strdup(conf->csock)) == NULL)
12171daa807cSclaudio 			fatal("strdup");
12181adf6159Sremi 		if (control_check(cname) == -1)
12191adf6159Sremi 			return (-1);
12201daa807cSclaudio 		if ((fd = control_init(0, cname)) == -1)
12211daa807cSclaudio 			fatalx("control socket setup failed");
12220d4dc236Sflorian 		if (control_listen(fd) == -1)
12230d4dc236Sflorian 			fatalx("control socket setup failed");
12241daa807cSclaudio 		restricted = 0;
12251daa807cSclaudio 		if (imsg_compose(ibuf_se, IMSG_RECONF_CTRL, 0, 0, fd,
12261daa807cSclaudio 		    &restricted, sizeof(restricted)) == -1)
12271daa807cSclaudio 			return (-1);
12281daa807cSclaudio 	}
12291daa807cSclaudio 	if (!conf->rcsock) {
12301daa807cSclaudio 		/* remove restricted socket */
12311daa807cSclaudio 		free(rcname);
12321daa807cSclaudio 		rcname = NULL;
12331daa807cSclaudio 	} else if (!rcname || strcmp(rcname, conf->rcsock)) {
12341daa807cSclaudio 		if (rcname) {
12351daa807cSclaudio 			free(rcname);
12361daa807cSclaudio 		}
12371daa807cSclaudio 		if ((rcname = strdup(conf->rcsock)) == NULL)
12381daa807cSclaudio 			fatal("strdup");
12391adf6159Sremi 		if (control_check(rcname) == -1)
12401adf6159Sremi 			return (-1);
12411daa807cSclaudio 		if ((fd = control_init(1, rcname)) == -1)
12421daa807cSclaudio 			fatalx("control socket setup failed");
12430d4dc236Sflorian 		if (control_listen(fd) == -1)
12440d4dc236Sflorian 			fatalx("control socket setup failed");
12451daa807cSclaudio 		restricted = 1;
12461daa807cSclaudio 		if (imsg_compose(ibuf_se, IMSG_RECONF_CTRL, 0, 0, fd,
12471daa807cSclaudio 		    &restricted, sizeof(restricted)) == -1)
12481daa807cSclaudio 			return (-1);
12491daa807cSclaudio 	}
12501daa807cSclaudio 	return (0);
12511daa807cSclaudio }
125213ff36d2Sclaudio 
125313ff36d2Sclaudio void
125413ff36d2Sclaudio set_pollfd(struct pollfd *pfd, struct imsgbuf *i)
125513ff36d2Sclaudio {
125613ff36d2Sclaudio 	if (i == NULL || i->fd == -1) {
125713ff36d2Sclaudio 		pfd->fd = -1;
125813ff36d2Sclaudio 		return;
125913ff36d2Sclaudio 	}
126013ff36d2Sclaudio 	pfd->fd = i->fd;
126113ff36d2Sclaudio 	pfd->events = POLLIN;
126231be28caSclaudio 	if (imsgbuf_queuelen(i) > 0)
126313ff36d2Sclaudio 		pfd->events |= POLLOUT;
126413ff36d2Sclaudio }
126513ff36d2Sclaudio 
126613ff36d2Sclaudio int
126713ff36d2Sclaudio handle_pollfd(struct pollfd *pfd, struct imsgbuf *i)
126813ff36d2Sclaudio {
126913ff36d2Sclaudio 	ssize_t n;
127013ff36d2Sclaudio 
127113ff36d2Sclaudio 	if (i == NULL)
127213ff36d2Sclaudio 		return (0);
127313ff36d2Sclaudio 
127413ff36d2Sclaudio 	if (pfd->revents & POLLOUT)
1275dd7efffeSclaudio 		if (imsgbuf_write(i) == -1) {
1276f1b8840cSclaudio 			log_warn("imsg write error");
127713ff36d2Sclaudio 			close(i->fd);
127813ff36d2Sclaudio 			i->fd = -1;
127913ff36d2Sclaudio 			return (-1);
128013ff36d2Sclaudio 		}
128113ff36d2Sclaudio 
128213ff36d2Sclaudio 	if (pfd->revents & POLLIN) {
128316b0c81bSclaudio 		if ((n = imsgbuf_read(i)) == -1) {
1284f1b8840cSclaudio 			log_warn("imsg read error");
128513ff36d2Sclaudio 			close(i->fd);
128613ff36d2Sclaudio 			i->fd = -1;
128713ff36d2Sclaudio 			return (-1);
128813ff36d2Sclaudio 		}
1289f1b8840cSclaudio 		if (n == 0) {
1290f1b8840cSclaudio 			log_warnx("peer closed imsg connection");
129113ff36d2Sclaudio 			close(i->fd);
129213ff36d2Sclaudio 			i->fd = -1;
129313ff36d2Sclaudio 			return (-1);
129413ff36d2Sclaudio 		}
129513ff36d2Sclaudio 	}
129613ff36d2Sclaudio 	return (0);
129713ff36d2Sclaudio }
129813ff36d2Sclaudio 
1299e8beb5b5Sclaudio static void
1300e8beb5b5Sclaudio getsockpair(int pipe[2])
1301e8beb5b5Sclaudio {
1302e8beb5b5Sclaudio 	int bsize, i;
1303e8beb5b5Sclaudio 
1304e8beb5b5Sclaudio 	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
1305e8beb5b5Sclaudio 	    PF_UNSPEC, pipe) == -1)
1306e8beb5b5Sclaudio 		fatal("socketpair");
1307e8beb5b5Sclaudio 
1308e8beb5b5Sclaudio 	for (i = 0; i < 2; i++) {
1309*3a99c822Sclaudio 		bsize = MAX_SOCK_BUF;
1310e8beb5b5Sclaudio 		if (setsockopt(pipe[i], SOL_SOCKET, SO_RCVBUF,
1311e8beb5b5Sclaudio 		    &bsize, sizeof(bsize)) == -1) {
1312e8beb5b5Sclaudio 			if (errno != ENOBUFS)
1313e8beb5b5Sclaudio 				fatal("setsockopt(SO_RCVBUF, %d)",
1314e8beb5b5Sclaudio 				    bsize);
1315e8beb5b5Sclaudio 			log_warn("setsockopt(SO_RCVBUF, %d)", bsize);
1316e8beb5b5Sclaudio 		}
1317e8beb5b5Sclaudio 	}
1318e8beb5b5Sclaudio 	for (i = 0; i < 2; i++) {
1319*3a99c822Sclaudio 		bsize = MAX_SOCK_BUF;
1320e8beb5b5Sclaudio 		if (setsockopt(pipe[i], SOL_SOCKET, SO_SNDBUF,
1321e8beb5b5Sclaudio 		    &bsize, sizeof(bsize)) == -1) {
1322e8beb5b5Sclaudio 			if (errno != ENOBUFS)
1323e8beb5b5Sclaudio 				fatal("setsockopt(SO_SNDBUF, %d)",
1324e8beb5b5Sclaudio 				    bsize);
1325e8beb5b5Sclaudio 			log_warn("setsockopt(SO_SNDBUF, %d)", bsize);
1326e8beb5b5Sclaudio 		}
1327e8beb5b5Sclaudio 	}
1328e8beb5b5Sclaudio }
1329e8beb5b5Sclaudio 
133013ff36d2Sclaudio int
1331ee9b0250Sclaudio imsg_send_sockets(struct imsgbuf *se, struct imsgbuf *rde, struct imsgbuf *rtr)
133213ff36d2Sclaudio {
133313ff36d2Sclaudio 	int pipe_s2r[2];
133413ff36d2Sclaudio 	int pipe_s2r_ctl[2];
1335bd9df44eSclaudio 	int pipe_r2r[2];
133613ff36d2Sclaudio 
1337e8beb5b5Sclaudio 	getsockpair(pipe_s2r);
1338e8beb5b5Sclaudio 	getsockpair(pipe_s2r_ctl);
1339bd9df44eSclaudio 	getsockpair(pipe_r2r);
134013ff36d2Sclaudio 
134113ff36d2Sclaudio 	if (imsg_compose(se, IMSG_SOCKET_CONN, 0, 0, pipe_s2r[0],
134213ff36d2Sclaudio 	    NULL, 0) == -1)
134313ff36d2Sclaudio 		return (-1);
134413ff36d2Sclaudio 	if (imsg_compose(rde, IMSG_SOCKET_CONN, 0, 0, pipe_s2r[1],
134513ff36d2Sclaudio 	    NULL, 0) == -1)
134613ff36d2Sclaudio 		return (-1);
134713ff36d2Sclaudio 
134813ff36d2Sclaudio 	if (imsg_compose(se, IMSG_SOCKET_CONN_CTL, 0, 0, pipe_s2r_ctl[0],
134913ff36d2Sclaudio 	    NULL, 0) == -1)
135013ff36d2Sclaudio 		return (-1);
135113ff36d2Sclaudio 	if (imsg_compose(rde, IMSG_SOCKET_CONN_CTL, 0, 0, pipe_s2r_ctl[1],
135213ff36d2Sclaudio 	    NULL, 0) == -1)
135313ff36d2Sclaudio 		return (-1);
135413ff36d2Sclaudio 
1355ee9b0250Sclaudio 	if (imsg_compose(rtr, IMSG_SOCKET_CONN_RTR, 0, 0, pipe_r2r[0],
1356bd9df44eSclaudio 	    NULL, 0) == -1)
1357bd9df44eSclaudio 		return (-1);
1358bd9df44eSclaudio 	if (imsg_compose(rde, IMSG_SOCKET_CONN_RTR, 0, 0, pipe_r2r[1],
1359bd9df44eSclaudio 	    NULL, 0) == -1)
1360bd9df44eSclaudio 		return (-1);
1361bd9df44eSclaudio 
136213ff36d2Sclaudio 	return (0);
136313ff36d2Sclaudio }
1364bd9df44eSclaudio 
1365bd9df44eSclaudio void
1366cd16358eSclaudio bgpd_rtr_conn_setup(struct rtr_config *r)
1367bd9df44eSclaudio {
1368571b47daSclaudio 	struct connect_elm *ce;
1369195c91bbSclaudio 	struct sockaddr *sa;
1370bd9df44eSclaudio 	socklen_t len;
1371f7421e07Sjob 	int nodelay = 1;
1372f7421e07Sjob 	int pre = IPTOS_PREC_INTERNETCONTROL;
1373bd9df44eSclaudio 
13747bb4de2bSclaudio 	if (connect_cnt >= MAX_CONNECT_CNT) {
13757bb4de2bSclaudio 		log_warnx("rtr %s: too many concurrent connection requests",
13767bb4de2bSclaudio 		    r->descr);
13777bb4de2bSclaudio 		return;
13787bb4de2bSclaudio 	}
13797bb4de2bSclaudio 
1380571b47daSclaudio 	if ((ce = calloc(1, sizeof(*ce))) == NULL) {
1381bd9df44eSclaudio 		log_warn("rtr %s", r->descr);
1382bd9df44eSclaudio 		return;
1383bd9df44eSclaudio 	}
1384571b47daSclaudio 
1385cd16358eSclaudio 	if (pfkey_establish(&ce->auth_state, &r->auth,
1386cd16358eSclaudio 	    &r->local_addr, &r->remote_addr) == -1)
1387cd16358eSclaudio 		log_warnx("rtr %s: pfkey setup failed", r->descr);
1388cd16358eSclaudio 
1389571b47daSclaudio 	ce->id = r->id;
1390571b47daSclaudio 	ce->fd = socket(aid2af(r->remote_addr.aid),
1391571b47daSclaudio 	    SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_TCP);
1392571b47daSclaudio 	if (ce->fd == -1) {
1393571b47daSclaudio 		log_warn("rtr %s", r->descr);
1394cd16358eSclaudio 		goto fail;
1395571b47daSclaudio 	}
1396571b47daSclaudio 
1397bc3692b5Sclaudio 	switch (r->remote_addr.aid) {
1398bc3692b5Sclaudio 	case AID_INET:
1399bc3692b5Sclaudio 		if (setsockopt(ce->fd, IPPROTO_IP, IP_TOS, &pre, sizeof(pre)) ==
1400bc3692b5Sclaudio 		    -1) {
1401bc3692b5Sclaudio 			log_warn("rtr %s: setsockopt IP_TOS", r->descr);
1402bc3692b5Sclaudio 			return;
1403bc3692b5Sclaudio 		}
1404bc3692b5Sclaudio 		break;
1405bc3692b5Sclaudio 	case AID_INET6:
1406bc3692b5Sclaudio 		if (setsockopt(ce->fd, IPPROTO_IPV6, IPV6_TCLASS, &pre,
1407bc3692b5Sclaudio 		    sizeof(pre)) == -1) {
1408bc3692b5Sclaudio 			log_warn("rtr %s: setsockopt IP_TOS", r->descr);
1409bc3692b5Sclaudio 			return;
1410bc3692b5Sclaudio 		}
1411bc3692b5Sclaudio 		break;
1412bc3692b5Sclaudio 	}
1413bc3692b5Sclaudio 
1414bc3692b5Sclaudio 	if (setsockopt(ce->fd, IPPROTO_TCP, TCP_NODELAY, &nodelay,
1415bc3692b5Sclaudio 	    sizeof(nodelay)) == -1) {
1416bc3692b5Sclaudio 		log_warn("rtr %s: setsockopt TCP_NODELAY", r->descr);
1417bc3692b5Sclaudio 		return;
1418bc3692b5Sclaudio 	}
1419bc3692b5Sclaudio 
1420cd16358eSclaudio 	if (tcp_md5_set(ce->fd, &r->auth, &r->remote_addr) == -1)
1421cd16358eSclaudio 		log_warn("rtr %s: setting md5sig", r->descr);
1422cd16358eSclaudio 
1423195c91bbSclaudio 	if ((sa = addr2sa(&r->local_addr, 0, &len)) != NULL) {
1424571b47daSclaudio 		if (bind(ce->fd, sa, len) == -1) {
1425bd9df44eSclaudio 			log_warn("rtr %s: bind to %s", r->descr,
1426bd9df44eSclaudio 			    log_addr(&r->local_addr));
1427cd16358eSclaudio 			goto fail;
1428bd9df44eSclaudio 		}
1429bd9df44eSclaudio 	}
1430bd9df44eSclaudio 
1431195c91bbSclaudio 	sa = addr2sa(&r->remote_addr, r->remote_port, &len);
1432571b47daSclaudio 	if (connect(ce->fd, sa, len) == -1) {
1433571b47daSclaudio 		if (errno != EINPROGRESS) {
1434bd9df44eSclaudio 			log_warn("rtr %s: connect to %s:%u", r->descr,
1435bd9df44eSclaudio 			    log_addr(&r->remote_addr), r->remote_port);
1436cd16358eSclaudio 			goto fail;
1437571b47daSclaudio 		}
1438571b47daSclaudio 		TAILQ_INSERT_TAIL(&connect_queue, ce, entry);
1439571b47daSclaudio 		connect_cnt++;
1440bd9df44eSclaudio 		return;
1441bd9df44eSclaudio 	}
1442bd9df44eSclaudio 
1443cd16358eSclaudio 	imsg_compose(ibuf_rtr, IMSG_SOCKET_SETUP, ce->id, 0, ce->fd, NULL, 0);
1444cd16358eSclaudio 	TAILQ_INSERT_TAIL(&socket_queue, ce, entry);
1445cd16358eSclaudio 	return;
1446cd16358eSclaudio 
1447cd16358eSclaudio  fail:
1448cd16358eSclaudio 	if (ce->fd != -1)
1449cd16358eSclaudio 		close(ce->fd);
1450571b47daSclaudio 	free(ce);
1451571b47daSclaudio }
1452571b47daSclaudio 
1453571b47daSclaudio void
1454cd16358eSclaudio bgpd_rtr_conn_setup_done(int fd, struct bgpd_config *conf)
1455571b47daSclaudio {
1456571b47daSclaudio 	struct rtr_config *r;
1457571b47daSclaudio 	struct connect_elm *ce;
1458571b47daSclaudio 	int error = 0;
1459571b47daSclaudio 	socklen_t len;
1460571b47daSclaudio 
1461571b47daSclaudio 	TAILQ_FOREACH(ce, &connect_queue, entry) {
1462571b47daSclaudio 		if (ce->fd == fd)
1463571b47daSclaudio 			break;
1464571b47daSclaudio 	}
1465571b47daSclaudio 	if (ce == NULL)
1466571b47daSclaudio 		fatalx("connect entry not found");
1467571b47daSclaudio 
1468571b47daSclaudio 	TAILQ_REMOVE(&connect_queue, ce, entry);
1469571b47daSclaudio 	connect_cnt--;
1470571b47daSclaudio 
1471571b47daSclaudio 	SIMPLEQ_FOREACH(r, &conf->rtrs, entry) {
1472571b47daSclaudio 		if (ce->id == r->id)
1473571b47daSclaudio 			break;
1474571b47daSclaudio 	}
1475571b47daSclaudio 	if (r == NULL) {
1476571b47daSclaudio 		log_warnx("rtr id %d no longer exists", ce->id);
1477571b47daSclaudio 		goto fail;
1478571b47daSclaudio 	}
1479571b47daSclaudio 
1480571b47daSclaudio 	len = sizeof(error);
1481571b47daSclaudio 	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) == -1) {
1482571b47daSclaudio 		log_warn("rtr %s: getsockopt SO_ERROR", r->descr);
1483571b47daSclaudio 		goto fail;
1484571b47daSclaudio 	}
1485571b47daSclaudio 
1486571b47daSclaudio 	if (error != 0) {
1487571b47daSclaudio 		errno = error;
1488571b47daSclaudio 		log_warn("rtr %s: connect to %s:%u", r->descr,
1489571b47daSclaudio 		    log_addr(&r->remote_addr), r->remote_port);
1490571b47daSclaudio 		goto fail;
1491571b47daSclaudio 	}
1492571b47daSclaudio 
1493cd16358eSclaudio 	imsg_compose(ibuf_rtr, IMSG_SOCKET_SETUP, ce->id, 0, ce->fd, NULL, 0);
1494cd16358eSclaudio 	TAILQ_INSERT_TAIL(&socket_queue, ce, entry);
1495571b47daSclaudio 	return;
1496571b47daSclaudio 
1497571b47daSclaudio fail:
1498571b47daSclaudio 	close(fd);
1499571b47daSclaudio 	free(ce);
1500bd9df44eSclaudio }
1501cd16358eSclaudio 
1502cd16358eSclaudio void
1503cd16358eSclaudio bgpd_rtr_conn_teardown(uint32_t id)
1504cd16358eSclaudio {
1505cd16358eSclaudio 	struct connect_elm *ce;
1506cd16358eSclaudio 
1507cd16358eSclaudio 	TAILQ_FOREACH(ce, &socket_queue, entry) {
1508cd16358eSclaudio 		if (ce->id == id) {
1509cd16358eSclaudio 			pfkey_remove(&ce->auth_state);
1510cd16358eSclaudio 			TAILQ_REMOVE(&socket_queue, ce, entry);
1511cd16358eSclaudio 			free(ce);
1512cd16358eSclaudio 			return;
1513cd16358eSclaudio 		}
1514cd16358eSclaudio 	}
1515cd16358eSclaudio }
1516