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