bgpd.c revision 1.16
1/* $OpenBSD: bgpd.c,v 1.16 2003/12/22 15:07:05 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; 44volatile sig_atomic_t mrtdump = 0; 45volatile sig_atomic_t quit = 0; 46volatile sig_atomic_t reconfig = 0; 47struct imsgbuf ibuf_se; 48struct imsgbuf ibuf_rde; 49 50void 51sighdlr(int sig) 52{ 53 switch (sig) { 54 case SIGTERM: 55 case SIGINT: 56 case SIGCHLD: 57 quit = 1; 58 break; 59 case SIGHUP: 60 reconfig = 1; 61 break; 62 case SIGALRM: 63 mrtdump = 1; 64 break; 65 case SIGUSR1: 66 mrtdump = 2; 67 break; 68 } 69} 70 71void 72usage(void) 73{ 74 extern char *__progname; 75 76 fprintf(stderr, "usage: %s [-dnv] ", __progname); 77 fprintf(stderr, "[-D macro=value] [-f file]\n"); 78 exit(1); 79} 80 81#define POLL_MAX 8 82#define PFD_PIPE_SESSION 0 83#define PFD_PIPE_ROUTE 1 84#define PFD_MRT_START 2 85 86int 87main(int argc, char *argv[]) 88{ 89 struct bgpd_config conf; 90 struct mrt_config mrtconf; 91 struct mrtdump_config *mconf, *(mrt[POLL_MAX]); 92 struct pollfd pfd[POLL_MAX]; 93 pid_t io_pid = 0, rde_pid = 0; 94 char *conffile; 95 int debug = 0; 96 int ch, i, j, n, nfds; 97 int pipe_m2s[2]; 98 int pipe_m2r[2]; 99 int pipe_s2r[2]; 100 101 conffile = CONFFILE; 102 bgpd_process = PROC_MAIN; 103 104 log_init(1); /* log to stderr until daemonized */ 105 106 if (geteuid()) 107 errx(1, "need root privileges"); 108 109 bzero(&conf, sizeof(conf)); 110 bzero(&mrtconf, sizeof(mrtconf)); 111 LIST_INIT(&mrtconf); 112 113 while ((ch = getopt(argc, argv, "dD:f:nv")) != -1) { 114 switch (ch) { 115 case 'd': 116 debug = 1; 117 break; 118 case 'D': 119 if (cmdline_symset(optarg) < 0) 120 logit(LOG_CRIT, 121 "could not parse macro definition %s", 122 optarg); 123 break; 124 case 'f': 125 conffile = optarg; 126 break; 127 case 'n': 128 conf.opts |= BGPD_OPT_NOACTION; 129 break; 130 case 'v': 131 if (conf.opts & BGPD_OPT_VERBOSE) 132 conf.opts |= BGPD_OPT_VERBOSE2; 133 conf.opts |= BGPD_OPT_VERBOSE; 134 break; 135 default: 136 usage(); 137 /* NOTREACHED */ 138 } 139 } 140 141 if (parse_config(conffile, &conf, &mrtconf)) 142 exit (1); 143 144 if (conf.opts & BGPD_OPT_NOACTION) { 145 fprintf(stderr, "configuration OK\n"); 146 exit(0); 147 } 148 149 signal(SIGTERM, sighdlr); 150 signal(SIGINT, sighdlr); 151 signal(SIGCHLD, sighdlr); 152 signal(SIGHUP, sighdlr); 153 signal(SIGALRM, sighdlr); 154 signal(SIGUSR1, sighdlr); 155 156 log_init(debug); 157 158 if (!debug) 159 daemon(1, 0); 160 161 logit(LOG_INFO, "startup"); 162 163 if (pipe(pipe_m2s) == -1) 164 fatal("pipe", errno); 165 if (fcntl(pipe_m2s[0], F_SETFL, O_NONBLOCK) == -1 || 166 fcntl(pipe_m2s[1], F_SETFL, O_NONBLOCK) == -1) 167 fatal("fcntl", errno); 168 if (pipe(pipe_m2r) == -1) 169 fatal("pipe", errno); 170 if (fcntl(pipe_m2r[0], F_SETFL, O_NONBLOCK) == -1 || 171 fcntl(pipe_m2r[1], F_SETFL, O_NONBLOCK) == -1) 172 fatal("fcntl", errno); 173 if (pipe(pipe_s2r) == -1) 174 fatal("pipe", errno); 175 if (fcntl(pipe_s2r[0], F_SETFL, O_NONBLOCK) == -1 || 176 fcntl(pipe_s2r[1], F_SETFL, O_NONBLOCK) == -1) 177 fatal("fcntl", errno); 178 179 if ((rde_pid = rde_main(&conf, pipe_m2r, pipe_s2r)) < 0) 180 fatal("could not start route decision engine", 0); 181 182 if ((io_pid = session_main(&conf, pipe_m2s, pipe_s2r)) < 0) 183 fatal("could not start session engine", 0); 184 185 setproctitle("parent"); 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 195 while (quit == 0) { 196 pfd[PFD_PIPE_SESSION].fd = ibuf_se.sock; 197 pfd[PFD_PIPE_SESSION].events = POLLIN; 198 if (ibuf_se.w.queued) 199 pfd[PFD_PIPE_SESSION].events |= POLLOUT; 200 pfd[PFD_PIPE_ROUTE].fd = ibuf_rde.sock; 201 pfd[PFD_PIPE_ROUTE].events = POLLIN; 202 if (ibuf_rde.w.queued) 203 pfd[PFD_PIPE_ROUTE].events |= POLLOUT; 204 i = PFD_MRT_START; 205 LIST_FOREACH(mconf, &mrtconf, list) 206 if (mconf->msgbuf.queued > 0) { 207 pfd[i].fd = mconf->msgbuf.sock; 208 pfd[i].events |= POLLOUT; 209 mrt[i++] = mconf; 210 } 211 212 if ((nfds = poll(pfd, 2, INFTIM)) == -1) 213 if (errno != EINTR) 214 fatal("poll error", errno); 215 216 if (nfds > 0 && (pfd[PFD_PIPE_SESSION].revents & POLLOUT)) 217 if ((n = msgbuf_write(&ibuf_se.w)) == -1) 218 fatal("pipe write error", errno); 219 220 if (nfds > 0 && (pfd[PFD_PIPE_ROUTE].revents & POLLOUT)) 221 if ((n = msgbuf_write(&ibuf_rde.w)) == -1) 222 fatal("pipe write error", errno); 223 224 if (nfds > 0 && pfd[PFD_PIPE_SESSION].revents & POLLIN) { 225 nfds--; 226 dispatch_imsg(&ibuf_se, PFD_PIPE_SESSION, &mrtconf); 227 } 228 229 if (nfds > 0 && pfd[PFD_PIPE_ROUTE].revents & POLLIN) { 230 nfds--; 231 dispatch_imsg(&ibuf_rde, PFD_PIPE_ROUTE, &mrtconf); 232 } 233 234 for (j = PFD_MRT_START; j < i && nfds > 0 ; j++) { 235 if (pfd[j].revents & POLLOUT) { 236 if ((n = msgbuf_write(&mrt[i]->msgbuf)) == -1) 237 fatal("pipe write error", errno); 238 } 239 } 240 241 if (reconfig) { 242 logit(LOG_CRIT, "rereading config"); 243 reconfigure(conffile, &conf, &mrtconf); 244 LIST_FOREACH(mconf, &mrtconf, list) 245 mrt_state(mconf, IMSG_NONE, &ibuf_rde); 246 reconfig = 0; 247 } 248 249 if (mrtdump == 1) { 250 mrt_alrm(&mrtconf, &ibuf_rde); 251 mrtdump = 0; 252 } else if (mrtdump == 2) { 253 mrt_usr1(&mrtconf, &ibuf_rde); 254 mrtdump = 0; 255 } 256 } 257 258 signal(SIGCHLD, SIG_IGN); 259 260 if (io_pid) 261 kill(io_pid, SIGTERM); 262 263 if (rde_pid) 264 kill(rde_pid, SIGTERM); 265 266 do { 267 i = waitpid(-1, NULL, WNOHANG); 268 } while (i > 0 || (i == -1 && errno == EINTR)); 269 270 logit(LOG_CRIT, "Terminating"); 271 return (0); 272} 273 274int 275reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_config *mrtc) 276{ 277 struct peer *p; 278 279 if (parse_config(conffile, conf, mrtc)) { 280 logit(LOG_CRIT, "config file %s has errors, not reloading", 281 conffile); 282 return (-1); 283 } 284 imsg_compose(&ibuf_se, IMSG_RECONF_CONF, 0, 285 conf, sizeof(struct bgpd_config)); 286 imsg_compose(&ibuf_rde, IMSG_RECONF_CONF, 0, 287 conf, sizeof(struct bgpd_config)); 288 for (p = conf->peers; p != NULL; p = p->next) { 289 imsg_compose(&ibuf_se, IMSG_RECONF_PEER, p->conf.id, 290 &p->conf, sizeof(struct peer_config)); 291 imsg_compose(&ibuf_rde, IMSG_RECONF_PEER, p->conf.id, 292 &p->conf, sizeof(struct peer_config)); 293 } 294 imsg_compose(&ibuf_se, IMSG_RECONF_DONE, 0, NULL, 0); 295 imsg_compose(&ibuf_rde, IMSG_RECONF_DONE, 0, NULL, 0); 296 297 return (0); 298} 299 300/* 301 * XXX currently messages are only buffered for mrt files. 302 */ 303int 304dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_config *conf) 305{ 306 struct imsg imsg; 307 struct buf *wbuf; 308 struct mrtdump_config *m; 309 ssize_t len; 310 int n; 311 312 if (imsg_get(ibuf, &imsg) > 0) { 313 switch (imsg.hdr.type) { 314 case IMSG_MRT_MSG: 315 case IMSG_MRT_END: 316 LIST_FOREACH(m, conf, list) { 317 if (m->id != imsg.hdr.peerid) 318 continue; 319 if (mrt_state(m, imsg.hdr.type, ibuf) == 0) 320 break; 321 if (m->msgbuf.sock == -1) 322 break; 323 len = imsg.hdr.len - IMSG_HEADER_SIZE; 324 wbuf = buf_open(len); 325 if (wbuf == NULL) 326 fatal("buf_open error", 0); 327 if (buf_add(wbuf, imsg.data, len) == -1) 328 fatal("buf_add error", 0); 329 if ((n = buf_close(&m->msgbuf, wbuf)) == -1) 330 fatal("buf_close error", 0); 331 break; 332 } 333 break; 334 default: 335 break; 336 } 337 imsg_free(&imsg); 338 } 339 return (0); 340} 341 342