bgpd.c revision 1.51
1/* $OpenBSD: bgpd.c,v 1.51 2004/01/03 20:22:07 henning 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 *, 41 struct peer *); 42int dispatch_imsg(struct imsgbuf *, int, struct mrt_config *); 43 44int mrtfd = -1; 45int rfd = -1; 46volatile sig_atomic_t mrtdump = 0; 47volatile sig_atomic_t quit = 0; 48volatile sig_atomic_t reconfig = 0; 49struct imsgbuf ibuf_se; 50struct imsgbuf ibuf_rde; 51 52void 53sighdlr(int sig) 54{ 55 switch (sig) { 56 case SIGTERM: 57 case SIGINT: 58 case SIGCHLD: 59 quit = 1; 60 break; 61 case SIGHUP: 62 reconfig = 1; 63 break; 64 case SIGALRM: 65 mrtdump = 1; 66 break; 67 case SIGUSR1: 68 mrtdump = 2; 69 break; 70 } 71} 72 73void 74usage(void) 75{ 76 extern char *__progname; 77 78 fprintf(stderr, "usage: %s [-dnv] ", __progname); 79 fprintf(stderr, "[-D macro=value] [-f file]\n"); 80 exit(1); 81} 82 83#define POLL_MAX 8 84#define PFD_PIPE_SESSION 0 85#define PFD_PIPE_ROUTE 1 86#define PFD_SOCK_ROUTE 2 87#define PFD_MRT_START 3 88 89int 90main(int argc, char *argv[]) 91{ 92 struct bgpd_config conf; 93 struct peer *peers, *p, *next; 94 struct mrt_config mrtconf; 95 struct mrtdump_config *mconf, *(mrt[POLL_MAX]); 96 struct pollfd pfd[POLL_MAX]; 97 pid_t io_pid = 0, rde_pid = 0; 98 char *conffile; 99 int debug = 0; 100 int ch, i, j, n, nfds, csock; 101 int pipe_m2s[2]; 102 int pipe_m2r[2]; 103 int pipe_s2r[2]; 104 105 conffile = CONFFILE; 106 bgpd_process = PROC_MAIN; 107 108 log_init(1); /* log to stderr until daemonized */ 109 110 bzero(&conf, sizeof(conf)); 111 bzero(&mrtconf, sizeof(mrtconf)); 112 LIST_INIT(&mrtconf); 113 peers = NULL; 114 115 while ((ch = getopt(argc, argv, "dD:f:nv")) != -1) { 116 switch (ch) { 117 case 'd': 118 debug = 1; 119 break; 120 case 'D': 121 if (cmdline_symset(optarg) < 0) 122 logit(LOG_CRIT, 123 "could not parse macro definition %s", 124 optarg); 125 break; 126 case 'f': 127 conffile = optarg; 128 break; 129 case 'n': 130 conf.opts |= BGPD_OPT_NOACTION; 131 break; 132 case 'v': 133 if (conf.opts & BGPD_OPT_VERBOSE) 134 conf.opts |= BGPD_OPT_VERBOSE2; 135 conf.opts |= BGPD_OPT_VERBOSE; 136 break; 137 default: 138 usage(); 139 /* NOTREACHED */ 140 } 141 } 142 143 if (parse_config(conffile, &conf, &mrtconf, &peers)) 144 exit(1); 145 146 if (conf.opts & BGPD_OPT_NOACTION) { 147 fprintf(stderr, "configuration OK\n"); 148 exit(0); 149 } 150 151 if (geteuid()) 152 errx(1, "need root privileges"); 153 154 log_init(debug); 155 156 if (!debug) 157 daemon(1, 0); 158 159 logit(LOG_INFO, "startup"); 160 161 if (pipe(pipe_m2s) == -1) 162 fatal("pipe"); 163 if (fcntl(pipe_m2s[0], F_SETFL, O_NONBLOCK) == -1 || 164 fcntl(pipe_m2s[1], F_SETFL, O_NONBLOCK) == -1) 165 fatal("fcntl"); 166 if (pipe(pipe_m2r) == -1) 167 fatal("pipe"); 168 if (fcntl(pipe_m2r[0], F_SETFL, O_NONBLOCK) == -1 || 169 fcntl(pipe_m2r[1], F_SETFL, O_NONBLOCK) == -1) 170 fatal("fcntl"); 171 if (pipe(pipe_s2r) == -1) 172 fatal("pipe"); 173 if (fcntl(pipe_s2r[0], F_SETFL, O_NONBLOCK) == -1 || 174 fcntl(pipe_s2r[1], F_SETFL, O_NONBLOCK) == -1) 175 fatal("fcntl"); 176 177 if ((csock = control_init()) == -1) 178 fatalx("control socket setup failed"); 179 180 /* fork children */ 181 rde_pid = rde_main(&conf, peers, pipe_m2r, pipe_s2r); 182 io_pid = session_main(&conf, peers, pipe_m2s, pipe_s2r); 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 close(csock); 198 199 imsg_init(&ibuf_se, pipe_m2s[0]); 200 imsg_init(&ibuf_rde, pipe_m2r[0]); 201 if ((rfd = kroute_init(!(conf.flags & BGPD_FLAG_NO_FIB_UPDATE))) == -1) 202 quit = 1; 203 204 for (p = peers; p != NULL; p = next) { 205 next = p->next; 206 free(p); 207 } 208 209 while (quit == 0) { 210 pfd[PFD_PIPE_SESSION].fd = ibuf_se.sock; 211 pfd[PFD_PIPE_SESSION].events = POLLIN; 212 if (ibuf_se.w.queued) 213 pfd[PFD_PIPE_SESSION].events |= POLLOUT; 214 pfd[PFD_PIPE_ROUTE].fd = ibuf_rde.sock; 215 pfd[PFD_PIPE_ROUTE].events = POLLIN; 216 if (ibuf_rde.w.queued) 217 pfd[PFD_PIPE_ROUTE].events |= POLLOUT; 218 pfd[PFD_SOCK_ROUTE].fd = rfd; 219 pfd[PFD_SOCK_ROUTE].events = POLLIN; 220 i = PFD_MRT_START; 221 LIST_FOREACH(mconf, &mrtconf, list) 222 if (mconf->msgbuf.queued > 0) { 223 pfd[i].fd = mconf->msgbuf.sock; 224 pfd[i].events |= POLLOUT; 225 mrt[i++] = mconf; 226 } 227 228 if ((nfds = poll(pfd, i, INFTIM)) == -1) 229 if (errno != EINTR) { 230 log_err("poll error"); 231 quit = 1; 232 } 233 234 if (nfds > 0 && (pfd[PFD_PIPE_SESSION].revents & POLLOUT)) 235 if ((n = msgbuf_write(&ibuf_se.w)) < 0) { 236 log_err("pipe write error (to SE)"); 237 quit = 1; 238 } 239 240 if (nfds > 0 && (pfd[PFD_PIPE_ROUTE].revents & POLLOUT)) 241 if ((n = msgbuf_write(&ibuf_rde.w)) < 0) { 242 log_err("pipe write error (to RDE)"); 243 quit = 1; 244 } 245 246 if (nfds > 0 && pfd[PFD_PIPE_SESSION].revents & POLLIN) { 247 nfds--; 248 if (dispatch_imsg(&ibuf_se, PFD_PIPE_SESSION, 249 &mrtconf) == -1) 250 quit = 1; 251 } 252 253 if (nfds > 0 && pfd[PFD_PIPE_ROUTE].revents & POLLIN) { 254 nfds--; 255 if (dispatch_imsg(&ibuf_rde, PFD_PIPE_ROUTE, 256 &mrtconf) == -1) 257 quit = 1; 258 } 259 260 if (nfds > 0 && pfd[PFD_SOCK_ROUTE].revents & POLLIN) { 261 nfds--; 262 if (kroute_dispatch_msg() == -1) 263 quit = 1; 264 } 265 266 for (j = PFD_MRT_START; j < i && nfds > 0 ; j++) { 267 if (pfd[j].revents & POLLOUT) { 268 if ((n = msgbuf_write(&mrt[i]->msgbuf)) < 0) { 269 log_err("pipe write error (MRT)"); 270 quit = 1; 271 } 272 } 273 } 274 275 if (reconfig) { 276 logit(LOG_CRIT, "rereading config"); 277 reconfigure(conffile, &conf, &mrtconf, peers); 278 LIST_FOREACH(mconf, &mrtconf, list) 279 mrt_state(mconf, IMSG_NONE, &ibuf_rde); 280 reconfig = 0; 281 } 282 283 if (mrtdump == 1) { 284 mrt_alrm(&mrtconf, &ibuf_rde); 285 mrtdump = 0; 286 } else if (mrtdump == 2) { 287 mrt_usr1(&mrtconf, &ibuf_rde); 288 mrtdump = 0; 289 } 290 } 291 292 signal(SIGCHLD, SIG_IGN); 293 294 if (io_pid) 295 kill(io_pid, SIGTERM); 296 297 if (rde_pid) 298 kill(rde_pid, SIGTERM); 299 300 do { 301 i = waitpid(-1, NULL, WNOHANG); 302 } while (i > 0 || (i == -1 && errno == EINTR)); 303 304 control_cleanup(); 305 kroute_shutdown(); 306 307 logit(LOG_CRIT, "Terminating"); 308 return (0); 309} 310 311int 312reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_config *mrtc, 313 struct peer *peers) 314{ 315 struct peer *p, *next; 316 317 if (parse_config(conffile, conf, mrtc, &peers)) { 318 logit(LOG_CRIT, "config file %s has errors, not reloading", 319 conffile); 320 return (-1); 321 } 322 323 if (imsg_compose(&ibuf_se, IMSG_RECONF_CONF, 0, 324 conf, sizeof(struct bgpd_config)) == -1) 325 return (-1); 326 if (imsg_compose(&ibuf_rde, IMSG_RECONF_CONF, 0, 327 conf, sizeof(struct bgpd_config)) == -1) 328 return (-1); 329 for (p = peers; p != NULL; p = next) { 330 next = p->next; 331 if (imsg_compose(&ibuf_se, IMSG_RECONF_PEER, p->conf.id, 332 &p->conf, sizeof(struct peer_config)) == -1) 333 return (-1); 334 if (imsg_compose(&ibuf_rde, IMSG_RECONF_PEER, p->conf.id, 335 &p->conf, sizeof(struct peer_config)) == -1) 336 return (-1); 337 free(p); 338 } 339 if (imsg_compose(&ibuf_se, IMSG_RECONF_DONE, 0, NULL, 0) == -1 || 340 imsg_compose(&ibuf_rde, IMSG_RECONF_DONE, 0, NULL, 0) == -1) 341 return (-1); 342 343 return (0); 344} 345 346/* 347 * XXX currently messages are only buffered for mrt files. 348 */ 349int 350dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_config *conf) 351{ 352 struct imsg imsg; 353 struct buf *wbuf; 354 struct mrtdump_config *m; 355 ssize_t len; 356 int n; 357 in_addr_t ina; 358 359 if ((n = imsg_read(ibuf)) == -1) 360 return (-1); 361 362 if (n == 0) { /* connection closed */ 363 logit(LOG_CRIT, "dispatch_imsg in main: pipe closed"); 364 return (-1); 365 } 366 367 for (;;) { 368 if ((n = imsg_get(ibuf, &imsg)) == -1) 369 return (-1); 370 371 if (n == 0) 372 break; 373 374 switch (imsg.hdr.type) { 375 case IMSG_MRT_MSG: 376 case IMSG_MRT_END: 377 LIST_FOREACH(m, conf, list) { 378 if (m->id != imsg.hdr.peerid) 379 continue; 380 if (mrt_state(m, imsg.hdr.type, ibuf) == 0) 381 break; 382 if (m->msgbuf.sock == -1) 383 break; 384 len = imsg.hdr.len - IMSG_HEADER_SIZE; 385 wbuf = buf_open(len); 386 if (wbuf == NULL) 387 return (-1); 388 if (buf_add(wbuf, imsg.data, len) == -1) { 389 buf_free(wbuf); 390 return (-1); 391 } 392 if ((n = buf_close(&m->msgbuf, wbuf)) < 0) { 393 buf_free(wbuf); 394 return (-1); 395 } 396 break; 397 } 398 break; 399 case IMSG_KROUTE_CHANGE: 400 if (idx != PFD_PIPE_ROUTE) 401 logit(LOG_CRIT, "route request not from RDE"); 402 else if (kroute_change(imsg.data)) 403 return (-1); 404 break; 405 case IMSG_KROUTE_DELETE: 406 if (idx != PFD_PIPE_ROUTE) 407 logit(LOG_CRIT, "route request not from RDE"); 408 else if (kroute_delete(imsg.data)) 409 return (-1); 410 break; 411 case IMSG_NEXTHOP_ADD: 412 if (idx != PFD_PIPE_ROUTE) 413 logit(LOG_CRIT, "nexthop request not from RDE"); 414 else { 415 memcpy(&ina, imsg.data, sizeof(ina)); 416 if (kroute_nexthop_add(ina) == -1) 417 return (-1); 418 } 419 break; 420 case IMSG_NEXTHOP_REMOVE: 421 if (idx != PFD_PIPE_ROUTE) 422 logit(LOG_CRIT, "nexthop request not from RDE"); 423 else { 424 memcpy(&ina, imsg.data, sizeof(ina)); 425 kroute_nexthop_delete(ina); 426 } 427 break; 428 default: 429 break; 430 } 431 imsg_free(&imsg); 432 } 433 return (0); 434} 435 436void 437send_nexthop_update(struct kroute_nexthop *msg) 438{ 439 char *gw = NULL; 440 441 if (msg->gateway) 442 if (asprintf(&gw, ": via %s", log_ntoa(msg->gateway)) == -1) { 443 log_err("send_nexthop_update"); 444 quit = 1; 445 } 446 447 logit(LOG_INFO, "nexthop %s now %s%s%s", log_ntoa(msg->nexthop), 448 msg->valid ? "valid" : "invalid", 449 msg->connected ? ": directly connected" : "", 450 msg->gateway ? gw : ""); 451 452 free(gw); 453 454 if (imsg_compose(&ibuf_rde, IMSG_NEXTHOP_UPDATE, 0, 455 msg, sizeof(struct kroute_nexthop)) == -1) 456 quit = 1; 457} 458