diff options
author | Henning Brauer <henning@cvs.openbsd.org> | 2005-03-30 11:23:16 +0000 |
---|---|---|
committer | Henning Brauer <henning@cvs.openbsd.org> | 2005-03-30 11:23:16 +0000 |
commit | ecb8f851ab9f0fc220d4801c8dfb9e881c04d5cc (patch) | |
tree | 320d24289149f6dd872416ecca969cb84e4a77ab /usr.sbin | |
parent | 52345c2f1694327d6cb03d31ffe011d16ed720cc (diff) |
bgpd used to open listeners in advance in the parent and the SE picked
those it needed, closing all the others. this has some nasty races.
so let the parent keep the list of listeners so it knows when it has
to open a new one
claudio ok, also tested by jason ackley
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/bgpd/bgpd.c | 20 | ||||
-rw-r--r-- | usr.sbin/bgpd/config.c | 82 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.c | 31 |
3 files changed, 95 insertions, 38 deletions
diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c index aa1172540dc..96cef6f54b0 100644 --- a/usr.sbin/bgpd/bgpd.c +++ b/usr.sbin/bgpd/bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.c,v 1.115 2005/03/28 15:03:33 henning Exp $ */ +/* $OpenBSD: bgpd.c,v 1.116 2005/03/30 11:23:15 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -235,11 +235,9 @@ main(int argc, char *argv[]) TAILQ_REMOVE(rules_l, r, entry); free(r); } - - while ((la = TAILQ_FIRST(conf.listen_addrs)) != NULL) { - TAILQ_REMOVE(conf.listen_addrs, la, entry); + TAILQ_FOREACH(la, conf.listen_addrs, entry) { close(la->fd); - free(la); + la->fd = -1; } mrt_reconfigure(&mrt_l); @@ -336,6 +334,11 @@ main(int argc, char *argv[]) LIST_REMOVE(m, entry); free(m); } + while ((la = TAILQ_FIRST(conf.listen_addrs)) != NULL) { + TAILQ_REMOVE(conf.listen_addrs, la, entry); + close(la->fd); + free(la); + } free(rules_l); control_cleanup(); @@ -450,15 +453,12 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l, TAILQ_REMOVE(rules_l, r, entry); free(r); } - while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) { + TAILQ_FOREACH(la, conf->listen_addrs, entry) { if (imsg_compose(ibuf_se, IMSG_RECONF_LISTENER, 0, 0, la->fd, la, sizeof(struct listen_addr)) == -1) return (-1); - TAILQ_REMOVE(conf->listen_addrs, la, entry); - free(la); + la->fd = -1; } - free(conf->listen_addrs); - conf->listen_addrs = NULL; if (imsg_compose(ibuf_se, IMSG_RECONF_DONE, 0, 0, -1, NULL, 0) == -1 || imsg_compose(ibuf_rde, IMSG_RECONF_DONE, 0, 0, -1, NULL, 0) == -1) diff --git a/usr.sbin/bgpd/config.c b/usr.sbin/bgpd/config.c index 9facf8734a0..c08beafd45b 100644 --- a/usr.sbin/bgpd/config.c +++ b/usr.sbin/bgpd/config.c @@ -1,7 +1,7 @@ -/* $OpenBSD: config.c,v 1.44 2005/03/28 14:19:56 henning Exp $ */ +/* $OpenBSD: config.c,v 1.45 2005/03/30 11:23:15 henning Exp $ */ /* - * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -39,7 +39,11 @@ int merge_config(struct bgpd_config *xconf, struct bgpd_config *conf, struct peer *peer_l, struct listen_addrs *listen_addrs) { - struct listen_addr *la; + struct listen_addr *nla, *ola, *next; + + /* + * merge the freshly parsed conf into the running xconf + */ /* preserve cmd line opts */ conf->opts = xconf->opts; @@ -58,17 +62,66 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf, if ((conf->flags & BGPD_FLAG_REFLECTOR) && conf->clusterid == 0) conf->clusterid = conf->bgpid; - if (xconf->listen_addrs != NULL) { - while ((la = TAILQ_FIRST(xconf->listen_addrs)) != NULL) { - TAILQ_REMOVE(xconf->listen_addrs, la, entry); - free(la); + conf->listen_addrs = xconf->listen_addrs; + memcpy(xconf, conf, sizeof(struct bgpd_config)); + + if (conf->listen_addrs == NULL) { + /* there is no old conf, just copy new one over */ + xconf->listen_addrs = listen_addrs; + TAILQ_FOREACH(nla, xconf->listen_addrs, entry) + nla->reconf = RECONF_REINIT; + + } else { + /* + * merge new listeners: + * -flag all existing ones as to be deleted + * -those that are in both new and old: flag to keep + * -new ones get inserted and flagged as to reinit + * -remove all that are still flagged for deletion + */ + + TAILQ_FOREACH(nla, xconf->listen_addrs, entry) + nla->reconf = RECONF_DELETE; + + /* no new listeners? preserve default ones */ + if (TAILQ_EMPTY(listen_addrs)) + TAILQ_FOREACH(ola, xconf->listen_addrs, entry) + if (ola->flags & DEFAULT_LISTENER) + ola->reconf = RECONF_KEEP; + + for (nla = TAILQ_FIRST(listen_addrs); nla != NULL; nla = next) { + next = TAILQ_NEXT(nla, entry); + + TAILQ_FOREACH(ola, xconf->listen_addrs, entry) + if (!memcmp(&nla->sa, &ola->sa, + sizeof(nla->sa))) + break; + + if (ola == NULL) { + /* new listener, copy over */ + TAILQ_REMOVE(listen_addrs, nla, entry); + TAILQ_INSERT_TAIL(xconf->listen_addrs, + nla, entry); + nla->reconf = RECONF_REINIT; + } else /* exists, just flag */ + ola->reconf = RECONF_KEEP; } - free(xconf->listen_addrs); - } - memcpy(xconf, conf, sizeof(struct bgpd_config)); + for (nla = TAILQ_FIRST(xconf->listen_addrs); nla != NULL; + nla = next) { + next = TAILQ_NEXT(nla, entry); + if (nla->reconf == RECONF_DELETE) { + TAILQ_REMOVE(xconf->listen_addrs, nla, entry); + free(nla); + } + } - xconf->listen_addrs = listen_addrs; + while ((ola = TAILQ_FIRST(listen_addrs)) != NULL) { + TAILQ_REMOVE(listen_addrs, ola, entry); + free(ola); + } + free(listen_addrs); + } return (0); } @@ -218,6 +271,7 @@ prepare_listeners(struct bgpd_config *conf) fatal("setup_listeners calloc"); la->fd = -1; la->flags = DEFAULT_LISTENER; + la->reconf = RECONF_REINIT; 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 = @@ -229,6 +283,7 @@ prepare_listeners(struct bgpd_config *conf) fatal("setup_listeners calloc"); la->fd = -1; la->flags = DEFAULT_LISTENER; + la->reconf = RECONF_REINIT; 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); @@ -237,6 +292,9 @@ prepare_listeners(struct bgpd_config *conf) for (la = TAILQ_FIRST(conf->listen_addrs); la != NULL; la = next) { next = TAILQ_NEXT(la, entry); + if (la->reconf != RECONF_REINIT) + continue; + if ((la->fd = socket(la->sa.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { if (la->flags & DEFAULT_LISTENER && (errno == @@ -249,7 +307,7 @@ prepare_listeners(struct bgpd_config *conf) } opt = 1; - if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEPORT, + if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) fatal("setsockopt SO_REUSEPORT"); diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c index 296e925a725..b51e2328a7b 100644 --- a/usr.sbin/bgpd/session.c +++ b/usr.sbin/bgpd/session.c @@ -1,7 +1,7 @@ -/* $OpenBSD: session.c,v 1.215 2005/03/28 15:16:46 henning Exp $ */ +/* $OpenBSD: session.c,v 1.216 2005/03/30 11:23:15 henning Exp $ */ /* - * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> + * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -2109,17 +2109,20 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) if (idx != PFD_PIPE_MAIN) fatalx("reconf request not from parent"); nla = imsg.data; - TAILQ_FOREACH(la, conf->listen_addrs, entry) { + TAILQ_FOREACH(la, conf->listen_addrs, entry) if (!la_cmp(la, nla)) break; - } - - if ((nla->fd = imsg_get_fd(ibuf)) == -1) - log_warnx("expected to receive fd for %s " - "but didn't receive any", - log_sockaddr((struct sockaddr *)&la->sa)); if (la == NULL) { + if (nla->reconf != RECONF_REINIT) + fatal("king bula sez: expected REINIT"); + + if ((nla->fd = imsg_get_fd(ibuf)) == -1) + log_warnx("expected to receive fd for " + "%s but didn't receive any", + log_sockaddr((struct sockaddr *) + &la->sa)); + la = calloc(1, sizeof(struct listen_addr)); if (la == NULL) fatal(NULL); @@ -2130,9 +2133,11 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) TAILQ_INSERT_TAIL(nconf->listen_addrs, la, entry); } else { + if (nla->reconf != RECONF_KEEP) + fatal("king bula sez: expected KEEP"); la->reconf = RECONF_KEEP; - close(nla->fd); } + break; case IMSG_RECONF_DONE: if (idx != PFD_PIPE_MAIN) @@ -2156,12 +2161,6 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) !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) { |