bgpd.c revision 1.50
185587Sobrien/* $OpenBSD: bgpd.c,v 1.50 2004/01/03 14:06:35 henning Exp $ */ 285587Sobrien 385587Sobrien/* 485587Sobrien * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 585587Sobrien * 685587Sobrien * Permission to use, copy, modify, and distribute this software for any 785587Sobrien * purpose with or without fee is hereby granted, provided that the above 885587Sobrien * copyright notice and this permission notice appear in all copies. 985587Sobrien * 1085587Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1185587Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1285587Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1385587Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1485587Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1585587Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1685587Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1785587Sobrien */ 1885587Sobrien 1985587Sobrien#include <sys/types.h> 2085587Sobrien#include <sys/socket.h> 2185587Sobrien#include <sys/wait.h> 2285587Sobrien#include <netinet/in.h> 2385587Sobrien#include <arpa/inet.h> 2485587Sobrien#include <err.h> 2585587Sobrien#include <errno.h> 2685587Sobrien#include <fcntl.h> 2785587Sobrien#include <poll.h> 2885587Sobrien#include <signal.h> 2985587Sobrien#include <stdio.h> 3085587Sobrien#include <stdlib.h> 3185587Sobrien#include <string.h> 3285587Sobrien#include <unistd.h> 3385587Sobrien 3485587Sobrien#include "mrt.h" 3585587Sobrien#include "bgpd.h" 3685587Sobrien 3785587Sobrienvoid sighdlr(int); 3885587Sobrienvoid usage(void); 3985587Sobrienint main(int, char *[]); 4085587Sobrienint reconfigure(char *, struct bgpd_config *, struct mrt_config *); 4185587Sobrienint dispatch_imsg(struct imsgbuf *, int, struct mrt_config *); 4285587Sobrien 4385587Sobrienint mrtfd = -1; 4485587Sobrienint rfd = -1; 4585587Sobrienvolatile sig_atomic_t mrtdump = 0; 4685587Sobrienvolatile sig_atomic_t quit = 0; 4785587Sobrienvolatile sig_atomic_t reconfig = 0; 4885587Sobrienstruct imsgbuf ibuf_se; 4985587Sobrienstruct imsgbuf ibuf_rde; 5085587Sobrien 5185587Sobrienvoid 5285587Sobriensighdlr(int sig) 5385587Sobrien{ 5485587Sobrien switch (sig) { 5585587Sobrien case SIGTERM: 5685587Sobrien case SIGINT: 5785587Sobrien case SIGCHLD: 5885587Sobrien quit = 1; 5985587Sobrien break; 6085587Sobrien case SIGHUP: 6185587Sobrien reconfig = 1; 6285587Sobrien break; 6385587Sobrien case SIGALRM: 6485587Sobrien mrtdump = 1; 6585587Sobrien break; 6685587Sobrien case SIGUSR1: 6785587Sobrien mrtdump = 2; 6885587Sobrien break; 6985587Sobrien } 7085587Sobrien} 7185587Sobrien 7285587Sobrienvoid 7385587Sobrienusage(void) 7485587Sobrien{ 7585587Sobrien extern char *__progname; 7685587Sobrien 7785587Sobrien fprintf(stderr, "usage: %s [-dnv] ", __progname); 7885587Sobrien fprintf(stderr, "[-D macro=value] [-f file]\n"); 7985587Sobrien exit(1); 8085587Sobrien} 8185587Sobrien 8285587Sobrien#define POLL_MAX 8 8385587Sobrien#define PFD_PIPE_SESSION 0 8485587Sobrien#define PFD_PIPE_ROUTE 1 8585587Sobrien#define PFD_SOCK_ROUTE 2 8685587Sobrien#define PFD_MRT_START 3 8785587Sobrien 8885587Sobrienint 8985587Sobrienmain(int argc, char *argv[]) 9085587Sobrien{ 9185587Sobrien struct bgpd_config conf; 9285587Sobrien struct mrt_config mrtconf; 9385587Sobrien struct mrtdump_config *mconf, *(mrt[POLL_MAX]); 9485587Sobrien struct pollfd pfd[POLL_MAX]; 9585587Sobrien pid_t io_pid = 0, rde_pid = 0; 9685587Sobrien char *conffile; 9785587Sobrien int debug = 0; 9885587Sobrien int ch, i, j, n, nfds, csock; 9985587Sobrien int pipe_m2s[2]; 10085587Sobrien int pipe_m2r[2]; 10185587Sobrien int pipe_s2r[2]; 10285587Sobrien 10385587Sobrien conffile = CONFFILE; 10485587Sobrien bgpd_process = PROC_MAIN; 10585587Sobrien 10685587Sobrien log_init(1); /* log to stderr until daemonized */ 10785587Sobrien 10885587Sobrien bzero(&conf, sizeof(conf)); 10985587Sobrien bzero(&mrtconf, sizeof(mrtconf)); 11085587Sobrien LIST_INIT(&mrtconf); 11185587Sobrien 11285587Sobrien while ((ch = getopt(argc, argv, "dD:f:nv")) != -1) { 11385587Sobrien switch (ch) { 11485587Sobrien case 'd': 11585587Sobrien debug = 1; 11685587Sobrien break; 11785587Sobrien case 'D': 11885587Sobrien if (cmdline_symset(optarg) < 0) 11985587Sobrien logit(LOG_CRIT, 12085587Sobrien "could not parse macro definition %s", 12185587Sobrien optarg); 12285587Sobrien break; 12385587Sobrien case 'f': 12485587Sobrien conffile = optarg; 12585587Sobrien break; 12685587Sobrien case 'n': 12785587Sobrien conf.opts |= BGPD_OPT_NOACTION; 12885587Sobrien break; 12985587Sobrien case 'v': 13085587Sobrien if (conf.opts & BGPD_OPT_VERBOSE) 13185587Sobrien conf.opts |= BGPD_OPT_VERBOSE2; 13285587Sobrien conf.opts |= BGPD_OPT_VERBOSE; 13385587Sobrien break; 13485587Sobrien default: 13585587Sobrien usage(); 13685587Sobrien /* NOTREACHED */ 13785587Sobrien } 13885587Sobrien } 13985587Sobrien 14085587Sobrien if (parse_config(conffile, &conf, &mrtconf)) 14185587Sobrien exit(1); 14285587Sobrien 14385587Sobrien if (conf.opts & BGPD_OPT_NOACTION) { 14485587Sobrien fprintf(stderr, "configuration OK\n"); 14585587Sobrien exit(0); 14685587Sobrien } 14785587Sobrien 14885587Sobrien if (geteuid()) 14985587Sobrien errx(1, "need root privileges"); 15085587Sobrien 15185587Sobrien log_init(debug); 15285587Sobrien 15385587Sobrien if (!debug) 15485587Sobrien daemon(1, 0); 15585587Sobrien 15685587Sobrien logit(LOG_INFO, "startup"); 15785587Sobrien 15885587Sobrien if (pipe(pipe_m2s) == -1) 15985587Sobrien fatal("pipe"); 16085587Sobrien if (fcntl(pipe_m2s[0], F_SETFL, O_NONBLOCK) == -1 || 16185587Sobrien fcntl(pipe_m2s[1], F_SETFL, O_NONBLOCK) == -1) 16285587Sobrien fatal("fcntl"); 16385587Sobrien if (pipe(pipe_m2r) == -1) 16485587Sobrien fatal("pipe"); 16585587Sobrien if (fcntl(pipe_m2r[0], F_SETFL, O_NONBLOCK) == -1 || 16685587Sobrien fcntl(pipe_m2r[1], F_SETFL, O_NONBLOCK) == -1) 16785587Sobrien fatal("fcntl"); 16885587Sobrien if (pipe(pipe_s2r) == -1) 16985587Sobrien fatal("pipe"); 17085587Sobrien if (fcntl(pipe_s2r[0], F_SETFL, O_NONBLOCK) == -1 || 17185587Sobrien fcntl(pipe_s2r[1], F_SETFL, O_NONBLOCK) == -1) 17285587Sobrien fatal("fcntl"); 17385587Sobrien 17485587Sobrien if ((csock = control_init()) == -1) 17585587Sobrien fatalx("control socket setup failed"); 17685587Sobrien 17785587Sobrien /* fork children */ 17885587Sobrien rde_pid = rde_main(&conf, pipe_m2r, pipe_s2r); 17985587Sobrien io_pid = session_main(&conf, pipe_m2s, pipe_s2r); 18085587Sobrien 18185587Sobrien setproctitle("parent"); 18285587Sobrien 18385587Sobrien signal(SIGTERM, sighdlr); 18485587Sobrien signal(SIGINT, sighdlr); 18585587Sobrien signal(SIGCHLD, sighdlr); 18685587Sobrien signal(SIGHUP, sighdlr); 18785587Sobrien signal(SIGALRM, sighdlr); 18885587Sobrien signal(SIGUSR1, sighdlr); 18985587Sobrien 19085587Sobrien close(pipe_m2s[1]); 19185587Sobrien close(pipe_m2r[1]); 19285587Sobrien close(pipe_s2r[0]); 19385587Sobrien close(pipe_s2r[1]); 19485587Sobrien close(csock); 19585587Sobrien 19685587Sobrien imsg_init(&ibuf_se, pipe_m2s[0]); 19785587Sobrien imsg_init(&ibuf_rde, pipe_m2r[0]); 19885587Sobrien if ((rfd = kroute_init(!(conf.flags & BGPD_FLAG_NO_FIB_UPDATE))) == -1) 19985587Sobrien quit = 1; 20085587Sobrien 20185587Sobrien while (quit == 0) { 20285587Sobrien pfd[PFD_PIPE_SESSION].fd = ibuf_se.sock; 20385587Sobrien pfd[PFD_PIPE_SESSION].events = POLLIN; 20485587Sobrien if (ibuf_se.w.queued) 20585587Sobrien pfd[PFD_PIPE_SESSION].events |= POLLOUT; 20685587Sobrien pfd[PFD_PIPE_ROUTE].fd = ibuf_rde.sock; 20785587Sobrien pfd[PFD_PIPE_ROUTE].events = POLLIN; 20885587Sobrien if (ibuf_rde.w.queued) 20985587Sobrien pfd[PFD_PIPE_ROUTE].events |= POLLOUT; 21085587Sobrien pfd[PFD_SOCK_ROUTE].fd = rfd; 21185587Sobrien pfd[PFD_SOCK_ROUTE].events = POLLIN; 21285587Sobrien i = PFD_MRT_START; 21385587Sobrien LIST_FOREACH(mconf, &mrtconf, list) 21485587Sobrien if (mconf->msgbuf.queued > 0) { 21585587Sobrien pfd[i].fd = mconf->msgbuf.sock; 21685587Sobrien pfd[i].events |= POLLOUT; 21785587Sobrien mrt[i++] = mconf; 21885587Sobrien } 21985587Sobrien 22085587Sobrien if ((nfds = poll(pfd, i, INFTIM)) == -1) 22185587Sobrien if (errno != EINTR) { 22285587Sobrien log_err("poll error"); 22385587Sobrien quit = 1; 22485587Sobrien } 22585587Sobrien 22685587Sobrien if (nfds > 0 && (pfd[PFD_PIPE_SESSION].revents & POLLOUT)) 22785587Sobrien if ((n = msgbuf_write(&ibuf_se.w)) < 0) { 22885587Sobrien log_err("pipe write error (to SE)"); 22985587Sobrien quit = 1; 23085587Sobrien } 23185587Sobrien 23285587Sobrien if (nfds > 0 && (pfd[PFD_PIPE_ROUTE].revents & POLLOUT)) 23385587Sobrien if ((n = msgbuf_write(&ibuf_rde.w)) < 0) { 23485587Sobrien log_err("pipe write error (to RDE)"); 23585587Sobrien quit = 1; 23685587Sobrien } 23785587Sobrien 23885587Sobrien if (nfds > 0 && pfd[PFD_PIPE_SESSION].revents & POLLIN) { 23985587Sobrien nfds--; 24085587Sobrien if (dispatch_imsg(&ibuf_se, PFD_PIPE_SESSION, 24185587Sobrien &mrtconf) == -1) 24285587Sobrien quit = 1; 24385587Sobrien } 24485587Sobrien 24585587Sobrien if (nfds > 0 && pfd[PFD_PIPE_ROUTE].revents & POLLIN) { 24685587Sobrien nfds--; 24785587Sobrien if (dispatch_imsg(&ibuf_rde, PFD_PIPE_ROUTE, 24885587Sobrien &mrtconf) == -1) 24985587Sobrien quit = 1; 25085587Sobrien } 25185587Sobrien 25285587Sobrien if (nfds > 0 && pfd[PFD_SOCK_ROUTE].revents & POLLIN) { 25385587Sobrien nfds--; 25485587Sobrien if (kroute_dispatch_msg() == -1) 25585587Sobrien quit = 1; 256107806Sobrien } 25785587Sobrien 25885587Sobrien for (j = PFD_MRT_START; j < i && nfds > 0 ; j++) { 25985587Sobrien if (pfd[j].revents & POLLOUT) { 26085587Sobrien if ((n = msgbuf_write(&mrt[i]->msgbuf)) < 0) { 26185587Sobrien log_err("pipe write error (MRT)"); 26285587Sobrien quit = 1; 26385587Sobrien } 26485587Sobrien } 26585587Sobrien } 26685587Sobrien 26785587Sobrien if (reconfig) { 26885587Sobrien logit(LOG_CRIT, "rereading config"); 26985587Sobrien reconfigure(conffile, &conf, &mrtconf); 27085587Sobrien LIST_FOREACH(mconf, &mrtconf, list) 27185587Sobrien mrt_state(mconf, IMSG_NONE, &ibuf_rde); 27285587Sobrien reconfig = 0; 27385587Sobrien } 27485587Sobrien 27585587Sobrien if (mrtdump == 1) { 27685587Sobrien mrt_alrm(&mrtconf, &ibuf_rde); 277 mrtdump = 0; 278 } else if (mrtdump == 2) { 279 mrt_usr1(&mrtconf, &ibuf_rde); 280 mrtdump = 0; 281 } 282 } 283 284 signal(SIGCHLD, SIG_IGN); 285 286 if (io_pid) 287 kill(io_pid, SIGTERM); 288 289 if (rde_pid) 290 kill(rde_pid, SIGTERM); 291 292 do { 293 i = waitpid(-1, NULL, WNOHANG); 294 } while (i > 0 || (i == -1 && errno == EINTR)); 295 296 control_cleanup(); 297 kroute_shutdown(); 298 299 logit(LOG_CRIT, "Terminating"); 300 return (0); 301} 302 303int 304reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_config *mrtc) 305{ 306 struct peer *p; 307 308 if (parse_config(conffile, conf, mrtc)) { 309 logit(LOG_CRIT, "config file %s has errors, not reloading", 310 conffile); 311 return (-1); 312 } 313 314 if (imsg_compose(&ibuf_se, IMSG_RECONF_CONF, 0, 315 conf, sizeof(struct bgpd_config)) == -1) 316 return (-1); 317 if (imsg_compose(&ibuf_rde, IMSG_RECONF_CONF, 0, 318 conf, sizeof(struct bgpd_config)) == -1) 319 return (-1); 320 for (p = conf->peers; p != NULL; p = p->next) { 321 if (imsg_compose(&ibuf_se, IMSG_RECONF_PEER, p->conf.id, 322 &p->conf, sizeof(struct peer_config)) == -1) 323 return (-1); 324 if (imsg_compose(&ibuf_rde, IMSG_RECONF_PEER, p->conf.id, 325 &p->conf, sizeof(struct peer_config)) == -1) 326 return (-1); 327 } 328 if (imsg_compose(&ibuf_se, IMSG_RECONF_DONE, 0, NULL, 0) == -1 || 329 imsg_compose(&ibuf_rde, IMSG_RECONF_DONE, 0, NULL, 0) == -1) 330 return (-1); 331 332 return (0); 333} 334 335/* 336 * XXX currently messages are only buffered for mrt files. 337 */ 338int 339dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_config *conf) 340{ 341 struct imsg imsg; 342 struct buf *wbuf; 343 struct mrtdump_config *m; 344 ssize_t len; 345 int n; 346 in_addr_t ina; 347 348 if ((n = imsg_read(ibuf)) == -1) 349 return (-1); 350 351 if (n == 0) { /* connection closed */ 352 logit(LOG_CRIT, "dispatch_imsg in main: pipe closed"); 353 return (-1); 354 } 355 356 for (;;) { 357 if ((n = imsg_get(ibuf, &imsg)) == -1) 358 return (-1); 359 360 if (n == 0) 361 break; 362 363 switch (imsg.hdr.type) { 364 case IMSG_MRT_MSG: 365 case IMSG_MRT_END: 366 LIST_FOREACH(m, conf, list) { 367 if (m->id != imsg.hdr.peerid) 368 continue; 369 if (mrt_state(m, imsg.hdr.type, ibuf) == 0) 370 break; 371 if (m->msgbuf.sock == -1) 372 break; 373 len = imsg.hdr.len - IMSG_HEADER_SIZE; 374 wbuf = buf_open(len); 375 if (wbuf == NULL) 376 return (-1); 377 if (buf_add(wbuf, imsg.data, len) == -1) { 378 buf_free(wbuf); 379 return (-1); 380 } 381 if ((n = buf_close(&m->msgbuf, wbuf)) < 0) { 382 buf_free(wbuf); 383 return (-1); 384 } 385 break; 386 } 387 break; 388 case IMSG_KROUTE_CHANGE: 389 if (idx != PFD_PIPE_ROUTE) 390 logit(LOG_CRIT, "route request not from RDE"); 391 else if (kroute_change(imsg.data)) 392 return (-1); 393 break; 394 case IMSG_KROUTE_DELETE: 395 if (idx != PFD_PIPE_ROUTE) 396 logit(LOG_CRIT, "route request not from RDE"); 397 else if (kroute_delete(imsg.data)) 398 return (-1); 399 break; 400 case IMSG_NEXTHOP_ADD: 401 if (idx != PFD_PIPE_ROUTE) 402 logit(LOG_CRIT, "nexthop request not from RDE"); 403 else { 404 memcpy(&ina, imsg.data, sizeof(ina)); 405 if (kroute_nexthop_add(ina) == -1) 406 return (-1); 407 } 408 break; 409 case IMSG_NEXTHOP_REMOVE: 410 if (idx != PFD_PIPE_ROUTE) 411 logit(LOG_CRIT, "nexthop request not from RDE"); 412 else { 413 memcpy(&ina, imsg.data, sizeof(ina)); 414 kroute_nexthop_delete(ina); 415 } 416 break; 417 default: 418 break; 419 } 420 imsg_free(&imsg); 421 } 422 return (0); 423} 424 425void 426send_nexthop_update(struct kroute_nexthop *msg) 427{ 428 char *gw = NULL; 429 430 if (msg->gateway) 431 if (asprintf(&gw, ": via %s", log_ntoa(msg->gateway)) == -1) { 432 log_err("send_nexthop_update"); 433 quit = 1; 434 } 435 436 logit(LOG_INFO, "nexthop %s now %s%s%s", log_ntoa(msg->nexthop), 437 msg->valid ? "valid" : "invalid", 438 msg->connected ? ": directly connected" : "", 439 msg->gateway ? gw : ""); 440 441 free(gw); 442 443 if (imsg_compose(&ibuf_rde, IMSG_NEXTHOP_UPDATE, 0, 444 msg, sizeof(struct kroute_nexthop)) == -1) 445 quit = 1; 446} 447