[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bgpd: changes in listener setup



the current way of setting up the listeners is a bit... strange.

here's the diff that changes it all and fixes some issues i have seen.

the parent keeps a list of the listeners too, and thus knows when it 
actually has to open a new fd. little state keeping and such of course

please try out, provoke it (reloads reloads reloads, with adding and 
removing listeners etc), read teh code, find bugs! :)

Index: bgpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.c,v
retrieving revision 1.113
diff -u -p -r1.113 bgpd.c
--- bgpd.c	9 Feb 2005 10:56:28 -0000	1.113
+++ bgpd.c	15 Mar 2005 12:35:54 -0000
@@ -234,12 +234,6 @@ main(int argc, char *argv[])
 		free(r);
 	}
 
-	while ((la = TAILQ_FIRST(conf.listen_addrs)) != NULL) {
-		TAILQ_REMOVE(conf.listen_addrs, la, entry);
-		close(la->fd);
-		free(la);
-	}
-
 	mrt_reconfigure(&mrt_l);
 
 	while (quit == 0) {
@@ -334,6 +328,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();
@@ -448,15 +447,12 @@ reconfigure(char *conffile, struct bgpd_
 		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)
Index: config.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/config.c,v
retrieving revision 1.40
diff -u -p -r1.40 config.c
--- config.c	1 Oct 2004 15:11:12 -0000	1.40
+++ config.c	15 Mar 2005 12:35:54 -0000
@@ -1,7 +1,7 @@
 /*	$OpenBSD: config.c,v 1.40 2004/10/01 15:11:12 henning Exp $ */
 
 /*
- * Copyright (c) 2003, 2004 Henning Brauer <henning_(_at_)_openbsd_(_dot_)_org>
+ * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning_(_at_)_openbsd_(_dot_)_org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -40,9 +40,13 @@ merge_config(struct bgpd_config *xconf, 
     struct peer *peer_l, struct listen_addrs *listen_addrs)
 {
 	struct peer				*p;
-	struct listen_addr			*la;
+	struct listen_addr			*nla, *ola, *next;
 	int					 errs = 0;
 
+	/*
+	 * merge the freshly parsed conf into the running xconf
+	 */
+
 	/* preserve cmd line opts */
 	conf->opts = xconf->opts;
 
@@ -76,17 +80,66 @@ merge_config(struct bgpd_config *xconf, 
 		}
 	}
 
-	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 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 (errs);
 }
@@ -236,6 +289,7 @@ prepare_listeners(struct bgpd_config *co
 			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 =
@@ -247,6 +301,7 @@ prepare_listeners(struct bgpd_config *co
 			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);
@@ -255,6 +310,9 @@ prepare_listeners(struct bgpd_config *co
 
 	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 ==
Index: session.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
retrieving revision 1.213
diff -u -p -r1.213 session.c
--- session.c	11 Mar 2005 17:46:11 -0000	1.213
+++ session.c	15 Mar 2005 12:35:55 -0000
@@ -1,7 +1,7 @@
 /*	$OpenBSD: session.c,v 1.213 2005/03/11 17:46:11 henning Exp $ */
 
 /*
- * Copyright (c) 2003, 2004 Henning Brauer <henning_(_at_)_openbsd_(_dot_)_org>
+ * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning_(_at_)_openbsd_(_dot_)_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 *ib
 			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 *ib
 				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)



Visit your host, monkey.org