bgpd.c revision 1.68
1/* $OpenBSD: bgpd.c,v 1.68 2004/01/17 19:35:35 claudio 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 mrt_l; 97 struct network_head net_l; 98 struct network *net; 99 struct mrt *(mrt[POLL_MAX]); 100 struct pollfd pfd[POLL_MAX]; 101 pid_t io_pid = 0, rde_pid = 0, pid; 102 char *conffile; 103 int debug = 0; 104 int ch, csock, i, j, n, nfds, timeout; 105 int pipe_m2s[2]; 106 int pipe_m2r[2]; 107 int pipe_s2r[2]; 108 109 conffile = CONFFILE; 110 bgpd_process = PROC_MAIN; 111 112 log_init(1); /* log to stderr until daemonized */ 113 114 bzero(&conf, sizeof(conf)); 115 LIST_INIT(&mrt_l); 116 TAILQ_INIT(&net_l); 117 peer_l = NULL; 118 119 while ((ch = getopt(argc, argv, "dD:f:nv")) != -1) { 120 switch (ch) { 121 case 'd': 122 debug = 1; 123 break; 124 case 'D': 125 if (cmdline_symset(optarg) < 0) 126 logit(LOG_CRIT, 127 "could not parse macro definition %s", 128 optarg); 129 break; 130 case 'f': 131 conffile = optarg; 132 break; 133 case 'n': 134 conf.opts |= BGPD_OPT_NOACTION; 135 break; 136 case 'v': 137 if (conf.opts & BGPD_OPT_VERBOSE) 138 conf.opts |= BGPD_OPT_VERBOSE2; 139 conf.opts |= BGPD_OPT_VERBOSE; 140 break; 141 default: 142 usage(); 143 /* NOTREACHED */ 144 } 145 } 146 147 if (parse_config(conffile, &conf, &mrt_l, &peer_l, &net_l)) 148 exit(1); 149 150 if (conf.opts & BGPD_OPT_NOACTION) { 151 fprintf(stderr, "configuration OK\n"); 152 exit(0); 153 } 154 155 if (geteuid()) 156 errx(1, "need root privileges"); 157 158 log_init(debug); 159 160 if (!debug) 161 daemon(1, 0); 162 163 logit(LOG_INFO, "startup"); 164 165 if (pipe(pipe_m2s) == -1) 166 fatal("pipe"); 167 if (fcntl(pipe_m2s[0], F_SETFL, O_NONBLOCK) == -1 || 168 fcntl(pipe_m2s[1], F_SETFL, O_NONBLOCK) == -1) 169 fatal("fcntl"); 170 if (pipe(pipe_m2r) == -1) 171 fatal("pipe"); 172 if (fcntl(pipe_m2r[0], F_SETFL, O_NONBLOCK) == -1 || 173 fcntl(pipe_m2r[1], F_SETFL, O_NONBLOCK) == -1) 174 fatal("fcntl"); 175 if (pipe(pipe_s2r) == -1) 176 fatal("pipe"); 177 if (fcntl(pipe_s2r[0], F_SETFL, O_NONBLOCK) == -1 || 178 fcntl(pipe_s2r[1], F_SETFL, O_NONBLOCK) == -1) 179 fatal("fcntl"); 180 181 if ((csock = control_init()) == -1) 182 fatalx("control socket setup failed"); 183 184 /* fork children */ 185 rde_pid = rde_main(&conf, peer_l, &net_l, pipe_m2r, pipe_s2r); 186 io_pid = session_main(&conf, peer_l, pipe_m2s, pipe_s2r); 187 188 setproctitle("parent"); 189 190 signal(SIGTERM, sighdlr); 191 signal(SIGINT, sighdlr); 192 signal(SIGCHLD, sighdlr); 193 signal(SIGHUP, sighdlr); 194 signal(SIGALRM, sighdlr); 195 signal(SIGUSR1, sighdlr); 196 197 close(pipe_m2s[1]); 198 close(pipe_m2r[1]); 199 close(pipe_s2r[0]); 200 close(pipe_s2r[1]); 201 close(csock); 202 203 imsg_init(&ibuf_se, pipe_m2s[0]); 204 imsg_init(&ibuf_rde, pipe_m2r[0]); 205 mrt_init(&ibuf_rde, &ibuf_se); 206 if ((rfd = kr_init(!(conf.flags & BGPD_FLAG_NO_FIB_UPDATE))) == -1) 207 quit = 1; 208 209 for (p = peer_l; p != NULL; p = next) { 210 next = p->next; 211 free(p); 212 } 213 for (net = TAILQ_FIRST(&net_l); net != TAILQ_END(&net_l); 214 net = TAILQ_FIRST(&net_l)) { 215 TAILQ_REMOVE(&net_l, net, network_l); 216 free(net); 217 } 218 219 while (quit == 0) { 220 pfd[PFD_PIPE_SESSION].fd = ibuf_se.sock; 221 pfd[PFD_PIPE_SESSION].events = POLLIN; 222 if (ibuf_se.w.queued) 223 pfd[PFD_PIPE_SESSION].events |= POLLOUT; 224 pfd[PFD_PIPE_ROUTE].fd = ibuf_rde.sock; 225 pfd[PFD_PIPE_ROUTE].events = POLLIN; 226 if (ibuf_rde.w.queued) 227 pfd[PFD_PIPE_ROUTE].events |= POLLOUT; 228 pfd[PFD_SOCK_ROUTE].fd = rfd; 229 pfd[PFD_SOCK_ROUTE].events = POLLIN; 230 i = PFD_MRT_START; 231 i = mrt_select(&mrt_l, pfd, mrt, i, POLL_MAX, &timeout); 232 233 if ((nfds = poll(pfd, i, INFTIM)) == -1) 234 if (errno != EINTR) { 235 log_err("poll error"); 236 quit = 1; 237 } 238 239 if (nfds > 0 && (pfd[PFD_PIPE_SESSION].revents & POLLOUT)) 240 if ((n = msgbuf_write(&ibuf_se.w)) < 0) { 241 log_err("pipe write error (to SE)"); 242 quit = 1; 243 } 244 245 if (nfds > 0 && (pfd[PFD_PIPE_ROUTE].revents & POLLOUT)) 246 if ((n = msgbuf_write(&ibuf_rde.w)) < 0) { 247 log_err("pipe write error (to RDE)"); 248 quit = 1; 249 } 250 251 if (nfds > 0 && pfd[PFD_PIPE_SESSION].revents & POLLIN) { 252 nfds--; 253 if (dispatch_imsg(&ibuf_se, PFD_PIPE_SESSION, 254 &mrt_l) == -1) 255 quit = 1; 256 } 257 258 if (nfds > 0 && pfd[PFD_PIPE_ROUTE].revents & POLLIN) { 259 nfds--; 260 if (dispatch_imsg(&ibuf_rde, PFD_PIPE_ROUTE, 261 &mrt_l) == -1) 262 quit = 1; 263 } 264 265 if (nfds > 0 && pfd[PFD_SOCK_ROUTE].revents & POLLIN) { 266 nfds--; 267 if (kr_dispatch_msg() == -1) 268 quit = 1; 269 } 270 271 for (j = PFD_MRT_START; j < i && nfds > 0 ; j++) { 272 if (pfd[j].revents & POLLOUT) { 273 if ((n = mrt_write(mrt[j])) < 0) { 274 log_err("mrt write error"); 275 } 276 } 277 } 278 279 if (reconfig) { 280 logit(LOG_CRIT, "rereading config"); 281 reconfigure(conffile, &conf, &mrt_l, peer_l); 282 reconfig = 0; 283 } 284 285 if (sigchld) { 286 if (check_child(io_pid, "session engine")) 287 quit = 1; 288 if (check_child(rde_pid, "route decision engine")) 289 quit = 1; 290 sigchld = 0; 291 } 292 293 if (mrtdump == 1) { 294 mrt_handler(&mrt_l); 295 mrtdump = 0; 296 } 297 } 298 299 signal(SIGCHLD, SIG_IGN); 300 301 if (io_pid) 302 kill(io_pid, SIGTERM); 303 304 if (rde_pid) 305 kill(rde_pid, SIGTERM); 306 307 do { 308 pid = waitpid(-1, NULL, WNOHANG); 309 } while (pid > 0 || (pid == -1 && errno == EINTR)); 310 311 control_cleanup(); 312 kr_shutdown(); 313 314 logit(LOG_CRIT, "Terminating"); 315 return (0); 316} 317 318int 319check_child(pid_t pid, const char *pname) 320{ 321 int status; 322 323 if (waitpid(pid, &status, WNOHANG) > 0) { 324 if (WIFEXITED(status)) { 325 logit(LOG_CRIT, "Lost child: %s exited", pname); 326 return (1); 327 } 328 if (WIFSIGNALED(status)) { 329 logit(LOG_CRIT, "Lost child: %s terminated; signal %d", 330 pname, WTERMSIG(status)); 331 return (1); 332 } 333 } 334 335 return (0); 336} 337 338int 339reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l, 340 struct peer *peer_l) 341{ 342 struct network_head net_l; 343 struct network *n; 344 struct peer *p, *next; 345 346 if (parse_config(conffile, conf, mrt_l, &peer_l, &net_l)) { 347 logit(LOG_CRIT, "config file %s has errors, not reloading", 348 conffile); 349 return (-1); 350 } 351 352 if (imsg_compose(&ibuf_se, IMSG_RECONF_CONF, 0, 353 conf, sizeof(struct bgpd_config)) == -1) 354 return (-1); 355 if (imsg_compose(&ibuf_rde, IMSG_RECONF_CONF, 0, 356 conf, sizeof(struct bgpd_config)) == -1) 357 return (-1); 358 for (p = peer_l; p != NULL; p = next) { 359 next = p->next; 360 if (imsg_compose(&ibuf_se, IMSG_RECONF_PEER, p->conf.id, 361 &p->conf, sizeof(struct peer_config)) == -1) 362 return (-1); 363 if (imsg_compose(&ibuf_rde, IMSG_RECONF_PEER, p->conf.id, 364 &p->conf, sizeof(struct peer_config)) == -1) 365 return (-1); 366 free(p); 367 } 368 for (n = TAILQ_FIRST(&net_l); n != TAILQ_END(&net_l); 369 n = TAILQ_FIRST(&net_l)) { 370 if (imsg_compose(&ibuf_rde, IMSG_RECONF_NETWORK, 0, 371 &n->net, sizeof(struct network_config)) == -1) 372 return (-1); 373 TAILQ_REMOVE(&net_l, n, network_l); 374 free(n); 375 } 376 if (imsg_compose(&ibuf_se, IMSG_RECONF_DONE, 0, NULL, 0) == -1 || 377 imsg_compose(&ibuf_rde, IMSG_RECONF_DONE, 0, NULL, 0) == -1) 378 return (-1); 379 380 return (0); 381} 382 383int 384dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_head *mrt_l) 385{ 386 struct imsg imsg; 387 int n; 388 389 if ((n = imsg_read(ibuf)) == -1) 390 return (-1); 391 392 if (n == 0) { /* connection closed */ 393 logit(LOG_CRIT, "dispatch_imsg in main: pipe closed"); 394 return (-1); 395 } 396 397 for (;;) { 398 if ((n = imsg_get(ibuf, &imsg)) == -1) 399 return (-1); 400 401 if (n == 0) 402 break; 403 404 switch (imsg.hdr.type) { 405 case IMSG_MRT_MSG: 406 case IMSG_MRT_END: 407 if (mrt_queue(mrt_l, &imsg) == -1) 408 logit(LOG_CRIT, "mrt_queue failed."); 409 break; 410 case IMSG_KROUTE_CHANGE: 411 if (idx != PFD_PIPE_ROUTE) 412 logit(LOG_CRIT, "route request not from RDE"); 413 else if (kr_change(imsg.data)) 414 return (-1); 415 break; 416 case IMSG_KROUTE_DELETE: 417 if (idx != PFD_PIPE_ROUTE) 418 logit(LOG_CRIT, "route request not from RDE"); 419 else if (kr_delete(imsg.data)) 420 return (-1); 421 break; 422 case IMSG_NEXTHOP_ADD: 423 if (idx != PFD_PIPE_ROUTE) 424 logit(LOG_CRIT, "nexthop request not from RDE"); 425 else 426 if (imsg.hdr.len != IMSG_HEADER_SIZE + 427 sizeof(struct bgpd_addr)) 428 logit(LOG_CRIT, "wrong imsg len"); 429 else if (kr_nexthop_add(imsg.data) == -1) 430 return (-1); 431 break; 432 case IMSG_NEXTHOP_REMOVE: 433 if (idx != PFD_PIPE_ROUTE) 434 logit(LOG_CRIT, "nexthop request not from RDE"); 435 else 436 if (imsg.hdr.len != IMSG_HEADER_SIZE + 437 sizeof(struct bgpd_addr)) 438 logit(LOG_CRIT, "wrong imsg len"); 439 else kr_nexthop_delete(imsg.data); 440 break; 441 case IMSG_CTL_RELOAD: 442 if (idx != PFD_PIPE_SESSION) 443 logit(LOG_CRIT, "reload request not from SE"); 444 else 445 reconfig = 1; 446 break; 447 case IMSG_CTL_FIB_COUPLE: 448 if (idx != PFD_PIPE_SESSION) 449 logit(LOG_CRIT, "couple request not from SE"); 450 else 451 kr_fib_couple(); 452 break; 453 case IMSG_CTL_FIB_DECOUPLE: 454 if (idx != PFD_PIPE_SESSION) 455 logit(LOG_CRIT, "decouple request not from SE"); 456 else 457 kr_fib_decouple(); 458 break; 459 case IMSG_CTL_KROUTE: 460 case IMSG_CTL_KROUTE_ADDR: 461 case IMSG_CTL_SHOW_NEXTHOP: 462 case IMSG_CTL_SHOW_INTERFACE: 463 if (idx != PFD_PIPE_SESSION) 464 logit(LOG_CRIT, "kroute request not from SE"); 465 else 466 kr_show_route(&imsg); 467 break; 468 default: 469 break; 470 } 471 imsg_free(&imsg); 472 } 473 return (0); 474} 475 476void 477send_nexthop_update(struct kroute_nexthop *msg) 478{ 479 char *gw = NULL, *nh = NULL; 480 481 if (msg->gateway.af == AF_INET) 482 if (asprintf(&gw, ": via %s", 483 log_ntoa(msg->gateway.v4.s_addr)) == -1) { 484 log_err("send_nexthop_update"); 485 quit = 1; 486 } 487 488 if (msg->nexthop.af == AF_INET) 489 nh = log_ntoa(msg->nexthop.v4.s_addr); 490 491 logit(LOG_INFO, "nexthop %s now %s%s%s", nh, 492 msg->valid ? "valid" : "invalid", 493 msg->connected ? ": directly connected" : "", 494 msg->gateway.af ? gw : ""); 495 496 free(gw); 497 498 if (imsg_compose(&ibuf_rde, IMSG_NEXTHOP_UPDATE, 0, 499 msg, sizeof(struct kroute_nexthop)) == -1) 500 quit = 1; 501} 502 503void 504send_imsg_session(int type, pid_t pid, void *data, u_int16_t datalen) 505{ 506 imsg_compose_pid(&ibuf_se, type, pid, data, datalen); 507} 508 509 510