bgpd.c revision 1.27
1/* $OpenBSD: bgpd.c,v 1.27 2003/12/25 02:09:19 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_MRT_START 2 86 87int 88main(int argc, char *argv[]) 89{ 90 struct bgpd_config conf; 91 struct mrt_config mrtconf; 92 struct mrtdump_config *mconf, *(mrt[POLL_MAX]); 93 struct pollfd pfd[POLL_MAX]; 94 pid_t io_pid = 0, rde_pid = 0; 95 char *conffile; 96 int debug = 0; 97 int ch, i, j, n, nfds; 98 int pipe_m2s[2]; 99 int pipe_m2r[2]; 100 int pipe_s2r[2]; 101 102 conffile = CONFFILE; 103 bgpd_process = PROC_MAIN; 104 105 log_init(1); /* log to stderr until daemonized */ 106 107 bzero(&conf, sizeof(conf)); 108 bzero(&mrtconf, sizeof(mrtconf)); 109 LIST_INIT(&mrtconf); 110 111 while ((ch = getopt(argc, argv, "dD:f:nv")) != -1) { 112 switch (ch) { 113 case 'd': 114 debug = 1; 115 break; 116 case 'D': 117 if (cmdline_symset(optarg) < 0) 118 logit(LOG_CRIT, 119 "could not parse macro definition %s", 120 optarg); 121 break; 122 case 'f': 123 conffile = optarg; 124 break; 125 case 'n': 126 conf.opts |= BGPD_OPT_NOACTION; 127 break; 128 case 'v': 129 if (conf.opts & BGPD_OPT_VERBOSE) 130 conf.opts |= BGPD_OPT_VERBOSE2; 131 conf.opts |= BGPD_OPT_VERBOSE; 132 break; 133 default: 134 usage(); 135 /* NOTREACHED */ 136 } 137 } 138 139 if (parse_config(conffile, &conf, &mrtconf)) 140 exit(1); 141 142 if (conf.opts & BGPD_OPT_NOACTION) { 143 fprintf(stderr, "configuration OK\n"); 144 exit(0); 145 } 146 147 if (geteuid()) 148 errx(1, "need root privileges"); 149 150 log_init(debug); 151 152 if (!debug) 153 daemon(1, 0); 154 155 logit(LOG_INFO, "startup"); 156 157 if (pipe(pipe_m2s) == -1) 158 fatal("pipe", errno); 159 if (fcntl(pipe_m2s[0], F_SETFL, O_NONBLOCK) == -1 || 160 fcntl(pipe_m2s[1], F_SETFL, O_NONBLOCK) == -1) 161 fatal("fcntl", errno); 162 if (pipe(pipe_m2r) == -1) 163 fatal("pipe", errno); 164 if (fcntl(pipe_m2r[0], F_SETFL, O_NONBLOCK) == -1 || 165 fcntl(pipe_m2r[1], F_SETFL, O_NONBLOCK) == -1) 166 fatal("fcntl", errno); 167 if (pipe(pipe_s2r) == -1) 168 fatal("pipe", errno); 169 if (fcntl(pipe_s2r[0], F_SETFL, O_NONBLOCK) == -1 || 170 fcntl(pipe_s2r[1], F_SETFL, O_NONBLOCK) == -1) 171 fatal("fcntl", errno); 172 173 if ((rde_pid = rde_main(&conf, pipe_m2r, pipe_s2r)) < 0) 174 fatal("could not start route decision engine", 0); 175 176 if ((io_pid = session_main(&conf, pipe_m2s, pipe_s2r)) < 0) 177 fatal("could not start session engine", 0); 178 179 setproctitle("parent"); 180 181 signal(SIGTERM, sighdlr); 182 signal(SIGINT, sighdlr); 183 signal(SIGCHLD, sighdlr); 184 signal(SIGHUP, sighdlr); 185 signal(SIGALRM, sighdlr); 186 signal(SIGUSR1, sighdlr); 187 188 close(pipe_m2s[1]); 189 close(pipe_m2r[1]); 190 close(pipe_s2r[0]); 191 close(pipe_s2r[1]); 192 193 imsg_init(&ibuf_se, pipe_m2s[0]); 194 imsg_init(&ibuf_rde, pipe_m2r[0]); 195 rfd = kroute_init(); 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 i = PFD_MRT_START; 207 LIST_FOREACH(mconf, &mrtconf, list) 208 if (mconf->msgbuf.queued > 0) { 209 pfd[i].fd = mconf->msgbuf.sock; 210 pfd[i].events |= POLLOUT; 211 mrt[i++] = mconf; 212 } 213 214 if ((nfds = poll(pfd, 2, INFTIM)) == -1) 215 if (errno != EINTR) 216 fatal("poll error", errno); 217 218 if (nfds > 0 && (pfd[PFD_PIPE_SESSION].revents & POLLOUT)) 219 if ((n = msgbuf_write(&ibuf_se.w)) < 0) 220 fatal("pipe write error", errno); 221 222 if (nfds > 0 && (pfd[PFD_PIPE_ROUTE].revents & POLLOUT)) 223 if ((n = msgbuf_write(&ibuf_rde.w)) < 0) 224 fatal("pipe write error", errno); 225 226 if (nfds > 0 && pfd[PFD_PIPE_SESSION].revents & POLLIN) { 227 nfds--; 228 dispatch_imsg(&ibuf_se, PFD_PIPE_SESSION, &mrtconf); 229 } 230 231 if (nfds > 0 && pfd[PFD_PIPE_ROUTE].revents & POLLIN) { 232 nfds--; 233 dispatch_imsg(&ibuf_rde, PFD_PIPE_ROUTE, &mrtconf); 234 } 235 236 for (j = PFD_MRT_START; j < i && nfds > 0 ; j++) { 237 if (pfd[j].revents & POLLOUT) { 238 if ((n = msgbuf_write(&mrt[i]->msgbuf)) < 0) 239 fatal("pipe write error", errno); 240 } 241 } 242 243 if (reconfig) { 244 logit(LOG_CRIT, "rereading config"); 245 reconfigure(conffile, &conf, &mrtconf); 246 LIST_FOREACH(mconf, &mrtconf, list) 247 mrt_state(mconf, IMSG_NONE, &ibuf_rde); 248 reconfig = 0; 249 } 250 251 if (mrtdump == 1) { 252 mrt_alrm(&mrtconf, &ibuf_rde); 253 mrtdump = 0; 254 } else if (mrtdump == 2) { 255 mrt_usr1(&mrtconf, &ibuf_rde); 256 mrtdump = 0; 257 } 258 } 259 260 signal(SIGCHLD, SIG_IGN); 261 262 if (io_pid) 263 kill(io_pid, SIGTERM); 264 265 if (rde_pid) 266 kill(rde_pid, SIGTERM); 267 268 do { 269 i = waitpid(-1, NULL, WNOHANG); 270 } while (i > 0 || (i == -1 && errno == EINTR)); 271 272 kroute_shutdown(rfd); 273 274 logit(LOG_CRIT, "Terminating"); 275 return (0); 276} 277 278int 279reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_config *mrtc) 280{ 281 struct peer *p; 282 283 if (parse_config(conffile, conf, mrtc)) { 284 logit(LOG_CRIT, "config file %s has errors, not reloading", 285 conffile); 286 return (-1); 287 } 288 imsg_compose(&ibuf_se, IMSG_RECONF_CONF, 0, 289 conf, sizeof(struct bgpd_config)); 290 imsg_compose(&ibuf_rde, IMSG_RECONF_CONF, 0, 291 conf, sizeof(struct bgpd_config)); 292 for (p = conf->peers; p != NULL; p = p->next) { 293 imsg_compose(&ibuf_se, IMSG_RECONF_PEER, p->conf.id, 294 &p->conf, sizeof(struct peer_config)); 295 imsg_compose(&ibuf_rde, IMSG_RECONF_PEER, p->conf.id, 296 &p->conf, sizeof(struct peer_config)); 297 } 298 imsg_compose(&ibuf_se, IMSG_RECONF_DONE, 0, NULL, 0); 299 imsg_compose(&ibuf_rde, IMSG_RECONF_DONE, 0, NULL, 0); 300 301 return (0); 302} 303 304/* 305 * XXX currently messages are only buffered for mrt files. 306 */ 307int 308dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_config *conf) 309{ 310 struct imsg imsg; 311 struct buf *wbuf; 312 struct mrtdump_config *m; 313 ssize_t len; 314 int n; 315 316 if (imsg_get(ibuf, &imsg) > 0) { 317 switch (imsg.hdr.type) { 318 case IMSG_MRT_MSG: 319 case IMSG_MRT_END: 320 LIST_FOREACH(m, conf, list) { 321 if (m->id != imsg.hdr.peerid) 322 continue; 323 if (mrt_state(m, imsg.hdr.type, ibuf) == 0) 324 break; 325 if (m->msgbuf.sock == -1) 326 break; 327 len = imsg.hdr.len - IMSG_HEADER_SIZE; 328 wbuf = buf_open(len); 329 if (wbuf == NULL) 330 fatal("buf_open error", 0); 331 if (buf_add(wbuf, imsg.data, len) == -1) 332 fatal("buf_add error", 0); 333 if ((n = buf_close(&m->msgbuf, wbuf)) < 0) 334 fatal("buf_close error", 0); 335 break; 336 } 337 break; 338 case IMSG_KROUTE_ADD: 339 if (idx != PFD_PIPE_ROUTE) 340 fatal("route request not from RDE", 0); 341 if (kroute_change(rfd, imsg.data)) 342 fatal("kroute_add error", errno); 343 break; 344 case IMSG_KROUTE_CHANGE: 345 if (idx != PFD_PIPE_ROUTE) 346 fatal("route request not from RDE", 0); 347 if (kroute_change(rfd, imsg.data)) 348 fatal("kroute_change error", errno); 349 case IMSG_KROUTE_DELETE: 350 if (idx != PFD_PIPE_ROUTE) 351 fatal("route request not from RDE", 0); 352 if (kroute_delete(rfd, imsg.data)) 353 fatal("kroute_delete error", errno); 354 break; 355 default: 356 break; 357 } 358 imsg_free(&imsg); 359 } 360 return (0); 361} 362 363