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