xref: /openbsd-src/usr.sbin/ripd/rde.c (revision f1b790a5738b7375271fee81f99119b1f82f2cfd)
1*f1b790a5Sclaudio /*	$OpenBSD: rde.c,v 1.31 2024/11/21 13:38:15 claudio Exp $ */
2ddeeec14Snorby 
3ddeeec14Snorby /*
4ddeeec14Snorby  * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
5ddeeec14Snorby  * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org>
6ddeeec14Snorby  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7ddeeec14Snorby  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8ddeeec14Snorby  *
9ddeeec14Snorby  * Permission to use, copy, modify, and distribute this software for any
10ddeeec14Snorby  * purpose with or without fee is hereby granted, provided that the above
11ddeeec14Snorby  * copyright notice and this permission notice appear in all copies.
12ddeeec14Snorby  *
13ddeeec14Snorby  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14ddeeec14Snorby  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15ddeeec14Snorby  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16ddeeec14Snorby  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17ddeeec14Snorby  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18ddeeec14Snorby  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19ddeeec14Snorby  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20ddeeec14Snorby  */
21ddeeec14Snorby 
22ddeeec14Snorby #include <sys/socket.h>
23ddeeec14Snorby #include <sys/queue.h>
24ddeeec14Snorby #include <netinet/in.h>
25ddeeec14Snorby #include <arpa/inet.h>
26ddeeec14Snorby #include <err.h>
27ddeeec14Snorby #include <errno.h>
28ddeeec14Snorby #include <stdlib.h>
29ddeeec14Snorby #include <signal.h>
30ddeeec14Snorby #include <string.h>
31ddeeec14Snorby #include <pwd.h>
32ddeeec14Snorby #include <unistd.h>
33ddeeec14Snorby #include <event.h>
34ddeeec14Snorby 
35ddeeec14Snorby #include "ripd.h"
36ddeeec14Snorby #include "rip.h"
37ddeeec14Snorby #include "ripe.h"
38ddeeec14Snorby #include "log.h"
39ddeeec14Snorby #include "rde.h"
40ddeeec14Snorby 
41b9fc9a72Sderaadt #define	MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
42b9fc9a72Sderaadt 
43ddeeec14Snorby struct ripd_conf	*rdeconf = NULL;
445434bd38Sclaudio static struct imsgev	*iev_ripe;
455434bd38Sclaudio static struct imsgev	*iev_main;
46ddeeec14Snorby 
47ddeeec14Snorby void	rde_sig_handler(int, short, void *);
48f6798567Srenato __dead void rde_shutdown(void);
49ddeeec14Snorby void	rde_dispatch_imsg(int, short, void *);
50ddeeec14Snorby void	rde_dispatch_parent(int, short, void *);
51ddeeec14Snorby int	rde_imsg_compose_ripe(int, u_int32_t, pid_t, void *, u_int16_t);
52ddeeec14Snorby int	rde_check_route(struct rip_route *);
53ddeeec14Snorby void	triggered_update(struct rt_node *);
54ddeeec14Snorby 
55ddeeec14Snorby void
56ddeeec14Snorby rde_sig_handler(int sig, short event, void *arg)
57ddeeec14Snorby {
58ddeeec14Snorby 	/*
59ddeeec14Snorby 	 * signal handler rules don't apply, libevent decouples for us
60ddeeec14Snorby 	 */
61ddeeec14Snorby 
62ddeeec14Snorby 	switch (sig) {
63ddeeec14Snorby 	case SIGINT:
64ddeeec14Snorby 	case SIGTERM:
65ddeeec14Snorby 		rde_shutdown();
66ddeeec14Snorby 		/* NOTREACHED */
67ddeeec14Snorby 	default:
68ddeeec14Snorby 		fatalx("unexpected signal");
69ddeeec14Snorby 	}
70ddeeec14Snorby }
71ddeeec14Snorby 
72ddeeec14Snorby /* route decision engine */
73ddeeec14Snorby pid_t
74ddeeec14Snorby rde(struct ripd_conf *xconf, int pipe_parent2rde[2], int pipe_ripe2rde[2],
75ddeeec14Snorby     int pipe_parent2ripe[2])
76ddeeec14Snorby {
77ddeeec14Snorby 	struct event		 ev_sigint, ev_sigterm;
789bb9ec63Sclaudio 	struct passwd		*pw;
799bb9ec63Sclaudio 	struct redistribute	*r;
80ddeeec14Snorby 	pid_t			 pid;
81ddeeec14Snorby 
82ddeeec14Snorby 	switch (pid = fork()) {
83ddeeec14Snorby 	case -1:
84ddeeec14Snorby 		fatal("cannot fork");
85ddeeec14Snorby 		/* NOTREACHED */
86ddeeec14Snorby 	case 0:
87ddeeec14Snorby 		break;
88ddeeec14Snorby 	default:
89ddeeec14Snorby 		return (pid);
90ddeeec14Snorby 	}
91ddeeec14Snorby 
92ddeeec14Snorby 	rdeconf = xconf;
93ddeeec14Snorby 
94ddeeec14Snorby 	if ((pw = getpwnam(RIPD_USER)) == NULL)
95ddeeec14Snorby 		fatal("getpwnam");
96ddeeec14Snorby 
97ddeeec14Snorby 	if (chroot(pw->pw_dir) == -1)
98ddeeec14Snorby 		fatal("chroot");
99ddeeec14Snorby 	if (chdir("/") == -1)
100ddeeec14Snorby 		fatal("chdir(\"/\")");
101ddeeec14Snorby 
102ddeeec14Snorby 	setproctitle("route decision engine");
10379911490Sclaudio 	log_procname = "rde";
104ddeeec14Snorby 
105ddeeec14Snorby 	if (setgroups(1, &pw->pw_gid) ||
106ddeeec14Snorby 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
107ddeeec14Snorby 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
108ddeeec14Snorby 		fatal("can't drop privileges");
109ddeeec14Snorby 
110e0f3cc49Sremi 	if (pledge("stdio", NULL) == -1)
111e0f3cc49Sremi 		fatal("pledge");
112e0f3cc49Sremi 
113ddeeec14Snorby 	event_init();
114ddeeec14Snorby 
115ddeeec14Snorby 	/* setup signal handler */
116ddeeec14Snorby 	signal_set(&ev_sigint, SIGINT, rde_sig_handler, NULL);
117ddeeec14Snorby 	signal_set(&ev_sigterm, SIGTERM, rde_sig_handler, NULL);
118ddeeec14Snorby 	signal_add(&ev_sigint, NULL);
119ddeeec14Snorby 	signal_add(&ev_sigterm, NULL);
120bfb3864dSclaudio 	signal(SIGPIPE, SIG_IGN);
1212a8226daSclaudio 	signal(SIGHUP, SIG_IGN);
122ddeeec14Snorby 
123ddeeec14Snorby 	/* setup pipes */
124ddeeec14Snorby 	close(pipe_ripe2rde[0]);
125ddeeec14Snorby 	close(pipe_parent2rde[0]);
126ddeeec14Snorby 	close(pipe_parent2ripe[0]);
127ddeeec14Snorby 	close(pipe_parent2ripe[1]);
128ddeeec14Snorby 
129f7ce36daSeric 	if ((iev_ripe = malloc(sizeof(struct imsgev))) == NULL ||
130f7ce36daSeric 	    (iev_main = malloc(sizeof(struct imsgev))) == NULL)
131ddeeec14Snorby 		fatal(NULL);
132*f1b790a5Sclaudio 	if (imsgbuf_init(&iev_ripe->ibuf, pipe_ripe2rde[1]) == -1)
133*f1b790a5Sclaudio 		fatal(NULL);
134f7ce36daSeric 	iev_ripe->handler =  rde_dispatch_imsg;
135*f1b790a5Sclaudio 	if (imsgbuf_init(&iev_main->ibuf, pipe_parent2rde[1]) == -1)
136*f1b790a5Sclaudio 		fatal(NULL);
137f7ce36daSeric 	iev_main->handler = rde_dispatch_parent;
138ddeeec14Snorby 
139ddeeec14Snorby 	/* setup event handler */
140f7ce36daSeric 	iev_ripe->events = EV_READ;
141f7ce36daSeric 	event_set(&iev_ripe->ev, iev_ripe->ibuf.fd, iev_ripe->events,
142f7ce36daSeric 	    iev_ripe->handler, iev_ripe);
143f7ce36daSeric 	event_add(&iev_ripe->ev, NULL);
144ddeeec14Snorby 
145f7ce36daSeric 	iev_main->events = EV_READ;
146f7ce36daSeric 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
147f7ce36daSeric 	    iev_main->handler, iev_main);
148f7ce36daSeric 	event_add(&iev_main->ev, NULL);
149ddeeec14Snorby 	rt_init();
1509bb9ec63Sclaudio 
1519bb9ec63Sclaudio 	/* remove unneeded config stuff */
1529bb9ec63Sclaudio 	while ((r = SIMPLEQ_FIRST(&rdeconf->redist_list)) != NULL) {
1539bb9ec63Sclaudio 		SIMPLEQ_REMOVE_HEAD(&rdeconf->redist_list, entry);
1549bb9ec63Sclaudio 		free(r);
1559bb9ec63Sclaudio 	}
1569bb9ec63Sclaudio 
157ddeeec14Snorby 	event_dispatch();
158ddeeec14Snorby 
159ddeeec14Snorby 	rde_shutdown();
160ddeeec14Snorby 	/* NOTREACHED */
161ddeeec14Snorby 
162ddeeec14Snorby 	return (0);
163ddeeec14Snorby }
164ddeeec14Snorby 
165f6798567Srenato __dead void
166ddeeec14Snorby rde_shutdown(void)
167ddeeec14Snorby {
168f6798567Srenato 	/* close pipes */
1699cbf9e90Sclaudio 	imsgbuf_clear(&iev_ripe->ibuf);
170f6798567Srenato 	close(iev_ripe->ibuf.fd);
1719cbf9e90Sclaudio 	imsgbuf_clear(&iev_main->ibuf);
172f6798567Srenato 	close(iev_main->ibuf.fd);
173f6798567Srenato 
174f6798567Srenato 	rt_clear();
175f6798567Srenato 	free(iev_ripe);
176f7ce36daSeric 	free(iev_main);
177ddeeec14Snorby 	free(rdeconf);
178ddeeec14Snorby 
179ddeeec14Snorby 	log_info("route decision engine exiting");
180ddeeec14Snorby 	_exit(0);
181ddeeec14Snorby }
182ddeeec14Snorby 
183ddeeec14Snorby int
184ddeeec14Snorby rde_imsg_compose_ripe(int type, u_int32_t peerid, pid_t pid, void *data,
185ddeeec14Snorby     u_int16_t datalen)
186ddeeec14Snorby {
187f7ce36daSeric 	return (imsg_compose_event(iev_ripe, type, peerid, pid, -1,
188f7ce36daSeric 		    data, datalen));
189ddeeec14Snorby }
190ddeeec14Snorby 
191ddeeec14Snorby void
192ddeeec14Snorby rde_dispatch_imsg(int fd, short event, void *bula)
193ddeeec14Snorby {
194f7ce36daSeric 	struct imsgev		*iev = bula;
195f7ce36daSeric 	struct imsgbuf		*ibuf = &iev->ibuf;
196ddeeec14Snorby 	struct rip_route	 rr;
197ddeeec14Snorby 	struct imsg		 imsg;
1982a8226daSclaudio 	ssize_t			 n;
199dce97bddSclaudio 	int			 shut = 0, verbose;
200ddeeec14Snorby 
201bd6053efSclaudio 	if (event & EV_READ) {
202668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
203dd7efffeSclaudio 			fatal("imsgbuf_read error");
204ddeeec14Snorby 		if (n == 0)	/* connection closed */
2052a8226daSclaudio 			shut = 1;
206bd6053efSclaudio 	}
207bd6053efSclaudio 	if (event & EV_WRITE) {
208dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
209c1aa9554Sclaudio 			if (errno == EPIPE)	/* connection closed */
2101203692fSkrw 				shut = 1;
211c1aa9554Sclaudio 			else
212dd7efffeSclaudio 				fatal("imsgbuf_write");
213c1aa9554Sclaudio 		}
214ddeeec14Snorby 	}
215ddeeec14Snorby 
216ddeeec14Snorby 	for (;;) {
217ddeeec14Snorby 		if ((n = imsg_get(ibuf, &imsg)) == -1)
21879e8bbf6Sclaudio 			fatal("rde_dispatch_imsg: imsg_get error");
219ddeeec14Snorby 		if (n == 0)
220ddeeec14Snorby 			break;
221ddeeec14Snorby 
222ddeeec14Snorby 		switch (imsg.hdr.type) {
223ddeeec14Snorby 		case IMSG_ROUTE_FEED:
224ddeeec14Snorby 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rr))
225ddeeec14Snorby 				fatalx("invalid size of RDE request");
226ddeeec14Snorby 
227ddeeec14Snorby 			memcpy(&rr, imsg.data, sizeof(rr));
228ddeeec14Snorby 
229ddeeec14Snorby 			if (rde_check_route(&rr) == -1)
230ddeeec14Snorby 				log_debug("rde_dispatch_imsg: "
231ddeeec14Snorby 				    "packet malformed\n");
232ddeeec14Snorby 			break;
233ddeeec14Snorby 		case IMSG_FULL_REQUEST:
234ddeeec14Snorby 			bzero(&rr, sizeof(rr));
235726964a1Sderaadt 			/*
236726964a1Sderaadt 			 * AFI == 0 && metric == INFINITY request the
237726964a1Sderaadt 			 * whole routing table
238ddeeec14Snorby 			 */
239ddeeec14Snorby 			rr.metric = INFINITY;
240ddeeec14Snorby 			rde_imsg_compose_ripe(IMSG_REQUEST_ADD, 0,
241ddeeec14Snorby 			    0, &rr, sizeof(rr));
242ddeeec14Snorby 			rde_imsg_compose_ripe(IMSG_SEND_REQUEST, 0,
243ddeeec14Snorby 			    0, NULL, 0);
244ddeeec14Snorby 			break;
245ddeeec14Snorby 		case IMSG_FULL_RESPONSE:
246ddeeec14Snorby 			rt_snap(imsg.hdr.peerid);
247ddeeec14Snorby 			rde_imsg_compose_ripe(IMSG_SEND_RESPONSE,
248ddeeec14Snorby 			    imsg.hdr.peerid, 0, NULL, 0);
249ddeeec14Snorby 			break;
250ddeeec14Snorby 		case IMSG_ROUTE_REQUEST:
251ddeeec14Snorby 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rr))
252ddeeec14Snorby 				fatalx("invalid size of RDE request");
253ddeeec14Snorby 
254ddeeec14Snorby 			memcpy(&rr, imsg.data, sizeof(rr));
255ddeeec14Snorby 
256ddeeec14Snorby 			rt_complete(&rr);
257ddeeec14Snorby 			rde_imsg_compose_ripe(IMSG_RESPONSE_ADD,
258ddeeec14Snorby 			    imsg.hdr.peerid, 0, &rr, sizeof(rr));
259ddeeec14Snorby 
260ddeeec14Snorby 			break;
261ddeeec14Snorby 		case IMSG_ROUTE_REQUEST_END:
262ddeeec14Snorby 			rde_imsg_compose_ripe(IMSG_SEND_RESPONSE,
263ddeeec14Snorby 			    imsg.hdr.peerid, 0, NULL, 0);
264ddeeec14Snorby 			break;
265ddeeec14Snorby 		case IMSG_CTL_SHOW_RIB:
266ddeeec14Snorby 			rt_dump(imsg.hdr.pid);
267ddeeec14Snorby 
268f7ce36daSeric 			imsg_compose_event(iev_ripe, IMSG_CTL_END, 0,
269f7ce36daSeric 			    imsg.hdr.pid, -1, NULL, 0);
270ddeeec14Snorby 
271ddeeec14Snorby 			break;
272dce97bddSclaudio 		case IMSG_CTL_LOG_VERBOSE:
273dce97bddSclaudio 			/* already checked by ripe */
274dce97bddSclaudio 			memcpy(&verbose, imsg.data, sizeof(verbose));
275dce97bddSclaudio 			log_verbose(verbose);
276dce97bddSclaudio 			break;
277ddeeec14Snorby 		default:
278ddeeec14Snorby 			log_debug("rde_dispatch_msg: unexpected imsg %d",
279ddeeec14Snorby 			    imsg.hdr.type);
280ddeeec14Snorby 			break;
281ddeeec14Snorby 		}
282ddeeec14Snorby 		imsg_free(&imsg);
283ddeeec14Snorby 	}
2842a8226daSclaudio 	if (!shut)
285f7ce36daSeric 		imsg_event_add(iev);
2862a8226daSclaudio 	else {
2872a8226daSclaudio 		/* this pipe is dead, so remove the event handler */
288f7ce36daSeric 		event_del(&iev->ev);
2892a8226daSclaudio 		event_loopexit(NULL);
2902a8226daSclaudio 	}
291ddeeec14Snorby }
292ddeeec14Snorby 
293ddeeec14Snorby void
294ddeeec14Snorby rde_dispatch_parent(int fd, short event, void *bula)
295ddeeec14Snorby {
296ddeeec14Snorby 	struct imsg		 imsg;
297ddeeec14Snorby 	struct rt_node		*rt;
298ddeeec14Snorby 	struct kroute		 kr;
299f7ce36daSeric 	struct imsgev		*iev = bula;
300f7ce36daSeric 	struct imsgbuf		*ibuf = &iev->ibuf;
301ddeeec14Snorby 	ssize_t			 n;
3022a8226daSclaudio 	int			 shut = 0;
303ddeeec14Snorby 
304bd6053efSclaudio 	if (event & EV_READ) {
305668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
306dd7efffeSclaudio 			fatal("imsgbuf_read error");
307ddeeec14Snorby 		if (n == 0)	/* connection closed */
3082a8226daSclaudio 			shut = 1;
309bd6053efSclaudio 	}
310bd6053efSclaudio 	if (event & EV_WRITE) {
311dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
312c1aa9554Sclaudio 			if (errno == EPIPE)	/* connection closed */
3131203692fSkrw 				shut = 1;
314c1aa9554Sclaudio 			else
315dd7efffeSclaudio 				fatal("imsgbuf_write");
316c1aa9554Sclaudio 		}
317ddeeec14Snorby 	}
318ddeeec14Snorby 
319ddeeec14Snorby 	for (;;) {
320ddeeec14Snorby 		if ((n = imsg_get(ibuf, &imsg)) == -1)
32179e8bbf6Sclaudio 			fatal("rde_dispatch_parent: imsg_get error");
322ddeeec14Snorby 		if (n == 0)
323ddeeec14Snorby 			break;
324ddeeec14Snorby 
325ddeeec14Snorby 		switch (imsg.hdr.type) {
326ddeeec14Snorby 		case IMSG_NETWORK_ADD:
327ddeeec14Snorby 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(kr)) {
328ddeeec14Snorby 				log_warnx("rde_dispatch: wrong imsg len");
329ddeeec14Snorby 				break;
330ddeeec14Snorby 			}
331ddeeec14Snorby 
332ddeeec14Snorby 			memcpy(&kr, imsg.data, sizeof(kr));
333ddeeec14Snorby 
334ddeeec14Snorby 			rt = rt_new_kr(&kr);
335ddeeec14Snorby 			rt_insert(rt);
336ddeeec14Snorby 			break;
337ddeeec14Snorby 		case IMSG_NETWORK_DEL:
338ddeeec14Snorby 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(kr)) {
339ddeeec14Snorby 				log_warnx("rde_dispatch: wrong imsg len");
340ddeeec14Snorby 				break;
341ddeeec14Snorby 			}
342ddeeec14Snorby 			memcpy(&kr, imsg.data, sizeof(kr));
343ddeeec14Snorby 
344ddeeec14Snorby 			if ((rt = rt_find(kr.prefix.s_addr,
345ddeeec14Snorby 			    kr.netmask.s_addr)) != NULL)
346ddeeec14Snorby 				rt_remove(rt);
347ddeeec14Snorby 			break;
348ddeeec14Snorby 		default:
349ddeeec14Snorby 			log_debug("rde_dispatch_parent: unexpected imsg %d",
350ddeeec14Snorby 			    imsg.hdr.type);
351ddeeec14Snorby 			break;
352ddeeec14Snorby 		}
353ddeeec14Snorby 		imsg_free(&imsg);
354ddeeec14Snorby 	}
3552a8226daSclaudio 	if (!shut)
356f7ce36daSeric 		imsg_event_add(iev);
3572a8226daSclaudio 	else {
3582a8226daSclaudio 		/* this pipe is dead, so remove the event handler */
359f7ce36daSeric 		event_del(&iev->ev);
3602a8226daSclaudio 		event_loopexit(NULL);
3612a8226daSclaudio 	}
362ddeeec14Snorby }
363ddeeec14Snorby 
364ddeeec14Snorby void
365ddeeec14Snorby rde_send_change_kroute(struct rt_node *r)
366ddeeec14Snorby {
367ddeeec14Snorby 	struct kroute	 kr;
368ddeeec14Snorby 
369ddeeec14Snorby 	bzero(&kr, sizeof(kr));
370ddeeec14Snorby 	kr.prefix.s_addr = r->prefix.s_addr;
371ddeeec14Snorby 	kr.nexthop.s_addr = r->nexthop.s_addr;
372ddeeec14Snorby 	kr.netmask.s_addr = r->netmask.s_addr;
373ddeeec14Snorby 	kr.metric = r->metric;
374ddeeec14Snorby 	kr.flags = r->flags;
375ddeeec14Snorby 	kr.ifindex = r->ifindex;
376ddeeec14Snorby 
377f7ce36daSeric 	imsg_compose_event(iev_main, IMSG_KROUTE_CHANGE, 0, 0, -1,
378f7ce36daSeric 	    &kr, sizeof(kr));
379ddeeec14Snorby }
380ddeeec14Snorby 
381ddeeec14Snorby void
382ddeeec14Snorby rde_send_delete_kroute(struct rt_node *r)
383ddeeec14Snorby {
384ddeeec14Snorby 	struct kroute	 kr;
385ddeeec14Snorby 
386ddeeec14Snorby 	bzero(&kr, sizeof(kr));
387ddeeec14Snorby 	kr.prefix.s_addr = r->prefix.s_addr;
388ddeeec14Snorby 	kr.nexthop.s_addr = r->nexthop.s_addr;
389ddeeec14Snorby 	kr.netmask.s_addr = r->netmask.s_addr;
390ddeeec14Snorby 	kr.metric = r->metric;
391ddeeec14Snorby 	kr.flags = r->flags;
392ddeeec14Snorby 	kr.ifindex = r->ifindex;
393ddeeec14Snorby 
394f7ce36daSeric 	imsg_compose_event(iev_main, IMSG_KROUTE_DELETE, 0, 0, -1,
395f7ce36daSeric 	    &kr, sizeof(kr));
396ddeeec14Snorby }
397ddeeec14Snorby 
398ddeeec14Snorby int
399ddeeec14Snorby rde_check_route(struct rip_route *e)
400ddeeec14Snorby {
401960f8542Smichele 	struct timeval	 tv, now;
402ddeeec14Snorby 	struct rt_node	*rn;
403ddeeec14Snorby 	struct iface	*iface;
4041d57a832Sclaudio 	u_int8_t	 metric;
405ddeeec14Snorby 
406ddeeec14Snorby 	if ((e->nexthop.s_addr & htonl(IN_CLASSA_NET)) ==
407ddeeec14Snorby 	    htonl(INADDR_LOOPBACK & IN_CLASSA_NET) ||
4082a8226daSclaudio 	    e->nexthop.s_addr == INADDR_ANY)
409ddeeec14Snorby 		return (-1);
410ddeeec14Snorby 
411ddeeec14Snorby 	if ((iface = if_find_index(e->ifindex)) == NULL)
412ddeeec14Snorby 		return (-1);
413ddeeec14Snorby 
414b9fc9a72Sderaadt 	metric = MINIMUM(INFINITY, e->metric + iface->cost);
415ddeeec14Snorby 
416ddeeec14Snorby 	if ((rn = rt_find(e->address.s_addr, e->mask.s_addr)) == NULL) {
417960f8542Smichele 		if (metric >= INFINITY)
418960f8542Smichele 			return (0);
419ddeeec14Snorby 		rn = rt_new_rr(e, metric);
420ddeeec14Snorby 		rt_insert(rn);
421ddeeec14Snorby 		rde_send_change_kroute(rn);
422ddeeec14Snorby 		route_start_timeout(rn);
423ddeeec14Snorby 		triggered_update(rn);
424ddeeec14Snorby 	} else {
425ddeeec14Snorby 		/*
426b8bbf4e7Sdavid 		 * XXX don't we have to track all incoming routes?
427ddeeec14Snorby 		 * what happens if the kernel route is removed later.
428ddeeec14Snorby 		 */
429ddeeec14Snorby 		if (rn->flags & F_KERNEL)
430ddeeec14Snorby 			return (0);
431ddeeec14Snorby 
432ddeeec14Snorby 		if (metric < rn->metric) {
433ddeeec14Snorby 			rn->metric = metric;
434ddeeec14Snorby 			rn->nexthop.s_addr = e->nexthop.s_addr;
435ddeeec14Snorby 			rn->ifindex = e->ifindex;
436ddeeec14Snorby 			rde_send_change_kroute(rn);
437ddeeec14Snorby 			triggered_update(rn);
438ddeeec14Snorby 		} else if (e->nexthop.s_addr == rn->nexthop.s_addr &&
439960f8542Smichele 		    metric > rn->metric) {
440ddeeec14Snorby 				rn->metric = metric;
441ddeeec14Snorby 				rde_send_change_kroute(rn);
442ddeeec14Snorby 				triggered_update(rn);
443960f8542Smichele 				if (rn->metric == INFINITY)
444960f8542Smichele 					route_start_garbage(rn);
445960f8542Smichele 		} else if (e->nexthop.s_addr != rn->nexthop.s_addr &&
446960f8542Smichele 		    metric == rn->metric) {
447960f8542Smichele 			/* If the new metric is the same as the old one,
448960f8542Smichele 			 * examine the timeout for the existing route.  If it
449960f8542Smichele 			 * is at least halfway to the expiration point, switch
450960f8542Smichele 			 * to the new route.
451960f8542Smichele 			 */
452960f8542Smichele 			timerclear(&tv);
453960f8542Smichele 			gettimeofday(&now, NULL);
454960f8542Smichele 			evtimer_pending(&rn->timeout_timer, &tv);
455960f8542Smichele 			if (tv.tv_sec - now.tv_sec < ROUTE_TIMEOUT / 2) {
456960f8542Smichele 				rn->nexthop.s_addr = e->nexthop.s_addr;
457960f8542Smichele 				rn->ifindex = e->ifindex;
458960f8542Smichele 				rde_send_change_kroute(rn);
459960f8542Smichele 			}
460ddeeec14Snorby 		}
461ddeeec14Snorby 
462960f8542Smichele 		if (e->nexthop.s_addr == rn->nexthop.s_addr &&
463960f8542Smichele 		    rn->metric < INFINITY)
464ddeeec14Snorby 			route_reset_timers(rn);
465ddeeec14Snorby 	}
466ddeeec14Snorby 
467ddeeec14Snorby 	return (0);
468ddeeec14Snorby }
469ddeeec14Snorby 
470ddeeec14Snorby void
471ddeeec14Snorby triggered_update(struct rt_node *rn)
472ddeeec14Snorby {
473ddeeec14Snorby 	struct rip_route	 rr;
474ddeeec14Snorby 
475ddeeec14Snorby 	rr.address.s_addr = rn->prefix.s_addr;
476ddeeec14Snorby 	rr.mask.s_addr = rn->netmask.s_addr;
477ddeeec14Snorby 	rr.nexthop.s_addr = rn->nexthop.s_addr;
478ddeeec14Snorby 	rr.metric = rn->metric;
479ddeeec14Snorby 	rr.ifindex = rn->ifindex;
480ddeeec14Snorby 
481ddeeec14Snorby 	rde_imsg_compose_ripe(IMSG_SEND_TRIGGERED_UPDATE, 0, 0, &rr,
482ddeeec14Snorby 	    sizeof(struct rip_route));
483ddeeec14Snorby }
484