bgpd.c revision 1.21
1/* $OpenBSD: bgpd.c,v 1.21 2003/12/23 19:14:49 deraadt Exp $ */ 2 3/* 4 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/types.h> 20#include <sys/socket.h> 21#include <sys/wait.h> 22#include <netinet/in.h> 23#include <arpa/inet.h> 24#include <err.h> 25#include <errno.h> 26#include <fcntl.h> 27#include <poll.h> 28#include <signal.h> 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include <unistd.h> 33 34#include "mrt.h" 35#include "bgpd.h" 36 37void sighdlr(int); 38void usage(void); 39int main(int, char *[]); 40int reconfigure(char *, struct bgpd_config *, struct mrt_config *); 41int dispatch_imsg(struct imsgbuf *, int, struct mrt_config *); 42 43int mrtfd = -1; 44int rfd = -1; 45volatile sig_atomic_t mrtdump = 0; 46volatile sig_atomic_t quit = 0; 47volatile sig_atomic_t reconfig = 0; 48struct imsgbuf ibuf_se; 49struct imsgbuf ibuf_rde; 50int se_done = 0; 51int rde_done = 0; 52 53#define QUIT_REQUESTED 1 54#define QUIT_INPROGRESS 2 55 56void 57sighdlr(int sig) 58{ 59 switch (sig) { 60 case SIGTERM: 61 case SIGINT: 62 case SIGCHLD: 63 quit = QUIT_REQUESTED; 64 break; 65 case SIGHUP: 66 reconfig = 1; 67 break; 68 case SIGALRM: 69 mrtdump = 1; 70 break; 71 case SIGUSR1: 72 mrtdump = 2; 73 break; 74 } 75} 76 77void 78usage(void) 79{ 80 extern char *__progname; 81 82 fprintf(stderr, "usage: %s [-dnv] ", __progname); 83 fprintf(stderr, "[-D macro=value] [-f file]\n"); 84 exit(1); 85} 86 87#define POLL_MAX 8 88#define PFD_PIPE_SESSION 0 89#define PFD_PIPE_ROUTE 1 90#define PFD_MRT_START 2 91 92int 93main(int argc, char *argv[]) 94{ 95 struct bgpd_config conf; 96 struct mrt_config mrtconf; 97 struct mrtdump_config *mconf, *(mrt[POLL_MAX]); 98 struct pollfd pfd[POLL_MAX]; 99 pid_t io_pid = 0, rde_pid = 0; 100 char *conffile; 101 int debug = 0; 102 int ch, i, j, n, nfds; 103 int pipe_m2s[2]; 104 int pipe_m2r[2]; 105 int pipe_s2r[2]; 106 107 conffile = CONFFILE; 108 bgpd_process = PROC_MAIN; 109 110 log_init(1); /* log to stderr until daemonized */ 111 112 bzero(&conf, sizeof(conf)); 113 bzero(&mrtconf, sizeof(mrtconf)); 114 LIST_INIT(&mrtconf); 115 116 while ((ch = getopt(argc, argv, "dD:f:nv")) != -1) { 117 switch (ch) { 118 case 'd': 119 debug = 1; 120 break; 121 case 'D': 122 if (cmdline_symset(optarg) < 0) 123 logit(LOG_CRIT, 124 "could not parse macro definition %s", 125 optarg); 126 break; 127 case 'f': 128 conffile = optarg; 129 break; 130 case 'n': 131 conf.opts |= BGPD_OPT_NOACTION; 132 break; 133 case 'v': 134 if (conf.opts & BGPD_OPT_VERBOSE) 135 conf.opts |= BGPD_OPT_VERBOSE2; 136 conf.opts |= BGPD_OPT_VERBOSE; 137 break; 138 default: 139 usage(); 140 /* NOTREACHED */ 141 } 142 } 143 144 if (parse_config(conffile, &conf, &mrtconf)) 145 exit(1); 146 147 if (conf.opts & BGPD_OPT_NOACTION) { 148 fprintf(stderr, "configuration OK\n"); 149 exit(0); 150 } 151 152 if (geteuid()) 153 errx(1, "need root privileges"); 154 155 log_init(debug); 156 157 if (!debug) 158 daemon(1, 0); 159 160 logit(LOG_INFO, "startup"); 161 162 if (pipe(pipe_m2s) == -1) 163 fatal("pipe", errno); 164 if (fcntl(pipe_m2s[0], F_SETFL, O_NONBLOCK) == -1 || 165 fcntl(pipe_m2s[1], F_SETFL, O_NONBLOCK) == -1) 166 fatal("fcntl", errno); 167 if (pipe(pipe_m2r) == -1) 168 fatal("pipe", errno); 169 if (fcntl(pipe_m2r[0], F_SETFL, O_NONBLOCK) == -1 || 170 fcntl(pipe_m2r[1], F_SETFL, O_NONBLOCK) == -1) 171 fatal("fcntl", errno); 172 if (pipe(pipe_s2r) == -1) 173 fatal("pipe", errno); 174 if (fcntl(pipe_s2r[0], F_SETFL, O_NONBLOCK) == -1 || 175 fcntl(pipe_s2r[1], F_SETFL, O_NONBLOCK) == -1) 176 fatal("fcntl", errno); 177 178 if ((rde_pid = rde_main(&conf, pipe_m2r, pipe_s2r)) < 0) 179 fatal("could not start route decision engine", 0); 180 181 if ((io_pid = session_main(&conf, pipe_m2s, pipe_s2r)) < 0) 182 fatal("could not start session engine", 0); 183 184 setproctitle("parent"); 185 186 signal(SIGTERM, sighdlr); 187 signal(SIGINT, sighdlr); 188 signal(SIGCHLD, sighdlr); 189 signal(SIGHUP, sighdlr); 190 signal(SIGALRM, sighdlr); 191 signal(SIGUSR1, sighdlr); 192 193 close(pipe_m2s[1]); 194 close(pipe_m2r[1]); 195 close(pipe_s2r[0]); 196 close(pipe_s2r[1]); 197 198 imsg_init(&ibuf_se, pipe_m2s[0]); 199 imsg_init(&ibuf_rde, pipe_m2r[0]); 200 rfd = kroute_init(); 201 202 while (quit != QUIT_INPROGRESS || se_done == 0 || rde_done == 0) { 203 pfd[PFD_PIPE_SESSION].fd = ibuf_se.sock; 204 pfd[PFD_PIPE_SESSION].events = POLLIN; 205 if (ibuf_se.w.queued) 206 pfd[PFD_PIPE_SESSION].events |= POLLOUT; 207 pfd[PFD_PIPE_ROUTE].fd = ibuf_rde.sock; 208 pfd[PFD_PIPE_ROUTE].events = POLLIN; 209 if (ibuf_rde.w.queued) 210 pfd[PFD_PIPE_ROUTE].events |= POLLOUT; 211 i = PFD_MRT_START; 212 LIST_FOREACH(mconf, &mrtconf, list) 213 if (mconf->msgbuf.queued > 0) { 214 pfd[i].fd = mconf->msgbuf.sock; 215 pfd[i].events |= POLLOUT; 216 mrt[i++] = mconf; 217 } 218 219 if ((nfds = poll(pfd, 2, INFTIM)) == -1) 220 if (errno != EINTR) 221 fatal("poll error", errno); 222 223 if (nfds > 0 && (pfd[PFD_PIPE_SESSION].revents & POLLOUT)) 224 if ((n = msgbuf_write(&ibuf_se.w)) == -1) 225 fatal("pipe write error", errno); 226 227 if (nfds > 0 && (pfd[PFD_PIPE_ROUTE].revents & POLLOUT)) 228 if ((n = msgbuf_write(&ibuf_rde.w)) == -1) 229 fatal("pipe write error", errno); 230 231 if (nfds > 0 && pfd[PFD_PIPE_SESSION].revents & POLLIN) { 232 nfds--; 233 dispatch_imsg(&ibuf_se, PFD_PIPE_SESSION, &mrtconf); 234 } 235 236 if (nfds > 0 && pfd[PFD_PIPE_ROUTE].revents & POLLIN) { 237 nfds--; 238 dispatch_imsg(&ibuf_rde, PFD_PIPE_ROUTE, &mrtconf); 239 } 240 241 for (j = PFD_MRT_START; j < i && nfds > 0 ; j++) { 242 if (pfd[j].revents & POLLOUT) { 243 if ((n = msgbuf_write(&mrt[i]->msgbuf)) == -1) 244 fatal("pipe write error", errno); 245 } 246 } 247 248 if (reconfig) { 249 logit(LOG_CRIT, "rereading config"); 250 reconfigure(conffile, &conf, &mrtconf); 251 LIST_FOREACH(mconf, &mrtconf, list) 252 mrt_state(mconf, IMSG_NONE, &ibuf_rde); 253 reconfig = 0; 254 } 255 256 if (quit == QUIT_REQUESTED) { 257 imsg_compose(&ibuf_se, IMSG_SHUTDOWN_REQUEST, 0, 258 NULL, 0); 259 imsg_compose(&ibuf_rde, IMSG_SHUTDOWN_REQUEST, 0, 260 NULL, 0); 261 quit = QUIT_INPROGRESS; 262 } 263 264 if (mrtdump == 1) { 265 mrt_alrm(&mrtconf, &ibuf_rde); 266 mrtdump = 0; 267 } else if (mrtdump == 2) { 268 mrt_usr1(&mrtconf, &ibuf_rde); 269 mrtdump = 0; 270 } 271 } 272 273 signal(SIGCHLD, SIG_IGN); 274 275 if (io_pid) 276 kill(io_pid, SIGTERM); 277 278 if (rde_pid) 279 kill(rde_pid, SIGTERM); 280 281 do { 282 i = waitpid(-1, NULL, WNOHANG); 283 } while (i > 0 || (i == -1 && errno == EINTR)); 284 285 logit(LOG_CRIT, "Terminating"); 286 return (0); 287} 288 289int 290reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_config *mrtc) 291{ 292 struct peer *p; 293 294 if (parse_config(conffile, conf, mrtc)) { 295 logit(LOG_CRIT, "config file %s has errors, not reloading", 296 conffile); 297 return (-1); 298 } 299 imsg_compose(&ibuf_se, IMSG_RECONF_CONF, 0, 300 conf, sizeof(struct bgpd_config)); 301 imsg_compose(&ibuf_rde, IMSG_RECONF_CONF, 0, 302 conf, sizeof(struct bgpd_config)); 303 for (p = conf->peers; p != NULL; p = p->next) { 304 imsg_compose(&ibuf_se, IMSG_RECONF_PEER, p->conf.id, 305 &p->conf, sizeof(struct peer_config)); 306 imsg_compose(&ibuf_rde, IMSG_RECONF_PEER, p->conf.id, 307 &p->conf, sizeof(struct peer_config)); 308 } 309 imsg_compose(&ibuf_se, IMSG_RECONF_DONE, 0, NULL, 0); 310 imsg_compose(&ibuf_rde, IMSG_RECONF_DONE, 0, NULL, 0); 311 312 return (0); 313} 314 315/* 316 * XXX currently messages are only buffered for mrt files. 317 */ 318int 319dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_config *conf) 320{ 321 struct imsg imsg; 322 struct buf *wbuf; 323 struct mrtdump_config *m; 324 ssize_t len; 325 int n; 326 327 if (imsg_get(ibuf, &imsg) > 0) { 328 switch (imsg.hdr.type) { 329 case IMSG_MRT_MSG: 330 case IMSG_MRT_END: 331 LIST_FOREACH(m, conf, list) { 332 if (m->id != imsg.hdr.peerid) 333 continue; 334 if (mrt_state(m, imsg.hdr.type, ibuf) == 0) 335 break; 336 if (m->msgbuf.sock == -1) 337 break; 338 len = imsg.hdr.len - IMSG_HEADER_SIZE; 339 wbuf = buf_open(len); 340 if (wbuf == NULL) 341 fatal("buf_open error", 0); 342 if (buf_add(wbuf, imsg.data, len) == -1) 343 fatal("buf_add error", 0); 344 if ((n = buf_close(&m->msgbuf, wbuf)) == -1) 345 fatal("buf_close error", 0); 346 break; 347 } 348 break; 349 case IMSG_KROUTE_ADD: 350 if (idx != PFD_PIPE_ROUTE) 351 fatal("route request not from RDE", 0); 352 if (kroute_add(rfd, imsg.data)) 353 fatal("kroute bytes left", 0); 354 break; 355 case IMSG_KROUTE_CHANGE: 356 if (idx != PFD_PIPE_ROUTE) 357 fatal("route request not from RDE", 0); 358 if (kroute_change(rfd, imsg.data)) 359 fatal("kroute bytes left", 0); 360 case IMSG_KROUTE_DELETE: 361 if (idx != PFD_PIPE_ROUTE) 362 fatal("route request not from RDE", 0); 363 if (kroute_delete(rfd, imsg.data)) 364 fatal("kroute bytes left", 0); 365 break; 366 case IMSG_SHUTDOWN_DONE: 367 if (idx == PFD_PIPE_ROUTE) 368 rde_done = 1; 369 else 370 se_done = 1; 371 break; 372 default: 373 break; 374 } 375 imsg_free(&imsg); 376 } 377 return (0); 378} 379 380