bgpd.c revision 1.7
1/* $OpenBSD: bgpd.c,v 1.7 2003/12/20 20:53:30 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 *, int, int *, int, int *, struct bgpd_config *, 41 struct mrt_config *); 42int dispatch_imsg(int, int, struct mrt_config *, int, int *); 43 44int mrtfd = -1; 45volatile sig_atomic_t mrtdump = 0; 46volatile sig_atomic_t quit = 0; 47volatile sig_atomic_t reconfig = 0; 48 49void 50sighdlr(int sig) 51{ 52 switch (sig) { 53 case SIGTERM: 54 case SIGKILL: 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 [-dv] ", __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 int m2s_writes_queued = 0; 101 int m2r_writes_queued = 0; 102 103 conffile = CONFFILE; 104 bgpd_process = PROC_MAIN; 105 106 log_init(1); /* log to stderr until daemonized */ 107 108 if (geteuid()) 109 fatal("need root privileges", 0); 110 111 bzero(&conf, sizeof(conf)); 112 bzero(&mrtconf, sizeof(mrtconf)); 113 LIST_INIT(&mrtconf); 114 115 while ((ch = getopt(argc, argv, "dD:f:v")) != -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 '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 fatal("config file has errors", 0); 142 143 signal(SIGTERM, sighdlr); 144 signal(SIGKILL, sighdlr); 145 signal(SIGINT, sighdlr); 146 signal(SIGCHLD, sighdlr); 147 signal(SIGHUP, sighdlr); 148 signal(SIGALRM, sighdlr); 149 signal(SIGUSR1, sighdlr); 150 151 log_init(debug); 152 153 if (!debug) 154 daemon(1, 0); 155 156 logit(LOG_INFO, "startup"); 157 158 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_m2s) == -1) 159 fatal("socketpair", errno); 160 if (fcntl(pipe_m2s[0], F_SETFL, O_NONBLOCK) == -1 || 161 fcntl(pipe_m2s[1], F_SETFL, O_NONBLOCK) == -1) 162 fatal("fcntl", errno); 163 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_m2r) == -1) 164 fatal("socketpair", errno); 165 if (fcntl(pipe_m2r[0], F_SETFL, O_NONBLOCK) == -1 || 166 fcntl(pipe_m2r[1], F_SETFL, O_NONBLOCK) == -1) 167 fatal("fcntl", errno); 168 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_s2r) == -1) 169 fatal("socketpair", errno); 170 if (fcntl(pipe_s2r[0], F_SETFL, O_NONBLOCK) == -1 || 171 fcntl(pipe_s2r[1], F_SETFL, O_NONBLOCK) == -1) 172 fatal("fcntl", errno); 173 174 if ((rde_pid = rde_main(&conf, pipe_m2r, pipe_s2r)) < 0) 175 fatal("could not start route decision engine", 0); 176 177 if ((io_pid = session_main(&conf, pipe_m2s, pipe_s2r)) < 0) 178 fatal("could not start session engine", 0); 179 180 setproctitle("parent"); 181 182 close(pipe_m2s[1]); 183 close(pipe_m2r[1]); 184 close(pipe_s2r[0]); 185 close(pipe_s2r[1]); 186 187 init_imsg_buf(); 188 189 while (quit == 0) { 190 pfd[PFD_PIPE_SESSION].fd = pipe_m2s[0]; 191 pfd[PFD_PIPE_SESSION].events = POLLIN; 192 if (m2s_writes_queued) 193 pfd[PFD_PIPE_SESSION].events |= POLLOUT; 194 pfd[PFD_PIPE_ROUTE].fd = pipe_m2r[0]; 195 pfd[PFD_PIPE_ROUTE].events = POLLIN; 196 if (m2r_writes_queued) 197 pfd[PFD_PIPE_ROUTE].events |= POLLOUT; 198 i = PFD_MRT_START; 199 LIST_FOREACH(mconf, &mrtconf, list) 200 if (mconf->queued_writes) { 201 pfd[i].fd = mconf->fd; 202 pfd[i].events |= POLLOUT; 203 mrt[i++] = mconf; 204 } 205 206 if ((nfds = poll(pfd, 2, INFTIM)) == -1) 207 if (errno != EINTR) 208 fatal("poll error", errno); 209 210 if (nfds > 0 && (pfd[PFD_PIPE_SESSION].revents & POLLOUT) && 211 m2s_writes_queued) { 212 if ((n = buf_sock_write(pfd[PFD_PIPE_SESSION].fd)) == 213 -1) 214 fatal("pipe write error", errno); 215 m2s_writes_queued -= n; 216 } 217 218 if (nfds > 0 && (pfd[PFD_PIPE_ROUTE].revents & POLLOUT) && 219 m2r_writes_queued) { 220 if ((n = buf_sock_write(pfd[PFD_PIPE_ROUTE].fd)) == -1) 221 fatal("pipe write error", errno); 222 m2r_writes_queued -= n; 223 } 224 225 if (nfds > 0 && pfd[PFD_PIPE_SESSION].revents & POLLIN) { 226 nfds--; 227 dispatch_imsg(pfd[PFD_PIPE_SESSION].fd, pipe_m2s[0], 228 &mrtconf, pipe_m2r[0], &m2r_writes_queued); 229 } 230 231 if (nfds > 0 && pfd[PFD_PIPE_ROUTE].revents & POLLIN) { 232 nfds--; 233 dispatch_imsg(pfd[PFD_PIPE_ROUTE].fd, pipe_m2r[0], 234 &mrtconf, pipe_m2r[0], &m2r_writes_queued); 235 } 236 237 for (j = PFD_MRT_START; j < i && nfds > 0 ; j++) { 238 if ((pfd[j].revents & POLLOUT) && 239 mrt[i]->queued_writes) { 240 if ((n = buf_sock_write(pfd[i].fd)) == -1) 241 fatal("pipe write error", errno); 242 mrt[i]->queued_writes -= n; 243 } 244 } 245 246 if (reconfig) { 247 logit(LOG_CRIT, "rereading config"); 248 reconfigure(conffile, pipe_m2s[0], &m2s_writes_queued, 249 pipe_m2r[0], &m2r_writes_queued, &conf, &mrtconf); 250 LIST_FOREACH(mconf, &mrtconf, list) 251 mrt_state(mconf, IMSG_NONE, pipe_m2r[0], 252 &m2r_writes_queued); 253 reconfig = 0; 254 } 255 if (mrtdump == 1) { 256 mrt_alrm(&mrtconf, pipe_m2r[0], &m2r_writes_queued); 257 mrtdump = 0; 258 } else if (mrtdump == 2) { 259 mrt_usr1(&mrtconf, pipe_m2r[0], &m2r_writes_queued); 260 mrtdump = 0; 261 } 262 } 263 264 signal(SIGCHLD, SIG_IGN); 265 266 if (io_pid) 267 kill(io_pid, SIGTERM); 268 269 if (rde_pid) 270 kill(rde_pid, SIGTERM); 271 272 do { 273 i = waitpid(-1, NULL, WNOHANG); 274 } while (i > 0 || (i == -1 && errno == EINTR)); 275 276 logit(LOG_CRIT, "Terminating"); 277 return (0); 278} 279 280int 281reconfigure(char *conffile, int se_fd, int *se_waiting, int rde_fd, 282 int *rde_waiting, struct bgpd_config *conf, struct mrt_config *mrtc) 283{ 284 struct peer *p; 285 286 if (parse_config(conffile, conf, mrtc)) { 287 logit(LOG_CRIT, "config file %s has errors, not reloading", 288 conffile); 289 return (-1); 290 } 291 *se_waiting += imsg_compose(se_fd, IMSG_RECONF_CONF, 0, 292 (u_char *)conf, sizeof(struct bgpd_config)); 293 *rde_waiting += imsg_compose(rde_fd, IMSG_RECONF_CONF, 0, 294 (u_char *)conf, sizeof(struct bgpd_config)); 295 for (p = conf->peers; p != NULL; p = p->next) { 296 *se_waiting += imsg_compose(se_fd, IMSG_RECONF_PEER, 297 p->conf.id, (u_char *)&p->conf, sizeof(struct peer_config)); 298 *rde_waiting += imsg_compose(rde_fd, IMSG_RECONF_PEER, 299 p->conf.id, (u_char *)&p->conf, sizeof(struct peer_config)); 300 } 301 *se_waiting += imsg_compose(se_fd, IMSG_RECONF_DONE, 0, NULL, 0); 302 *rde_waiting += imsg_compose(rde_fd, IMSG_RECONF_DONE, 0, NULL, 0); 303 304 return (0); 305} 306 307/* 308 * XXX currently messages are only buffered for mrt files. 309 */ 310int 311dispatch_imsg(int fd, int idx, struct mrt_config *conf, 312 int rfd, int *rwait /*, int sfd, int *swait */) 313{ 314 struct buf *wbuf; 315 struct mrtdump_config *m; 316 struct imsg imsg; 317 ssize_t len; 318 int n; 319 320 if (get_imsg(fd, &imsg) > 0) { 321 switch (imsg.hdr.type) { 322 case IMSG_MRT_MSG: 323 case IMSG_MRT_END: 324 LIST_FOREACH(m, conf, list) { 325 if (m->id != imsg.hdr.peerid) 326 continue; 327 if (mrt_state(m, imsg.hdr.type, 328 rfd, rwait) == 0) 329 break; 330 if (m->fd == -1) 331 break; 332 len = imsg.hdr.len - IMSG_HEADER_SIZE; 333 wbuf = buf_open(NULL, m->fd, len); 334 if (wbuf == NULL) 335 fatal("buf_open error", 0); 336 if (buf_add(wbuf, imsg.data, len) == -1) 337 fatal("buf_add error", 0); 338 if ((n = buf_close(wbuf)) == -1) 339 fatal("buf_close error", 0); 340 m->queued_writes += n; 341 break; 342 } 343 break; 344 default: 345 break; 346 } 347 imsg_free(&imsg); 348 } 349 return (0); 350} 351 352