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