summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd
diff options
context:
space:
mode:
authorHenning Brauer <henning@cvs.openbsd.org>2004-06-06 17:38:11 +0000
committerHenning Brauer <henning@cvs.openbsd.org>2004-06-06 17:38:11 +0000
commitc2d42bcab482d8ff7df96f4a747d47aacb855904 (patch)
tree0bbf3fdfb1cb4024587c51defce1035eddbd3d05 /usr.sbin/bgpd
parent249573f8161aafd6d278817f7ede3175091d36e8 (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.c19
-rw-r--r--usr.sbin/bgpd/bgpd.h34
-rw-r--r--usr.sbin/bgpd/config.c19
-rw-r--r--usr.sbin/bgpd/parse.y43
-rw-r--r--usr.sbin/bgpd/printconf.c14
-rw-r--r--usr.sbin/bgpd/rde.c20
-rw-r--r--usr.sbin/bgpd/session.c248
-rw-r--r--usr.sbin/bgpd/session.h4
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 *,