bgpd.c revision 1.61
1/* $OpenBSD: bgpd.c,v 1.61 2004/01/09 19:08:50 henning Exp $ */ 2 3/* 4 * Copyright (c) 2003, 2004 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#include "session.h" 37 38void sighdlr(int); 39void usage(void); 40int main(int, char *[]); 41int check_child(pid_t, const char *); 42int reconfigure(char *, struct bgpd_config *, struct mrt_head *, 43 struct peer *); 44int dispatch_imsg(struct imsgbuf *, int, struct mrt_head *); 45 46int rfd = -1; 47volatile sig_atomic_t mrtdump = 0; 48volatile sig_atomic_t quit = 0; 49volatile sig_atomic_t reconfig = 0; 50volatile sig_atomic_t sigchld = 0; 51struct imsgbuf ibuf_se; 52struct imsgbuf ibuf_rde; 53 54void 55sighdlr(int sig) 56{ 57 switch (sig) { 58 case SIGTERM: 59 case SIGINT: 60 quit = 1; 61 break; 62 case SIGCHLD: 63 sigchld = 1; 64 break; 65 case SIGHUP: 66 reconfig = 1; 67 break; 68 case SIGALRM: 69 case SIGUSR1: 70 mrtdump = 1; 71 break; 72 } 73} 74 75void 76usage(void) 77{ 78 extern char *__progname; 79 80 fprintf(stderr, "usage: %s [-dnv] ", __progname); 81 fprintf(stderr, "[-D macro=value] [-f file]\n"); 82 exit(1); 83} 84 85#define POLL_MAX 8 86#define PFD_PIPE_SESSION 0 87#define PFD_PIPE_ROUTE 1 88#define PFD_SOCK_ROUTE 2 89#define PFD_MRT_START 3 90 91int 92main(int argc, char *argv[]) 93{ 94 struct bgpd_config conf; 95 struct peer *peer_l, *p, *next; 96 struct mrt_head mrtconf; 97 struct mrt *(mrt[POLL_MAX]); 98 struct pollfd pfd[POLL_MAX]; 99 pid_t io_pid = 0, rde_pid = 0, pid; 100 char *conffile; 101 int debug = 0; 102 int ch, csock, i, j, n, nfds, timeout; 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 LIST_INIT(&mrtconf); 114 peer_l = NULL; 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, &peer_l)) 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"); 164 if (fcntl(pipe_m2s[0], F_SETFL, O_NONBLOCK) == -1 || 165 fcntl(pipe_m2s[1], F_SETFL, O_NONBLOCK) == -1) 166 fatal("fcntl"); 167 if (pipe(pipe_m2r) == -1) 168 fatal("pipe"); 169 if (fcntl(pipe_m2r[0], F_SETFL, O_NONBLOCK) == -1 || 170 fcntl(pipe_m2r[1], F_SETFL, O_NONBLOCK) == -1) 171 fatal("fcntl"); 172 if (pipe(pipe_s2r) == -1) 173 fatal("pipe"); 174 if (fcntl(pipe_s2r[0], F_SETFL, O_NONBLOCK) == -1 || 175 fcntl(pipe_s2r[1], F_SETFL, O_NONBLOCK) == -1) 176 fatal("fcntl"); 177 178 if ((csock = control_init()) == -1) 179 fatalx("control socket setup failed"); 180 181 /* fork children */ 182 rde_pid = rde_main(&conf, peer_l, pipe_m2r, pipe_s2r); 183 io_pid = session_main(&conf, peer_l, pipe_m2s, pipe_s2r); 184 185 setproctitle("parent"); 186 187 signal(SIGTERM, sighdlr); 188 signal(SIGINT, sighdlr); 189 signal(SIGCHLD, sighdlr); 190 signal(SIGHUP, sighdlr); 191 signal(SIGALRM, sighdlr); 192 signal(SIGUSR1, sighdlr); 193 194 close(pipe_m2s[1]); 195 close(pipe_m2r[1]); 196 close(pipe_s2r[0]); 197 close(pipe_s2r[1]); 198 close(csock); 199 200 imsg_init(&ibuf_se, pipe_m2s[0]); 201 imsg_init(&ibuf_rde, pipe_m2r[0]); 202 mrt_init(&ibuf_rde, &ibuf_se); 203 if ((rfd = kr_init(!(conf.flags & BGPD_FLAG_NO_FIB_UPDATE))) == -1) 204 quit = 1; 205 206 for (p = peer_l; p != NULL; p = next) { 207 next = p->next; 208 free(p); 209 } 210 211 while (quit == 0) { 212 pfd[PFD_PIPE_SESSION].fd = ibuf_se.sock; 213 pfd[PFD_PIPE_SESSION].events = POLLIN; 214 if (ibuf_se.w.queued) 215 pfd[PFD_PIPE_SESSION].events |= POLLOUT; 216 pfd[PFD_PIPE_ROUTE].fd = ibuf_rde.sock; 217 pfd[PFD_PIPE_ROUTE].events = POLLIN; 218 if (ibuf_rde.w.queued) 219 pfd[PFD_PIPE_ROUTE].events |= POLLOUT; 220 pfd[PFD_SOCK_ROUTE].fd = rfd; 221 pfd[PFD_SOCK_ROUTE].events = POLLIN; 222 i = PFD_MRT_START; 223 i = mrt_select(&mrtconf, pfd, mrt, i, POLL_MAX, &timeout); 224 225 if ((nfds = poll(pfd, i, INFTIM)) == -1) 226 if (errno != EINTR) { 227 log_err("poll error"); 228 quit = 1; 229 } 230 231 if (nfds > 0 && (pfd[PFD_PIPE_SESSION].revents & POLLOUT)) 232 if ((n = msgbuf_write(&ibuf_se.w)) < 0) { 233 log_err("pipe write error (to SE)"); 234 quit = 1; 235 } 236 237 if (nfds > 0 && (pfd[PFD_PIPE_ROUTE].revents & POLLOUT)) 238 if ((n = msgbuf_write(&ibuf_rde.w)) < 0) { 239 log_err("pipe write error (to RDE)"); 240 quit = 1; 241 } 242 243 if (nfds > 0 && pfd[PFD_PIPE_SESSION].revents & POLLIN) { 244 nfds--; 245 if (dispatch_imsg(&ibuf_se, PFD_PIPE_SESSION, 246 &mrtconf) == -1) 247 quit = 1; 248 } 249 250 if (nfds > 0 && pfd[PFD_PIPE_ROUTE].revents & POLLIN) { 251 nfds--; 252 if (dispatch_imsg(&ibuf_rde, PFD_PIPE_ROUTE, 253 &mrtconf) == -1) 254 quit = 1; 255 } 256 257 if (nfds > 0 && pfd[PFD_SOCK_ROUTE].revents & POLLIN) { 258 nfds--; 259 if (kr_dispatch_msg() == -1) 260 quit = 1; 261 } 262 263 for (j = PFD_MRT_START; j < i && nfds > 0 ; j++) { 264 if (pfd[j].revents & POLLOUT) { 265 if ((n = mrt_write(mrt[i])) < 0) { 266 log_err("mrt write error"); 267 } 268 } 269 } 270 271 if (reconfig) { 272 logit(LOG_CRIT, "rereading config"); 273 reconfigure(conffile, &conf, &mrtconf, peer_l); 274 reconfig = 0; 275 } 276 277 if (sigchld) { 278 if (check_child(io_pid, "session engine")) 279 quit = 1; 280 if (check_child(rde_pid, "route decision engine")) 281 quit = 1; 282 sigchld = 0; 283 } 284 285 if (mrtdump == 1) { 286 mrt_handler(&mrtconf); 287 mrtdump = 0; 288 } 289 } 290 291 signal(SIGCHLD, SIG_IGN); 292 293 if (io_pid) 294 kill(io_pid, SIGTERM); 295 296 if (rde_pid) 297 kill(rde_pid, SIGTERM); 298 299 do { 300 pid = waitpid(-1, NULL, WNOHANG); 301 } while (pid > 0 || (pid == -1 && errno == EINTR)); 302 303 control_cleanup(); 304 kr_shutdown(); 305 306 logit(LOG_CRIT, "Terminating"); 307 return (0); 308} 309 310int 311check_child(pid_t pid, const char *pname) 312{ 313 int status; 314 315 if (waitpid(pid, &status, WNOHANG) > 0) { 316 if (WIFEXITED(status)) { 317 logit(LOG_CRIT, "Lost child: %s exited", pname); 318 return (1); 319 } 320 if (WIFSIGNALED(status)) { 321 logit(LOG_CRIT, "Lost child: %s terminated; signal %d", 322 pname, WTERMSIG(status)); 323 return (1); 324 } 325 } 326 327 return (0); 328} 329 330int 331reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrtc, 332 struct peer *peer_l) 333{ 334 struct peer *p, *next; 335 336 if (parse_config(conffile, conf, mrtc, &peer_l)) { 337 logit(LOG_CRIT, "config file %s has errors, not reloading", 338 conffile); 339 return (-1); 340 } 341 342 if (imsg_compose(&ibuf_se, IMSG_RECONF_CONF, 0, 343 conf, sizeof(struct bgpd_config)) == -1) 344 return (-1); 345 if (imsg_compose(&ibuf_rde, IMSG_RECONF_CONF, 0, 346 conf, sizeof(struct bgpd_config)) == -1) 347 return (-1); 348 for (p = peer_l; p != NULL; p = next) { 349 next = p->next; 350 if (imsg_compose(&ibuf_se, IMSG_RECONF_PEER, p->conf.id, 351 &p->conf, sizeof(struct peer_config)) == -1) 352 return (-1); 353 if (imsg_compose(&ibuf_rde, IMSG_RECONF_PEER, p->conf.id, 354 &p->conf, sizeof(struct peer_config)) == -1) 355 return (-1); 356 free(p); 357 } 358 if (imsg_compose(&ibuf_se, IMSG_RECONF_DONE, 0, NULL, 0) == -1 || 359 imsg_compose(&ibuf_rde, IMSG_RECONF_DONE, 0, NULL, 0) == -1) 360 return (-1); 361 362 return (0); 363} 364 365int 366dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_head *mrtc) 367{ 368 struct imsg imsg; 369 int n; 370 in_addr_t ina; 371 372 if ((n = imsg_read(ibuf)) == -1) 373 return (-1); 374 375 if (n == 0) { /* connection closed */ 376 logit(LOG_CRIT, "dispatch_imsg in main: pipe closed"); 377 return (-1); 378 } 379 380 for (;;) { 381 if ((n = imsg_get(ibuf, &imsg)) == -1) 382 return (-1); 383 384 if (n == 0) 385 break; 386 387 switch (imsg.hdr.type) { 388 case IMSG_MRT_MSG: 389 case IMSG_MRT_END: 390 if (mrt_queue(mrtc, &imsg) == -1) 391 logit(LOG_CRIT, "mrt_queue failed."); 392 break; 393 case IMSG_KROUTE_CHANGE: 394 if (idx != PFD_PIPE_ROUTE) 395 logit(LOG_CRIT, "route request not from RDE"); 396 else if (kr_change(imsg.data)) 397 return (-1); 398 break; 399 case IMSG_KROUTE_DELETE: 400 if (idx != PFD_PIPE_ROUTE) 401 logit(LOG_CRIT, "route request not from RDE"); 402 else if (kr_delete(imsg.data)) 403 return (-1); 404 break; 405 case IMSG_NEXTHOP_ADD: 406 if (idx != PFD_PIPE_ROUTE) 407 logit(LOG_CRIT, "nexthop request not from RDE"); 408 else { 409 memcpy(&ina, imsg.data, sizeof(ina)); 410 if (kr_nexthop_add(ina) == -1) 411 return (-1); 412 } 413 break; 414 case IMSG_NEXTHOP_REMOVE: 415 if (idx != PFD_PIPE_ROUTE) 416 logit(LOG_CRIT, "nexthop request not from RDE"); 417 else { 418 memcpy(&ina, imsg.data, sizeof(ina)); 419 kr_nexthop_delete(ina); 420 } 421 break; 422 case IMSG_CTL_RELOAD: 423 if (idx != PFD_PIPE_SESSION) 424 logit(LOG_CRIT, "reload request not from SE"); 425 else 426 reconfig = 1; 427 break; 428 case IMSG_CTL_FIB_COUPLE: 429 if (idx != PFD_PIPE_SESSION) 430 logit(LOG_CRIT, "couple request not from SE"); 431 else 432 kr_fib_couple(); 433 break; 434 case IMSG_CTL_FIB_DECOUPLE: 435 if (idx != PFD_PIPE_SESSION) 436 logit(LOG_CRIT, "decouple request not from SE"); 437 else 438 kr_fib_decouple(); 439 break; 440 case IMSG_CTL_KROUTE: 441 case IMSG_CTL_KROUTE_ADDR: 442 if (idx != PFD_PIPE_SESSION) 443 logit(LOG_CRIT, "kroute request not from SE"); 444 else 445 kr_show_route(&imsg); 446 break; 447 default: 448 break; 449 } 450 imsg_free(&imsg); 451 } 452 return (0); 453} 454 455void 456send_nexthop_update(struct kroute_nexthop *msg) 457{ 458 char *gw = NULL; 459 460 if (msg->gateway) 461 if (asprintf(&gw, ": via %s", log_ntoa(msg->gateway)) == -1) { 462 log_err("send_nexthop_update"); 463 quit = 1; 464 } 465 466 logit(LOG_INFO, "nexthop %s now %s%s%s", log_ntoa(msg->nexthop), 467 msg->valid ? "valid" : "invalid", 468 msg->connected ? ": directly connected" : "", 469 msg->gateway ? gw : ""); 470 471 free(gw); 472 473 if (imsg_compose(&ibuf_rde, IMSG_NEXTHOP_UPDATE, 0, 474 msg, sizeof(struct kroute_nexthop)) == -1) 475 quit = 1; 476} 477 478void 479send_imsg_session(int type, pid_t pid, void *data, u_int16_t datalen) 480{ 481 imsg_compose_pid(&ibuf_se, type, pid, data, datalen); 482} 483 484 485