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