diff options
author | Henning Brauer <henning@cvs.openbsd.org> | 2004-06-06 17:38:11 +0000 |
---|---|---|
committer | Henning Brauer <henning@cvs.openbsd.org> | 2004-06-06 17:38:11 +0000 |
commit | c2d42bcab482d8ff7df96f4a747d47aacb855904 (patch) | |
tree | 0bbf3fdfb1cb4024587c51defce1035eddbd3d05 /usr.sbin/bgpd | |
parent | 249573f8161aafd6d278817f7ede3175091d36e8 (diff) |
rework bgpd's handling of listening sockets. instead of one for each
supported address familiy, keep a tailq of an arbitary number of them.
the new struct listen_addr contains the sockaddr and the fd.
this fixes quite some nasty behaviour which was a consequence of the previous
model.
looks right deraadt@, and discussed with claudio
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r-- | usr.sbin/bgpd/bgpd.c | 19 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 34 | ||||
-rw-r--r-- | usr.sbin/bgpd/config.c | 19 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 43 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 14 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.c | 20 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.c | 248 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.h | 4 |
8 files changed, 295 insertions, 106 deletions
diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c index 6cd92f39e83..bce647303fc 100644 --- a/usr.sbin/bgpd/bgpd.c +++ b/usr.sbin/bgpd/bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.c,v 1.94 2004/05/21 11:48:56 claudio Exp $ */ +/* $OpenBSD: bgpd.c,v 1.95 2004/06/06 17:38:10 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -100,6 +100,7 @@ main(int argc, char *argv[]) struct network *net; struct filter_rule *r; struct mrt *(mrt[POLL_MAX]), *m; + struct listen_addr *la; struct pollfd pfd[POLL_MAX]; pid_t io_pid = 0, rde_pid = 0, pid; char *conffile; @@ -228,6 +229,11 @@ main(int argc, char *argv[]) free(r); } + while ((la = TAILQ_FIRST(conf.listen_addrs)) != NULL) { + TAILQ_REMOVE(conf.listen_addrs, la, entry); + free(la); + } + while (quit == 0) { pfd[PFD_PIPE_SESSION].fd = ibuf_se.fd; pfd[PFD_PIPE_SESSION].events = POLLIN; @@ -368,6 +374,7 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l, struct network *n; struct peer *p; struct filter_rule *r; + struct listen_addr *la; if (parse_config(conffile, conf, mrt_l, peer_l, &net_l, rules_l)) { log_warnx("config file %s has errors, not reloading", @@ -399,6 +406,16 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l, TAILQ_REMOVE(rules_l, r, entries); free(r); } + while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) { + if (imsg_compose(&ibuf_se, IMSG_RECONF_LISTENER, 0, + la, sizeof(struct listen_addr)) == -1) + return (-1); + TAILQ_REMOVE(conf->listen_addrs, la, entry); + free(la); + } + free(conf->listen_addrs); + conf->listen_addrs = NULL; + if (imsg_compose(&ibuf_se, IMSG_RECONF_DONE, 0, NULL, 0) == -1 || imsg_compose(&ibuf_rde, IMSG_RECONF_DONE, 0, NULL, 0) == -1) return (-1); diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 9ddd92d22c8..967c45d1de2 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.125 2004/05/21 15:36:40 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.126 2004/06/06 17:38:10 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -108,17 +108,28 @@ struct bgpd_addr { #define addr32 ba.addr32 }; +#define DEFAULT_LISTENER 0x01 + +struct listen_addr { + TAILQ_ENTRY(listen_addr) entry; + struct sockaddr_storage sa; + int fd; + enum reconf_action reconf; + u_int8_t flags; +}; + +TAILQ_HEAD(listen_addrs, listen_addr); + struct bgpd_config { - int opts; - u_int16_t as; - u_int32_t bgpid; - u_int32_t clusterid; - u_int16_t holdtime; - u_int16_t min_holdtime; - int flags; - int log; - struct sockaddr_in listen_addr; - struct sockaddr_in6 listen6_addr; + int opts; + u_int16_t as; + u_int32_t bgpid; + u_int32_t clusterid; + u_int16_t holdtime; + u_int16_t min_holdtime; + int flags; + int log; + struct listen_addrs *listen_addrs; }; struct buf_read { @@ -239,6 +250,7 @@ enum imsg_type { IMSG_RECONF_CONF, IMSG_RECONF_PEER, IMSG_RECONF_FILTER, + IMSG_RECONF_LISTENER, IMSG_RECONF_DONE, IMSG_UPDATE, IMSG_UPDATE_ERR, diff --git a/usr.sbin/bgpd/config.c b/usr.sbin/bgpd/config.c index 56f801ca75f..151f1f515a7 100644 --- a/usr.sbin/bgpd/config.c +++ b/usr.sbin/bgpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.37 2004/05/21 15:36:40 claudio Exp $ */ +/* $OpenBSD: config.c,v 1.38 2004/06/06 17:38:10 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -37,10 +37,11 @@ int host_v6(const char *, struct bgpd_addr *); int merge_config(struct bgpd_config *xconf, struct bgpd_config *conf, - struct peer *peer_l) + struct peer *peer_l, struct listen_addrs *listen_addrs) { - struct peer *p; - int errs = 0; + struct peer *p; + struct listen_addr *la; + int errs = 0; /* preserve cmd line opts */ conf->opts = xconf->opts; @@ -75,8 +76,18 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf, } } + if (xconf->listen_addrs != NULL) { + while ((la = TAILQ_FIRST(xconf->listen_addrs)) != NULL) { + TAILQ_REMOVE(xconf->listen_addrs, la, entry); + free(la); + } + free(xconf->listen_addrs); + } + memcpy(xconf, conf, sizeof(struct bgpd_config)); + xconf->listen_addrs = listen_addrs; + return (errs); } diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index 6e645c94512..846b0bb6ff1 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.112 2004/05/21 15:36:40 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.113 2004/06/06 17:38:10 henning Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -45,6 +45,7 @@ static struct peer *peer_l, *peer_l_old; static struct peer *curpeer; static struct peer *curgroup; static struct filter_head *filter_l; +static struct listen_addrs *listen_addrs; static FILE *fin = NULL; static int lineno = 1; static int errors = 0; @@ -226,20 +227,37 @@ conf_main : AS asnumber { conf->min_holdtime = $3; } | LISTEN ON address { + struct listen_addr *la; + struct sockaddr_in *in; + struct sockaddr_in6 *in6; + + if ((la = calloc(1, sizeof(struct listen_addr))) == + NULL) + fatal("parse conf_main listen on calloc"); + + la->fd = -1; + la->sa.ss_family = $3.af; switch ($3.af) { case AF_INET: - conf->listen_addr.sin_addr.s_addr = - $3.v4.s_addr; + la->sa.ss_len = sizeof(struct sockaddr_in); + in = (struct sockaddr_in *)&la->sa; + in->sin_addr.s_addr = $3.v4.s_addr; + in->sin_port = htons(BGP_PORT); break; case AF_INET6: - memcpy(&conf->listen6_addr.sin6_addr, &$3.v6, - sizeof(conf->listen6_addr.sin6_addr)); + la->sa.ss_len = sizeof(struct sockaddr_in6); + in6 = (struct sockaddr_in6 *)&la->sa; + memcpy(&in6->sin6_addr, &$3.v6, + sizeof(in6->sin6_addr)); + in6->sin6_port = htons(BGP_PORT); break; default: yyerror("king bula does not like family %u", $3.af); YYERROR; } + + TAILQ_INSERT_TAIL(listen_addrs, la, entry); } | FIBUPDATE yesno { if ($2 == 0) @@ -1279,9 +1297,12 @@ parse_config(char *filename, struct bgpd_config *xconf, fatal(NULL); if ((mrtconf = calloc(1, sizeof(struct mrt_head))) == NULL) fatal(NULL); + if ((listen_addrs = calloc(1, sizeof(struct listen_addrs))) == NULL) + fatal(NULL); LIST_INIT(mrtconf); netconf = nc; TAILQ_INIT(netconf); + TAILQ_INIT(listen_addrs); peer_l = NULL; peer_l_old = *xpeers; @@ -1293,16 +1314,6 @@ parse_config(char *filename, struct bgpd_config *xconf, filter_l = xfilter_l; TAILQ_INIT(filter_l); - conf->listen_addr.sin_len = sizeof(conf->listen_addr); - conf->listen_addr.sin_family = AF_INET; - conf->listen_addr.sin_addr.s_addr = INADDR_ANY; - conf->listen_addr.sin_port = htons(BGP_PORT); - - bzero(&conf->listen6_addr, sizeof(conf->listen6_addr)); - conf->listen6_addr.sin6_len = sizeof(conf->listen6_addr); - conf->listen6_addr.sin6_family = AF_INET6; - conf->listen6_addr.sin6_port = htons(BGP_PORT); - if ((fin = fopen(filename, "r")) == NULL) { warn("%s", filename); free(conf); @@ -1336,7 +1347,7 @@ parse_config(char *filename, struct bgpd_config *xconf, } } - errors += merge_config(xconf, conf, peer_l); + errors += merge_config(xconf, conf, peer_l, listen_addrs); errors += mrt_mergeconfig(xmconf, mrtconf); *xpeers = peer_l; diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c index dbe220be40b..6d7bcb86f38 100644 --- a/usr.sbin/bgpd/printconf.c +++ b/usr.sbin/bgpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.20 2004/05/08 19:17:20 henning Exp $ */ +/* $OpenBSD: printconf.c,v 1.21 2004/06/06 17:38:10 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -88,8 +88,8 @@ print_set(struct filter_set *set) void print_mainconf(struct bgpd_config *conf) { - struct in_addr ina; - struct in6_addr ina6; + struct in_addr ina; + struct listen_addr *la; printf("AS %u\n", conf->as); ina.s_addr = conf->bgpid; @@ -110,13 +110,9 @@ print_mainconf(struct bgpd_config *conf) if (conf->log & BGPD_LOG_UPDATES) printf("log updates\n"); - if (conf->listen_addr.sin_addr.s_addr != INADDR_ANY) - printf("listen on %s\n", inet_ntoa(conf->listen_addr.sin_addr)); - - bzero(&ina6, sizeof(ina6)); - if (bcmp(&ina6, &conf->listen6_addr.sin6_addr, sizeof(ina6))) + TAILQ_FOREACH(la, conf->listen_addrs, entry) printf("listen on %s\n", - log_sockaddr((struct sockaddr *)&conf->listen6_addr)); + log_sockaddr((struct sockaddr *)&la->sa)); } void diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 87f3c8f6fae..6b183441ff1 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.115 2004/05/21 15:36:40 claudio Exp $ */ +/* $OpenBSD: rde.c,v 1.116 2004/06/06 17:38:10 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -104,11 +104,12 @@ rde_main(struct bgpd_config *config, struct network_head *net_l, struct filter_head *rules, struct mrt_head *mrt_l, int pipe_m2r[2], int pipe_s2r[2]) { - pid_t pid; - struct passwd *pw; - struct mrt *m; - struct pollfd pfd[2]; - int nfds; + pid_t pid; + struct passwd *pw; + struct mrt *m; + struct listen_addr *la; + struct pollfd pfd[2]; + int nfds; switch (pid = fork()) { case -1: @@ -150,11 +151,16 @@ rde_main(struct bgpd_config *config, struct network_head *net_l, imsg_init(&ibuf_se, pipe_s2r[1]); imsg_init(&ibuf_main, pipe_m2r[1]); - /* main mrt list is not used in the SE */ + /* main mrt list and listener list are not used in the SE */ while ((m = LIST_FIRST(mrt_l)) != NULL) { LIST_REMOVE(m, list); free(m); } + while ((la = TAILQ_FIRST(config->listen_addrs)) != NULL) { + TAILQ_REMOVE(config->listen_addrs, la, entry); + free(la); + } + free(config->listen_addrs); pt_init(); path_init(pathhashsize); diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c index 603d68c27ac..9d581aedee6 100644 --- a/usr.sbin/bgpd/session.c +++ b/usr.sbin/bgpd/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.172 2004/05/28 18:39:09 henning Exp $ */ +/* $OpenBSD: session.c,v 1.173 2004/06/06 17:38:10 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -44,15 +44,13 @@ #include "mrt.h" #include "session.h" -#define PFD_LISTEN 0 -#define PFD_LISTEN6 1 -#define PFD_PIPE_MAIN 2 -#define PFD_PIPE_ROUTE 3 -#define PFD_SOCK_CTL 4 -#define PFD_PEERS_START 5 +#define PFD_PIPE_MAIN 0 +#define PFD_PIPE_ROUTE 1 +#define PFD_SOCK_CTL 2 +#define PFD_LISTENERS_START 3 void session_sighdlr(int); -int setup_listener(struct sockaddr *); +int setup_listeners(void); void init_conf(struct bgpd_config *); void init_peer(struct peer *); int timer_due(time_t); @@ -81,6 +79,7 @@ void session_dispatch_imsg(struct imsgbuf *, int); void session_up(struct peer *); void session_down(struct peer *); +int la_cmp(struct listen_addr *, struct listen_addr *); struct peer *getpeerbyip(struct sockaddr *); int session_match_mask(struct peer *, struct sockaddr *); struct peer *getpeerbyid(u_int32_t); @@ -91,8 +90,6 @@ struct bgpd_sysdep sysdep; struct peer *npeers; volatile sig_atomic_t session_quit = 0; int pending_reconf = 0; -int sock = -1; -int sock6 = -1; int csock = -1; struct imsgbuf ibuf_rde; struct imsgbuf ibuf_main; @@ -111,41 +108,77 @@ session_sighdlr(int sig) } int -setup_listener(struct sockaddr *sa) +setup_listeners(void) { - int fd, opt; + int opt; + struct listen_addr *la; + + if (TAILQ_EMPTY(conf->listen_addrs)) { + if ((la = calloc(1, sizeof(struct listen_addr))) == NULL) + fatal("setup_listeners calloc"); + la->fd = -1; + la->flags = DEFAULT_LISTENER; + la->sa.ss_len = sizeof(struct sockaddr_in); + ((struct sockaddr_in *)&la->sa)->sin_family = AF_INET; + ((struct sockaddr_in *)&la->sa)->sin_addr.s_addr = + htonl(INADDR_ANY); + ((struct sockaddr_in *)&la->sa)->sin_port = htons(BGP_PORT); + TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry); + + if ((la = calloc(1, sizeof(struct listen_addr))) == NULL) + fatal("setup_listeners calloc"); + la->fd = -1; + la->flags = DEFAULT_LISTENER; + la->sa.ss_len = sizeof(struct sockaddr_in6); + ((struct sockaddr_in6 *)&la->sa)->sin6_family = AF_INET6; + ((struct sockaddr_in6 *)&la->sa)->sin6_port = htons(BGP_PORT); + TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry); + } + + TAILQ_FOREACH(la, conf->listen_addrs, entry) { + la->reconf = RECONF_NONE; + + if (la->fd != -1) + continue; - if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) - fatal("king bula sez: unknown address family"); + if ((la->fd = socket(la->sa.ss_family, SOCK_STREAM, + IPPROTO_TCP)) == -1) + fatal("socket"); - if ((fd = socket(sa->sa_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { - log_warn("error setting up %s listener", - sa->sa_family == AF_INET ? "IPv4" : "IPv6"); - return (fd); - } + opt = 1; + if (setsockopt(la->fd, IPPROTO_TCP, TCP_MD5SIG, + &opt, sizeof(opt)) == -1) { + if (errno == ENOPROTOOPT) { /* system w/o md5sig */ + log_warnx("md5sig not available, disabling"); + sysdep.no_md5sig = 1; + } else + fatal("setsockopt TCP_MD5SIG"); + } - opt = 1; - if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt, sizeof(opt)) == -1) { - if (errno == ENOPROTOOPT) { /* system w/o md5sig support */ - log_warnx("md5 signatures not available, disabling"); - sysdep.no_md5sig = 1; - } else - fatal("setsockopt TCP_MD5SIG"); - } + if (bind(la->fd, (struct sockaddr *)&la->sa, la->sa.ss_len) == + -1) { + if (errno == EACCES) { + log_warnx("can't establish listener on %s", + log_sockaddr((struct sockaddr *)&la->sa)); + close(la->fd); + la->fd = -1; + return (-1); + } else + fatal("bind"); + } - if (bind(fd, sa, sa->sa_len)) { - close(fd); - fatal("bind"); - } + session_socket_blockmode(la->fd, BM_NONBLOCK); - session_socket_blockmode(fd, BM_NONBLOCK); + if (listen(la->fd, MAX_BACKLOG)) { + close(la->fd); + fatal("listen"); + } - if (listen(fd, MAX_BACKLOG)) { - close(fd); - fatal("listen"); + log_info("listening on %s", + log_sockaddr((struct sockaddr *)&la->sa)); } - return (fd); + return (0); } int @@ -153,7 +186,7 @@ session_main(struct bgpd_config *config, struct peer *cpeers, struct network_head *net_l, struct filter_head *rules, struct mrt_head *m_l, int pipe_m2s[2], int pipe_s2r[2]) { - int nfds, i, j, timeout, idx_peers; + int nfds, i, j, timeout, idx_peers, idx_listeners; pid_t pid; time_t nextaction; struct passwd *pw; @@ -164,6 +197,7 @@ session_main(struct bgpd_config *config, struct peer *cpeers, struct filter_rule *r; struct pollfd pfd[OPEN_MAX]; struct ctl_conn *ctl_conn; + struct listen_addr *la; short events; conf = config; @@ -193,8 +227,7 @@ session_main(struct bgpd_config *config, struct peer *cpeers, setproctitle("session engine"); bgpd_process = PROC_SE; - sock = setup_listener((struct sockaddr *)&conf->listen_addr); - sock6 = setup_listener((struct sockaddr *)&conf->listen6_addr); + setup_listeners(); if (pfkey_init(&sysdep) == -1) fatalx("pfkey setup failed"); @@ -240,10 +273,6 @@ session_main(struct bgpd_config *config, struct peer *cpeers, while (session_quit == 0) { bzero(&pfd, sizeof(pfd)); - pfd[PFD_LISTEN].fd = sock; - pfd[PFD_LISTEN].events = POLLIN; - pfd[PFD_LISTEN6].fd = sock6; - pfd[PFD_LISTEN6].events = POLLIN; pfd[PFD_PIPE_MAIN].fd = ibuf_main.fd; pfd[PFD_PIPE_MAIN].events = POLLIN; if (ibuf_main.w.queued > 0) @@ -256,7 +285,15 @@ session_main(struct bgpd_config *config, struct peer *cpeers, pfd[PFD_SOCK_CTL].events = POLLIN; nextaction = time(NULL) + 240; /* loop every 240s at least */ - i = PFD_PEERS_START; + i = PFD_LISTENERS_START; + + TAILQ_FOREACH(la, conf->listen_addrs, entry) { + pfd[i].fd = la->fd; + pfd[i].events = POLLIN; + i++; + } + + idx_listeners = i; last = NULL; for (p = peers; p != NULL; p = next) { @@ -353,16 +390,6 @@ session_main(struct bgpd_config *config, struct peer *cpeers, if (errno != EINTR) fatal("poll error"); - if (nfds > 0 && pfd[PFD_LISTEN].revents & POLLIN) { - nfds--; - session_accept(sock); - } - - if (nfds > 0 && pfd[PFD_LISTEN6].revents & POLLIN) { - nfds--; - session_accept(sock6); - } - if (nfds > 0 && pfd[PFD_PIPE_MAIN].revents & POLLOUT) if (msgbuf_write(&ibuf_main.w) < 0) fatal("pipe write error"); @@ -386,7 +413,14 @@ session_main(struct bgpd_config *config, struct peer *cpeers, control_accept(csock); } - for (j = PFD_PEERS_START; nfds > 0 && j < idx_peers; j++) + for (j = PFD_LISTENERS_START; nfds > 0 && j < idx_listeners; + j++) + if (pfd[j].revents & POLLIN) { + nfds--; + session_accept(pfd[j].fd); + } + + for (; nfds > 0 && j < idx_peers; j++) nfds -= session_dispatch_msg(&pfd[j], peer_l[j]); for (; nfds > 0 && j < i; j++) @@ -405,6 +439,12 @@ session_main(struct bgpd_config *config, struct peer *cpeers, free(mrt); } + while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) { + TAILQ_REMOVE(conf->listen_addrs, la, entry); + free(la); + } + free(conf->listen_addrs); + msgbuf_write(&ibuf_rde.w); msgbuf_clear(&ibuf_rde.w); msgbuf_write(&ibuf_main.w); @@ -1914,6 +1954,7 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx) struct mrt_config *mrt; struct peer_config *pconf; struct peer *p, *next; + struct listen_addr *la, *nla; u_char *data; enum reconf_action reconf; int n; @@ -1940,6 +1981,10 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx) NULL) fatal(NULL); memcpy(nconf, imsg.data, sizeof(struct bgpd_config)); + if ((nconf->listen_addrs = calloc(1, + sizeof(struct listen_addrs))) == NULL) + fatal(NULL); + TAILQ_INIT(nconf->listen_addrs); npeers = NULL; init_conf(nconf); pending_reconf = 1; @@ -1963,6 +2008,29 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx) memcpy(&p->conf, pconf, sizeof(struct peer_config)); p->conf.reconf_action = reconf; break; + case IMSG_RECONF_LISTENER: + if (idx != PFD_PIPE_MAIN) + fatalx("reconf request not from parent"); + nla = imsg.data; + TAILQ_FOREACH(la, conf->listen_addrs, entry) { + if (!la_cmp(la, nla)) + break; + } + + if (la == NULL) { + la = calloc(1, sizeof(struct listen_addr)); + if (la == NULL) + fatal(NULL); + memcpy(&la->sa, &nla->sa, sizeof(la->sa)); + la->fd = nla->fd; + la->flags = nla->flags; + la->reconf = RECONF_REINIT; + TAILQ_INSERT_TAIL(nconf->listen_addrs, la, + entry); + } else { + la->reconf = RECONF_KEEP; + } + break; case IMSG_RECONF_DONE: if (idx != PFD_PIPE_MAIN) fatalx("reconf request not from parent"); @@ -1972,17 +2040,50 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx) conf->holdtime = nconf->holdtime; conf->bgpid = nconf->bgpid; conf->min_holdtime = nconf->min_holdtime; + /* add new peers */ for (p = npeers; p != NULL; p = next) { next = p->next; p->next = peers; peers = p; } - /* find peers to be deleted */ + /* find ones to be deleted */ for (p = peers; p != NULL; p = p->next) if (p->conf.reconf_action == RECONF_NONE && !p->conf.cloned) p->conf.reconf_action = RECONF_DELETE; + + /* if there are no new listeners, keep default ones */ + if (TAILQ_EMPTY(nconf->listen_addrs)) + TAILQ_FOREACH(la, conf->listen_addrs, entry) + if (la->flags & DEFAULT_LISTENER) + la->reconf = RECONF_KEEP; + + /* delete old listeners */ + for (la = TAILQ_FIRST(conf->listen_addrs); la != NULL; + la = nla) { + nla = TAILQ_NEXT(la, entry); + if (la->reconf == RECONF_NONE) { + log_info("not listening on %s any more", + log_sockaddr( + (struct sockaddr *)&la->sa)); + TAILQ_REMOVE(conf->listen_addrs, la, + entry); + close(la->fd); + free(la); + } + } + + /* add new listeners */ + while ((la = TAILQ_FIRST(nconf->listen_addrs)) != + NULL) { + TAILQ_REMOVE(nconf->listen_addrs, la, entry); + TAILQ_INSERT_TAIL(conf->listen_addrs, la, + entry); + } + + setup_listeners(); + free(nconf->listen_addrs); free(nconf); nconf = NULL; pending_reconf = 0; @@ -2068,6 +2169,41 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx) } } +int +la_cmp(struct listen_addr *a, struct listen_addr *b) +{ + struct sockaddr_in *in_a, *in_b; + struct sockaddr_in6 *in6_a, *in6_b; + + if (a->sa.ss_family != b->sa.ss_family) + return (1); + + switch (a->sa.ss_family) { + case AF_INET: + in_a = (struct sockaddr_in *)&a->sa; + in_b = (struct sockaddr_in *)&b->sa; + if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr) + return (1); + if (in_a->sin_port != in_b->sin_port) + return (1); + break; + case AF_INET6: + in6_a = (struct sockaddr_in6 *)&a->sa; + in6_b = (struct sockaddr_in6 *)&b->sa; + if (bcmp(&in6_a->sin6_addr, &in6_b->sin6_addr, + sizeof(struct in6_addr))) + return (1); + if (in6_a->sin6_port != in6_b->sin6_port) + return (1); + break; + default: + fatal("king bula sez: unknown address family"); + /* not reached */ + } + + return (0); +} + struct peer * getpeerbyaddr(struct bgpd_addr *addr) { diff --git a/usr.sbin/bgpd/session.h b/usr.sbin/bgpd/session.h index 23232ab3731..ce140a7a23a 100644 --- a/usr.sbin/bgpd/session.h +++ b/usr.sbin/bgpd/session.h @@ -1,4 +1,4 @@ -/* $OpenBSD: session.h,v 1.53 2004/05/28 18:39:09 henning Exp $ */ +/* $OpenBSD: session.h,v 1.54 2004/06/06 17:38:10 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -207,7 +207,7 @@ int parse_config(char *, struct bgpd_config *, struct mrt_head *, /* config.c */ int merge_config(struct bgpd_config *, struct bgpd_config *, - struct peer *); + struct peer *, struct listen_addrs *); /* rde.c */ int rde_main(struct bgpd_config *, struct network_head *, |