bgpd.c revision 1.16
1/*	$OpenBSD: bgpd.c,v 1.16 2003/12/22 15:07:05 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 *, struct bgpd_config *, struct mrt_config *);
41int	dispatch_imsg(struct imsgbuf *, int, struct mrt_config *);
42
43int			mrtfd = -1;
44volatile sig_atomic_t	mrtdump = 0;
45volatile sig_atomic_t	quit = 0;
46volatile sig_atomic_t	reconfig = 0;
47struct imsgbuf		ibuf_se;
48struct imsgbuf		ibuf_rde;
49
50void
51sighdlr(int sig)
52{
53	switch (sig) {
54	case SIGTERM:
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 [-dnv] ", __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
101	conffile = CONFFILE;
102	bgpd_process = PROC_MAIN;
103
104	log_init(1);		/* log to stderr until daemonized */
105
106	if (geteuid())
107		errx(1, "need root privileges");
108
109	bzero(&conf, sizeof(conf));
110	bzero(&mrtconf, sizeof(mrtconf));
111	LIST_INIT(&mrtconf);
112
113	while ((ch = getopt(argc, argv, "dD:f:nv")) != -1) {
114		switch (ch) {
115		case 'd':
116			debug = 1;
117			break;
118		case 'D':
119			if (cmdline_symset(optarg) < 0)
120				logit(LOG_CRIT,
121				    "could not parse macro definition %s",
122				    optarg);
123			break;
124		case 'f':
125			conffile = optarg;
126			break;
127		case 'n':
128			conf.opts |= BGPD_OPT_NOACTION;
129			break;
130		case 'v':
131			if (conf.opts & BGPD_OPT_VERBOSE)
132				conf.opts |= BGPD_OPT_VERBOSE2;
133			conf.opts |= BGPD_OPT_VERBOSE;
134			break;
135		default:
136			usage();
137			/* NOTREACHED */
138		}
139	}
140
141	if (parse_config(conffile, &conf, &mrtconf))
142		exit (1);
143
144	if (conf.opts & BGPD_OPT_NOACTION) {
145		fprintf(stderr, "configuration OK\n");
146		exit(0);
147	}
148
149	signal(SIGTERM, sighdlr);
150	signal(SIGINT, sighdlr);
151	signal(SIGCHLD, sighdlr);
152	signal(SIGHUP, sighdlr);
153	signal(SIGALRM, sighdlr);
154	signal(SIGUSR1, sighdlr);
155
156	log_init(debug);
157
158	if (!debug)
159		daemon(1, 0);
160
161	logit(LOG_INFO, "startup");
162
163	if (pipe(pipe_m2s) == -1)
164		fatal("pipe", errno);
165	if (fcntl(pipe_m2s[0], F_SETFL, O_NONBLOCK) == -1 ||
166	    fcntl(pipe_m2s[1], F_SETFL, O_NONBLOCK) == -1)
167		fatal("fcntl", errno);
168	if (pipe(pipe_m2r) == -1)
169		fatal("pipe", errno);
170	if (fcntl(pipe_m2r[0], F_SETFL, O_NONBLOCK) == -1 ||
171	    fcntl(pipe_m2r[1], F_SETFL, O_NONBLOCK) == -1)
172		fatal("fcntl", errno);
173	if (pipe(pipe_s2r) == -1)
174		fatal("pipe", errno);
175	if (fcntl(pipe_s2r[0], F_SETFL, O_NONBLOCK) == -1 ||
176	    fcntl(pipe_s2r[1], F_SETFL, O_NONBLOCK) == -1)
177		fatal("fcntl", errno);
178
179	if ((rde_pid = rde_main(&conf, pipe_m2r, pipe_s2r)) < 0)
180		fatal("could not start route decision engine", 0);
181
182	if ((io_pid = session_main(&conf, pipe_m2s, pipe_s2r)) < 0)
183		fatal("could not start session engine", 0);
184
185	setproctitle("parent");
186
187	close(pipe_m2s[1]);
188	close(pipe_m2r[1]);
189	close(pipe_s2r[0]);
190	close(pipe_s2r[1]);
191
192	imsg_init(&ibuf_se, pipe_m2s[0]);
193	imsg_init(&ibuf_rde, pipe_m2r[0]);
194
195	while (quit == 0) {
196		pfd[PFD_PIPE_SESSION].fd = ibuf_se.sock;
197		pfd[PFD_PIPE_SESSION].events = POLLIN;
198		if (ibuf_se.w.queued)
199			pfd[PFD_PIPE_SESSION].events |= POLLOUT;
200		pfd[PFD_PIPE_ROUTE].fd = ibuf_rde.sock;
201		pfd[PFD_PIPE_ROUTE].events = POLLIN;
202		if (ibuf_rde.w.queued)
203			pfd[PFD_PIPE_ROUTE].events |= POLLOUT;
204		i = PFD_MRT_START;
205		LIST_FOREACH(mconf, &mrtconf, list)
206			if (mconf->msgbuf.queued > 0) {
207				pfd[i].fd = mconf->msgbuf.sock;
208				pfd[i].events |= POLLOUT;
209				mrt[i++] = mconf;
210			}
211
212		if ((nfds = poll(pfd, 2, INFTIM)) == -1)
213			if (errno != EINTR)
214				fatal("poll error", errno);
215
216		if (nfds > 0 && (pfd[PFD_PIPE_SESSION].revents & POLLOUT))
217			if ((n = msgbuf_write(&ibuf_se.w)) == -1)
218				fatal("pipe write error", errno);
219
220		if (nfds > 0 && (pfd[PFD_PIPE_ROUTE].revents & POLLOUT))
221			if ((n = msgbuf_write(&ibuf_rde.w)) == -1)
222				fatal("pipe write error", errno);
223
224		if (nfds > 0 && pfd[PFD_PIPE_SESSION].revents & POLLIN) {
225			nfds--;
226			dispatch_imsg(&ibuf_se, PFD_PIPE_SESSION, &mrtconf);
227		}
228
229		if (nfds > 0 && pfd[PFD_PIPE_ROUTE].revents & POLLIN) {
230			nfds--;
231			dispatch_imsg(&ibuf_rde, PFD_PIPE_ROUTE, &mrtconf);
232		}
233
234		for (j =  PFD_MRT_START; j < i && nfds > 0 ; j++) {
235			if (pfd[j].revents & POLLOUT) {
236				if ((n = msgbuf_write(&mrt[i]->msgbuf)) == -1)
237					fatal("pipe write error", errno);
238			}
239		}
240
241		if (reconfig) {
242			logit(LOG_CRIT, "rereading config");
243			reconfigure(conffile, &conf, &mrtconf);
244			LIST_FOREACH(mconf, &mrtconf, list)
245				mrt_state(mconf, IMSG_NONE, &ibuf_rde);
246			reconfig = 0;
247		}
248
249		if (mrtdump == 1) {
250			mrt_alrm(&mrtconf, &ibuf_rde);
251			mrtdump = 0;
252		} else if (mrtdump == 2) {
253			mrt_usr1(&mrtconf, &ibuf_rde);
254			mrtdump = 0;
255		}
256	}
257
258	signal(SIGCHLD, SIG_IGN);
259
260	if (io_pid)
261		kill(io_pid, SIGTERM);
262
263	if (rde_pid)
264		kill(rde_pid, SIGTERM);
265
266	do {
267		i = waitpid(-1, NULL, WNOHANG);
268	} while (i > 0 || (i == -1 && errno == EINTR));
269
270	logit(LOG_CRIT, "Terminating");
271	return (0);
272}
273
274int
275reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_config *mrtc)
276{
277	struct peer		*p;
278
279	if (parse_config(conffile, conf, mrtc)) {
280		logit(LOG_CRIT, "config file %s has errors, not reloading",
281		    conffile);
282		return (-1);
283	}
284	imsg_compose(&ibuf_se, IMSG_RECONF_CONF, 0,
285	    conf, sizeof(struct bgpd_config));
286	imsg_compose(&ibuf_rde, IMSG_RECONF_CONF, 0,
287	    conf, sizeof(struct bgpd_config));
288	for (p = conf->peers; p != NULL; p = p->next) {
289		imsg_compose(&ibuf_se, IMSG_RECONF_PEER, p->conf.id,
290		    &p->conf, sizeof(struct peer_config));
291		imsg_compose(&ibuf_rde, IMSG_RECONF_PEER, p->conf.id,
292		    &p->conf, sizeof(struct peer_config));
293	}
294	imsg_compose(&ibuf_se, IMSG_RECONF_DONE, 0, NULL, 0);
295	imsg_compose(&ibuf_rde, IMSG_RECONF_DONE, 0, NULL, 0);
296
297	return (0);
298}
299
300/*
301 * XXX currently messages are only buffered for mrt files.
302 */
303int
304dispatch_imsg(struct imsgbuf *ibuf, int idx, struct mrt_config *conf)
305{
306	struct imsg		 imsg;
307	struct buf		*wbuf;
308	struct mrtdump_config	*m;
309	ssize_t			 len;
310	int			 n;
311
312	if (imsg_get(ibuf, &imsg) > 0) {
313		switch (imsg.hdr.type) {
314		case IMSG_MRT_MSG:
315		case IMSG_MRT_END:
316			LIST_FOREACH(m, conf, list) {
317				if (m->id != imsg.hdr.peerid)
318					continue;
319				if (mrt_state(m, imsg.hdr.type, ibuf) == 0)
320					break;
321				if (m->msgbuf.sock == -1)
322					break;
323				len = imsg.hdr.len - IMSG_HEADER_SIZE;
324				wbuf = buf_open(len);
325				if (wbuf == NULL)
326					fatal("buf_open error", 0);
327				if (buf_add(wbuf, imsg.data, len) == -1)
328					fatal("buf_add error", 0);
329				if ((n = buf_close(&m->msgbuf, wbuf)) == -1)
330					fatal("buf_close error", 0);
331				break;
332			}
333			break;
334		default:
335			break;
336		}
337		imsg_free(&imsg);
338	}
339	return (0);
340}
341
342