xref: /openbsd-src/usr.sbin/ospfd/kroute.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1 /*	$OpenBSD: kroute.c,v 1.108 2017/07/24 11:00:01 friehm Exp $ */
2 
3 /*
4  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
5  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/sysctl.h>
23 #include <sys/tree.h>
24 #include <sys/uio.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <net/if.h>
28 #include <net/if_dl.h>
29 #include <net/if_types.h>
30 #include <net/route.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <limits.h>
39 
40 #include "ospfd.h"
41 #include "log.h"
42 
43 struct {
44 	u_int32_t		rtseq;
45 	pid_t			pid;
46 	int			fib_sync;
47 	int			fib_serial;
48 	int			fd;
49 	struct event		ev;
50 	struct event		reload;
51 	u_int			rdomain;
52 #define KR_RELOAD_IDLE	0
53 #define KR_RELOAD_FETCH	1
54 #define KR_RELOAD_HOLD	2
55 	int			reload_state;
56 } kr_state;
57 
58 struct kroute_node {
59 	RB_ENTRY(kroute_node)	 entry;
60 	struct kroute_node	*next;
61 	struct kroute		 r;
62 	int			 serial;
63 };
64 
65 struct kif_node {
66 	RB_ENTRY(kif_node)	 entry;
67 	TAILQ_HEAD(, kif_addr)	 addrs;
68 	struct kif		 k;
69 };
70 
71 void	kr_redist_remove(struct kroute_node *, struct kroute_node *);
72 int	kr_redist_eval(struct kroute *, struct kroute *);
73 void	kr_redistribute(struct kroute_node *);
74 int	kroute_compare(struct kroute_node *, struct kroute_node *);
75 int	kif_compare(struct kif_node *, struct kif_node *);
76 int	kr_change_fib(struct kroute_node *, struct kroute *, int, int);
77 int	kr_delete_fib(struct kroute_node *);
78 
79 struct kroute_node	*kroute_find(in_addr_t, u_int8_t, u_int8_t);
80 struct kroute_node	*kroute_matchgw(struct kroute_node *, struct in_addr);
81 int			 kroute_insert(struct kroute_node *);
82 int			 kroute_remove(struct kroute_node *);
83 void			 kroute_clear(void);
84 
85 struct kif_node		*kif_find(u_short);
86 struct kif_node		*kif_insert(u_short);
87 int			 kif_remove(struct kif_node *);
88 struct kif		*kif_update(u_short, int, struct if_data *,
89 			    struct sockaddr_dl *);
90 int			 kif_validate(u_short);
91 
92 struct kroute_node	*kroute_match(in_addr_t);
93 
94 int		protect_lo(void);
95 u_int8_t	prefixlen_classful(in_addr_t);
96 void		get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
97 void		if_change(u_short, int, struct if_data *, struct sockaddr_dl *);
98 void		if_newaddr(u_short, struct sockaddr_in *, struct sockaddr_in *,
99 		    struct sockaddr_in *);
100 void		if_deladdr(u_short, struct sockaddr_in *, struct sockaddr_in *,
101 		    struct sockaddr_in *);
102 void		if_announce(void *);
103 
104 int		send_rtmsg(int, int, struct kroute *);
105 int		dispatch_rtmsg(void);
106 int		fetchtable(void);
107 int		fetchifs(u_short);
108 int		rtmsg_process(char *, size_t);
109 void		kr_fib_reload_timer(int, short, void *);
110 void		kr_fib_reload_arm_timer(int);
111 
112 RB_HEAD(kroute_tree, kroute_node)	krt = RB_INITIALIZER(&krt);
113 RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare)
114 RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare)
115 
116 RB_HEAD(kif_tree, kif_node)		kit = RB_INITIALIZER(&kit);
117 RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare)
118 RB_GENERATE(kif_tree, kif_node, entry, kif_compare)
119 
120 int
121 kif_init(void)
122 {
123 	if (fetchifs(0) == -1)
124 		return (-1);
125 
126 	return (0);
127 }
128 
129 int
130 kr_init(int fs, u_int rdomain)
131 {
132 	int		opt = 0, rcvbuf, default_rcvbuf;
133 	socklen_t	optlen;
134 
135 	kr_state.fib_sync = fs;
136 	kr_state.rdomain = rdomain;
137 
138 	if ((kr_state.fd = socket(AF_ROUTE,
139 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, AF_INET)) == -1) {
140 		log_warn("kr_init: socket");
141 		return (-1);
142 	}
143 
144 	/* not interested in my own messages */
145 	if (setsockopt(kr_state.fd, SOL_SOCKET, SO_USELOOPBACK,
146 	    &opt, sizeof(opt)) == -1)
147 		log_warn("kr_init: setsockopt");	/* not fatal */
148 
149 	/* grow receive buffer, don't wanna miss messages */
150 	optlen = sizeof(default_rcvbuf);
151 	if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
152 	    &default_rcvbuf, &optlen) == -1)
153 		log_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
154 	else
155 		for (rcvbuf = MAX_RTSOCK_BUF;
156 		    rcvbuf > default_rcvbuf &&
157 		    setsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
158 		    &rcvbuf, sizeof(rcvbuf)) == -1 && errno == ENOBUFS;
159 		    rcvbuf /= 2)
160 			;	/* nothing */
161 
162 	kr_state.pid = getpid();
163 	kr_state.rtseq = 1;
164 
165 	if (fetchtable() == -1)
166 		return (-1);
167 
168 	if (protect_lo() == -1)
169 		return (-1);
170 
171 	event_set(&kr_state.ev, kr_state.fd, EV_READ | EV_PERSIST,
172 	    kr_dispatch_msg, NULL);
173 	event_add(&kr_state.ev, NULL);
174 
175 	kr_state.reload_state = KR_RELOAD_IDLE;
176 	evtimer_set(&kr_state.reload, kr_fib_reload_timer, NULL);
177 
178 	return (0);
179 }
180 
181 int
182 kr_change_fib(struct kroute_node *kr, struct kroute *kroute, int krcount,
183     int action)
184 {
185 	int			 i;
186 	struct kroute_node	*kn, *nkn;
187 
188 	if (action == RTM_ADD) {
189 		/*
190 		 * First remove all stale multipath routes.
191 		 * This step must be skipped when the action is RTM_CHANGE
192 		 * because it is already a single path route that will be
193 		 * changed.
194 		 */
195 		for (kn = kr; kn != NULL; kn = nkn) {
196 			for (i = 0; i < krcount; i++) {
197 				if (kn->r.nexthop.s_addr ==
198 				    kroute[i].nexthop.s_addr)
199 					break;
200 			}
201 			nkn = kn->next;
202 			if (i == krcount) {
203 				/* stale route */
204 				if (kr_delete_fib(kn) == -1)
205 					log_warnx("kr_delete_fib failed");
206 				/*
207 				 * if head element was removed we need to adjust
208 				 * the head
209 				 */
210 				if (kr == kn)
211 					kr = nkn;
212 			}
213 		}
214 	}
215 
216 	/*
217 	 * now add or change the route
218 	 */
219 	for (i = 0; i < krcount; i++) {
220 		/* nexthop within 127/8 -> ignore silently */
221 		if ((kroute[i].nexthop.s_addr & htonl(IN_CLASSA_NET)) ==
222 		    htonl(INADDR_LOOPBACK & IN_CLASSA_NET))
223 			continue;
224 
225 		if (action == RTM_ADD && kr) {
226 			for (kn = kr; kn != NULL; kn = kn->next) {
227 				if (kn->r.nexthop.s_addr ==
228 				    kroute[i].nexthop.s_addr)
229 					break;
230 			}
231 
232 			if (kn != NULL)
233 				/* nexthop already present, skip it */
234 				continue;
235 		} else
236 			/* modify first entry */
237 			kn = kr;
238 
239 		/* send update */
240 		if (send_rtmsg(kr_state.fd, action, &kroute[i]) == -1)
241 			return (-1);
242 
243 		/* create new entry unless we are changing the first entry */
244 		if (action == RTM_ADD)
245 			if ((kn = calloc(1, sizeof(*kn))) == NULL)
246 				fatal(NULL);
247 
248 		kn->r.prefix.s_addr = kroute[i].prefix.s_addr;
249 		kn->r.prefixlen = kroute[i].prefixlen;
250 		kn->r.nexthop.s_addr = kroute[i].nexthop.s_addr;
251 		kn->r.flags = kroute[i].flags | F_OSPFD_INSERTED;
252 		kn->r.priority = RTP_OSPF;
253 		kn->r.ext_tag = kroute[i].ext_tag;
254 		rtlabel_unref(kn->r.rtlabel);	/* for RTM_CHANGE */
255 		kn->r.rtlabel = kroute[i].rtlabel;
256 
257 		if (action == RTM_ADD)
258 			if (kroute_insert(kn) == -1) {
259 				log_debug("kr_update_fib: cannot insert %s",
260 				    inet_ntoa(kn->r.nexthop));
261 				free(kn);
262 			}
263 		action = RTM_ADD;
264 	}
265 	return  (0);
266 }
267 
268 int
269 kr_change(struct kroute *kroute, int krcount)
270 {
271 	struct kroute_node	*kr;
272 	int			 action = RTM_ADD;
273 
274 	kroute->rtlabel = rtlabel_tag2id(kroute->ext_tag);
275 
276 	kr = kroute_find(kroute->prefix.s_addr, kroute->prefixlen, RTP_OSPF);
277 	if (kr != NULL && kr->next == NULL && krcount == 1)
278 		/* single path OSPF route */
279 		action = RTM_CHANGE;
280 
281 	return (kr_change_fib(kr, kroute, krcount, action));
282 }
283 
284 int
285 kr_delete_fib(struct kroute_node *kr)
286 {
287 	if (kr->r.priority != RTP_OSPF)
288 		log_warn("kr_delete_fib: %s/%d has wrong priority %d",
289 		    inet_ntoa(kr->r.prefix), kr->r.prefixlen, kr->r.priority);
290 
291 	if (send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r) == -1)
292 		return (-1);
293 
294 	if (kroute_remove(kr) == -1)
295 		return (-1);
296 
297 	return (0);
298 }
299 
300 int
301 kr_delete(struct kroute *kroute)
302 {
303 	struct kroute_node	*kr, *nkr;
304 
305 	if ((kr = kroute_find(kroute->prefix.s_addr, kroute->prefixlen,
306 	    RTP_OSPF)) == NULL)
307 		return (0);
308 
309 	while (kr != NULL) {
310 		nkr = kr->next;
311 		if (kr_delete_fib(kr) == -1)
312 			return (-1);
313 		kr = nkr;
314 	}
315 	return (0);
316 }
317 
318 void
319 kr_shutdown(void)
320 {
321 	kr_fib_decouple();
322 	kroute_clear();
323 	kif_clear();
324 }
325 
326 void
327 kr_fib_couple(void)
328 {
329 	struct kroute_node	*kr;
330 	struct kroute_node	*kn;
331 
332 	if (kr_state.fib_sync == 1)	/* already coupled */
333 		return;
334 
335 	kr_state.fib_sync = 1;
336 
337 	RB_FOREACH(kr, kroute_tree, &krt)
338 		if (kr->r.priority == RTP_OSPF)
339 			for (kn = kr; kn != NULL; kn = kn->next)
340 				send_rtmsg(kr_state.fd, RTM_ADD, &kn->r);
341 
342 	log_info("kernel routing table coupled");
343 }
344 
345 void
346 kr_fib_decouple(void)
347 {
348 	struct kroute_node	*kr;
349 	struct kroute_node	*kn;
350 
351 	if (kr_state.fib_sync == 0)	/* already decoupled */
352 		return;
353 
354 	RB_FOREACH(kr, kroute_tree, &krt)
355 		if (kr->r.priority == RTP_OSPF)
356 			for (kn = kr; kn != NULL; kn = kn->next)
357 				send_rtmsg(kr_state.fd, RTM_DELETE, &kn->r);
358 
359 	kr_state.fib_sync = 0;
360 
361 	log_info("kernel routing table decoupled");
362 }
363 
364 void
365 kr_fib_reload_timer(int fd, short event, void *bula)
366 {
367 	if (kr_state.reload_state == KR_RELOAD_FETCH) {
368 		kr_fib_reload();
369 		kr_state.reload_state = KR_RELOAD_HOLD;
370 		kr_fib_reload_arm_timer(KR_RELOAD_HOLD_TIMER);
371 	} else {
372 		kr_state.reload_state = KR_RELOAD_IDLE;
373 	}
374 }
375 
376 void
377 kr_fib_reload_arm_timer(int delay)
378 {
379 	struct timeval		 tv;
380 
381 	timerclear(&tv);
382 	tv.tv_sec = delay / 1000;
383 	tv.tv_usec = (delay % 1000) * 1000;
384 
385 	if (evtimer_add(&kr_state.reload, &tv) == -1)
386 		fatal("add_reload_timer");
387 }
388 
389 void
390 kr_fib_reload()
391 {
392 	struct kroute_node	*krn, *kr, *kn;
393 
394 	log_info("reloading interface list and routing table");
395 
396 	kr_state.fib_serial++;
397 
398 	if (fetchifs(0) == -1 || fetchtable() == -1)
399 		return;
400 
401 	for (kr = RB_MIN(kroute_tree, &krt); kr != NULL; kr = krn) {
402 		krn = RB_NEXT(kroute_tree, &krt, kr);
403 
404 		do {
405 			kn = kr->next;
406 
407 			if (kr->serial != kr_state.fib_serial) {
408 				if (kr->r.priority == RTP_OSPF) {
409 					kr->serial = kr_state.fib_serial;
410 					if (send_rtmsg(kr_state.fd,
411 					    RTM_ADD, &kr->r) != 0)
412 						break;
413 				} else
414 					kroute_remove(kr);
415 			}
416 
417 		} while ((kr = kn) != NULL);
418 	}
419 }
420 
421 /* ARGSUSED */
422 void
423 kr_dispatch_msg(int fd, short event, void *bula)
424 {
425 	/* XXX this is stupid */
426 	if (dispatch_rtmsg() == -1)
427 		event_loopexit(NULL);
428 }
429 
430 void
431 kr_show_route(struct imsg *imsg)
432 {
433 	struct kroute_node	*kr;
434 	struct kroute_node	*kn;
435 	int			 flags;
436 	struct in_addr		 addr;
437 
438 	switch (imsg->hdr.type) {
439 	case IMSG_CTL_KROUTE:
440 		if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(flags)) {
441 			log_warnx("kr_show_route: wrong imsg len");
442 			return;
443 		}
444 		memcpy(&flags, imsg->data, sizeof(flags));
445 		RB_FOREACH(kr, kroute_tree, &krt)
446 			if (!flags || kr->r.flags & flags) {
447 				kn = kr;
448 				do {
449 					main_imsg_compose_ospfe(IMSG_CTL_KROUTE,
450 					    imsg->hdr.pid,
451 					    &kn->r, sizeof(kn->r));
452 				} while ((kn = kn->next) != NULL);
453 			}
454 		break;
455 	case IMSG_CTL_KROUTE_ADDR:
456 		if (imsg->hdr.len != IMSG_HEADER_SIZE +
457 		    sizeof(struct in_addr)) {
458 			log_warnx("kr_show_route: wrong imsg len");
459 			return;
460 		}
461 		memcpy(&addr, imsg->data, sizeof(addr));
462 		kr = NULL;
463 		kr = kroute_match(addr.s_addr);
464 		if (kr != NULL)
465 			main_imsg_compose_ospfe(IMSG_CTL_KROUTE, imsg->hdr.pid,
466 			    &kr->r, sizeof(kr->r));
467 		break;
468 	default:
469 		log_debug("kr_show_route: error handling imsg");
470 		break;
471 	}
472 
473 	main_imsg_compose_ospfe(IMSG_CTL_END, imsg->hdr.pid, NULL, 0);
474 }
475 
476 void
477 kr_ifinfo(char *ifname, pid_t pid)
478 {
479 	struct kif_node	*kif;
480 
481 	RB_FOREACH(kif, kif_tree, &kit)
482 		if (ifname == NULL || !strcmp(ifname, kif->k.ifname)) {
483 			main_imsg_compose_ospfe(IMSG_CTL_IFINFO,
484 			    pid, &kif->k, sizeof(kif->k));
485 		}
486 
487 	main_imsg_compose_ospfe(IMSG_CTL_END, pid, NULL, 0);
488 }
489 
490 void
491 kr_redist_remove(struct kroute_node *kh, struct kroute_node *kn)
492 {
493 	struct kroute	*kr;
494 
495 	/* was the route redistributed? */
496 	if ((kn->r.flags & F_REDISTRIBUTED) == 0)
497 		return;
498 
499 	/* remove redistributed flag */
500 	kn->r.flags &= ~F_REDISTRIBUTED;
501 	kr = &kn->r;
502 
503 	/* probably inform the RDE (check if no other path is redistributed) */
504 	for (kn = kh; kn; kn = kn->next)
505 		if (kn->r.flags & F_REDISTRIBUTED)
506 			break;
507 
508 	if (kn == NULL)
509 		main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, kr,
510 		    sizeof(struct kroute));
511 }
512 
513 int
514 kr_redist_eval(struct kroute *kr, struct kroute *new_kr)
515 {
516 	u_int32_t	 a, metric = 0;
517 
518 	/* Only non-ospfd routes are considered for redistribution. */
519 	if (!(kr->flags & F_KERNEL))
520 		goto dont_redistribute;
521 
522 	/* Dynamic routes are not redistributable. */
523 	if (kr->flags & F_DYNAMIC)
524 		goto dont_redistribute;
525 
526 	/* interface is not up and running so don't announce */
527 	if (kr->flags & F_DOWN)
528 		goto dont_redistribute;
529 
530 	/*
531 	 * We consider the loopback net, multicast and experimental addresses
532 	 * as not redistributable.
533 	 */
534 	a = ntohl(kr->prefix.s_addr);
535 	if (IN_MULTICAST(a) || IN_BADCLASS(a) ||
536 	    (a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
537 		goto dont_redistribute;
538 	/*
539 	 * Consider networks with nexthop loopback as not redistributable
540 	 * unless it is a reject or blackhole route.
541 	 */
542 	if (kr->nexthop.s_addr == htonl(INADDR_LOOPBACK) &&
543 	    !(kr->flags & (F_BLACKHOLE|F_REJECT)))
544 		goto dont_redistribute;
545 
546 	/* Should we redistribute this route? */
547 	if (!ospf_redistribute(kr, &metric))
548 		goto dont_redistribute;
549 
550 	/* prefix should be redistributed */
551 	kr->flags |= F_REDISTRIBUTED;
552 	/*
553 	 * only one of all multipath routes can be redistributed so
554 	 * redistribute the best one.
555 	 */
556 	if (new_kr->metric > metric) {
557 		*new_kr = *kr;
558 		new_kr->metric = metric;
559 	}
560 
561 	return (1);
562 
563 dont_redistribute:
564 	/* was the route redistributed? */
565 	if ((kr->flags & F_REDISTRIBUTED) == 0)
566 		return (0);
567 
568 	kr->flags &= ~F_REDISTRIBUTED;
569 	return (1);
570 }
571 
572 void
573 kr_redistribute(struct kroute_node *kh)
574 {
575 	struct kroute_node	*kn;
576 	struct kroute		 kr;
577 	int			 redistribute = 0;
578 
579 	/* only the highest prio route can be redistributed */
580 	if (kroute_find(kh->r.prefix.s_addr, kh->r.prefixlen, RTP_ANY) != kh)
581 		return;
582 
583 	bzero(&kr, sizeof(kr));
584 	kr.metric = UINT_MAX;
585 	for (kn = kh; kn; kn = kn->next)
586 		if (kr_redist_eval(&kn->r, &kr))
587 			redistribute = 1;
588 
589 	if (!redistribute)
590 		return;
591 
592 	if (kr.flags & F_REDISTRIBUTED) {
593 		main_imsg_compose_rde(IMSG_NETWORK_ADD, 0, &kr,
594 		    sizeof(struct kroute));
595 	} else {
596 		kr = kh->r;
597 		main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, &kr,
598 		    sizeof(struct kroute));
599 	}
600 }
601 
602 void
603 kr_reload(void)
604 {
605 	struct kroute_node	*kr, *kn;
606 	u_int32_t		 dummy;
607 	int			 r;
608 
609 	RB_FOREACH(kr, kroute_tree, &krt) {
610 		for (kn = kr; kn; kn = kn->next) {
611 			r = ospf_redistribute(&kn->r, &dummy);
612 			/*
613 			 * if it is redistributed, redistribute again metric
614 			 * may have changed.
615 			 */
616 			if ((kn->r.flags & F_REDISTRIBUTED && !r) || r)
617 				break;
618 		}
619 		if (kn) {
620 			/*
621 			 * kr_redistribute copes with removes and RDE with
622 			 * duplicates
623 			 */
624 			kr_redistribute(kr);
625 		}
626 	}
627 }
628 
629 /* rb-tree compare */
630 int
631 kroute_compare(struct kroute_node *a, struct kroute_node *b)
632 {
633 	if (ntohl(a->r.prefix.s_addr) < ntohl(b->r.prefix.s_addr))
634 		return (-1);
635 	if (ntohl(a->r.prefix.s_addr) > ntohl(b->r.prefix.s_addr))
636 		return (1);
637 	if (a->r.prefixlen < b->r.prefixlen)
638 		return (-1);
639 	if (a->r.prefixlen > b->r.prefixlen)
640 		return (1);
641 
642 	/* if the priority is RTP_ANY finish on the first address hit */
643 	if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY)
644 		return (0);
645 	if (a->r.priority < b->r.priority)
646 		return (-1);
647 	if (a->r.priority > b->r.priority)
648 		return (1);
649 	return (0);
650 }
651 
652 int
653 kif_compare(struct kif_node *a, struct kif_node *b)
654 {
655 	return (b->k.ifindex - a->k.ifindex);
656 }
657 
658 /* tree management */
659 struct kroute_node *
660 kroute_find(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio)
661 {
662 	struct kroute_node	s;
663 	struct kroute_node	*kn, *tmp;
664 
665 	s.r.prefix.s_addr = prefix;
666 	s.r.prefixlen = prefixlen;
667 	s.r.priority = prio;
668 
669 	kn = RB_FIND(kroute_tree, &krt, &s);
670 	if (kn && prio == RTP_ANY) {
671 		tmp = RB_PREV(kroute_tree, &krt, kn);
672 		while (tmp) {
673 			if (kroute_compare(&s, tmp) == 0)
674 				kn = tmp;
675 			else
676 				break;
677 			tmp = RB_PREV(kroute_tree, &krt, kn);
678 		}
679 	}
680 	return (kn);
681 }
682 
683 struct kroute_node *
684 kroute_matchgw(struct kroute_node *kr, struct in_addr nh)
685 {
686 	in_addr_t	nexthop;
687 
688 	nexthop = nh.s_addr;
689 
690 	while (kr) {
691 		if (kr->r.nexthop.s_addr == nexthop)
692 			return (kr);
693 		kr = kr->next;
694 	}
695 
696 	return (NULL);
697 }
698 
699 int
700 kroute_insert(struct kroute_node *kr)
701 {
702 	struct kroute_node	*krm, *krh;
703 
704 	kr->serial = kr_state.fib_serial;
705 
706 	if ((krh = RB_INSERT(kroute_tree, &krt, kr)) != NULL) {
707 		/*
708 		 * Multipath route, add at end of list.
709 		 */
710 		krm = krh;
711 		while (krm->next != NULL)
712 			krm = krm->next;
713 		krm->next = kr;
714 		kr->next = NULL; /* to be sure */
715 	} else
716 		krh = kr;
717 
718 	if (!(kr->r.flags & F_KERNEL)) {
719 		/* don't validate or redistribute ospf route */
720 		kr->r.flags &= ~F_DOWN;
721 		return (0);
722 	}
723 
724 	if (kif_validate(kr->r.ifindex))
725 		kr->r.flags &= ~F_DOWN;
726 	else
727 		kr->r.flags |= F_DOWN;
728 
729 	kr_redistribute(krh);
730 	return (0);
731 }
732 
733 int
734 kroute_remove(struct kroute_node *kr)
735 {
736 	struct kroute_node	*krm;
737 
738 	if ((krm = RB_FIND(kroute_tree, &krt, kr)) == NULL) {
739 		log_warnx("kroute_remove failed to find %s/%u",
740 		    inet_ntoa(kr->r.prefix), kr->r.prefixlen);
741 		return (-1);
742 	}
743 
744 	if (krm == kr) {
745 		/* head element */
746 		if (RB_REMOVE(kroute_tree, &krt, kr) == NULL) {
747 			log_warnx("kroute_remove failed for %s/%u",
748 			    inet_ntoa(kr->r.prefix), kr->r.prefixlen);
749 			return (-1);
750 		}
751 		if (kr->next != NULL) {
752 			if (RB_INSERT(kroute_tree, &krt, kr->next) != NULL) {
753 				log_warnx("kroute_remove failed to add %s/%u",
754 				    inet_ntoa(kr->r.prefix), kr->r.prefixlen);
755 				return (-1);
756 			}
757 		}
758 	} else {
759 		/* somewhere in the list */
760 		while (krm->next != kr && krm->next != NULL)
761 			krm = krm->next;
762 		if (krm->next == NULL) {
763 			log_warnx("kroute_remove multipath list corrupted "
764 			    "for %s/%u", inet_ntoa(kr->r.prefix),
765 			    kr->r.prefixlen);
766 			return (-1);
767 		}
768 		krm->next = kr->next;
769 	}
770 
771 	kr_redist_remove(krm, kr);
772 	rtlabel_unref(kr->r.rtlabel);
773 
774 	free(kr);
775 	return (0);
776 }
777 
778 void
779 kroute_clear(void)
780 {
781 	struct kroute_node	*kr;
782 
783 	while ((kr = RB_MIN(kroute_tree, &krt)) != NULL)
784 		kroute_remove(kr);
785 }
786 
787 struct kif_node *
788 kif_find(u_short ifindex)
789 {
790 	struct kif_node	s;
791 
792 	bzero(&s, sizeof(s));
793 	s.k.ifindex = ifindex;
794 
795 	return (RB_FIND(kif_tree, &kit, &s));
796 }
797 
798 struct kif *
799 kif_findname(char *ifname, struct in_addr addr, struct kif_addr **kap)
800 {
801 	struct kif_node	*kif;
802 	struct kif_addr	*ka;
803 
804 	RB_FOREACH(kif, kif_tree, &kit)
805 		if (!strcmp(ifname, kif->k.ifname)) {
806 			ka = TAILQ_FIRST(&kif->addrs);
807 			if (addr.s_addr != 0) {
808 				TAILQ_FOREACH(ka, &kif->addrs, entry) {
809 					if (addr.s_addr == ka->addr.s_addr)
810 						break;
811 				}
812 			}
813 			if (kap != NULL)
814 				*kap = ka;
815 			return (&kif->k);
816 		}
817 
818 	return (NULL);
819 }
820 
821 struct kif_node *
822 kif_insert(u_short ifindex)
823 {
824 	struct kif_node	*kif;
825 
826 	if ((kif = calloc(1, sizeof(struct kif_node))) == NULL)
827 		return (NULL);
828 
829 	kif->k.ifindex = ifindex;
830 	TAILQ_INIT(&kif->addrs);
831 
832 	if (RB_INSERT(kif_tree, &kit, kif) != NULL)
833 		fatalx("kif_insert: RB_INSERT");
834 
835 	return (kif);
836 }
837 
838 int
839 kif_remove(struct kif_node *kif)
840 {
841 	struct kif_addr	*ka;
842 
843 	if (RB_REMOVE(kif_tree, &kit, kif) == NULL) {
844 		log_warnx("RB_REMOVE(kif_tree, &kit, kif)");
845 		return (-1);
846 	}
847 
848 	while ((ka = TAILQ_FIRST(&kif->addrs)) != NULL) {
849 		TAILQ_REMOVE(&kif->addrs, ka, entry);
850 		free(ka);
851 	}
852 	free(kif);
853 	return (0);
854 }
855 
856 void
857 kif_clear(void)
858 {
859 	struct kif_node	*kif;
860 
861 	while ((kif = RB_MIN(kif_tree, &kit)) != NULL)
862 		kif_remove(kif);
863 }
864 
865 struct kif *
866 kif_update(u_short ifindex, int flags, struct if_data *ifd,
867     struct sockaddr_dl *sdl)
868 {
869 	struct kif_node		*kif;
870 
871 	if ((kif = kif_find(ifindex)) == NULL) {
872 		if ((kif = kif_insert(ifindex)) == NULL)
873 			return (NULL);
874 		kif->k.nh_reachable = (flags & IFF_UP) &&
875 		    LINK_STATE_IS_UP(ifd->ifi_link_state);
876 	}
877 
878 	kif->k.flags = flags;
879 	kif->k.link_state = ifd->ifi_link_state;
880 	kif->k.if_type = ifd->ifi_type;
881 	kif->k.baudrate = ifd->ifi_baudrate;
882 	kif->k.mtu = ifd->ifi_mtu;
883 	kif->k.rdomain = ifd->ifi_rdomain;
884 
885 	if (sdl && sdl->sdl_family == AF_LINK) {
886 		if (sdl->sdl_nlen >= sizeof(kif->k.ifname))
887 			memcpy(kif->k.ifname, sdl->sdl_data,
888 			    sizeof(kif->k.ifname) - 1);
889 		else if (sdl->sdl_nlen > 0)
890 			memcpy(kif->k.ifname, sdl->sdl_data,
891 			    sdl->sdl_nlen);
892 		/* string already terminated via calloc() */
893 	}
894 
895 	return (&kif->k);
896 }
897 
898 int
899 kif_validate(u_short ifindex)
900 {
901 	struct kif_node		*kif;
902 
903 	if ((kif = kif_find(ifindex)) == NULL) {
904 		log_warnx("interface with index %u not found", ifindex);
905 		return (1);
906 	}
907 
908 	return (kif->k.nh_reachable);
909 }
910 
911 struct kroute_node *
912 kroute_match(in_addr_t key)
913 {
914 	int			 i;
915 	struct kroute_node	*kr;
916 
917 	/* we will never match the default route */
918 	for (i = 32; i > 0; i--)
919 		if ((kr = kroute_find(key & prefixlen2mask(i), i,
920 		    RTP_ANY)) != NULL)
921 			return (kr);
922 
923 	/* if we don't have a match yet, try to find a default route */
924 	if ((kr = kroute_find(0, 0, RTP_ANY)) != NULL)
925 			return (kr);
926 
927 	return (NULL);
928 }
929 
930 /* misc */
931 int
932 protect_lo(void)
933 {
934 	struct kroute_node	*kr;
935 
936 	/* special protection for 127/8 */
937 	if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
938 		log_warn("protect_lo");
939 		return (-1);
940 	}
941 	kr->r.prefix.s_addr = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
942 	kr->r.prefixlen = 8;
943 	kr->r.flags = F_KERNEL|F_CONNECTED;
944 
945 	if (RB_INSERT(kroute_tree, &krt, kr) != NULL)
946 		free(kr);	/* kernel route already there, no problem */
947 
948 	return (0);
949 }
950 
951 u_int8_t
952 prefixlen_classful(in_addr_t ina)
953 {
954 	/* it hurt to write this. */
955 
956 	if (ina >= 0xf0000000U)		/* class E */
957 		return (32);
958 	else if (ina >= 0xe0000000U)	/* class D */
959 		return (4);
960 	else if (ina >= 0xc0000000U)	/* class C */
961 		return (24);
962 	else if (ina >= 0x80000000U)	/* class B */
963 		return (16);
964 	else				/* class A */
965 		return (8);
966 }
967 
968 u_int8_t
969 mask2prefixlen(in_addr_t ina)
970 {
971 	if (ina == 0)
972 		return (0);
973 	else
974 		return (33 - ffs(ntohl(ina)));
975 }
976 
977 in_addr_t
978 prefixlen2mask(u_int8_t prefixlen)
979 {
980 	if (prefixlen == 0)
981 		return (0);
982 
983 	return (htonl(0xffffffff << (32 - prefixlen)));
984 }
985 
986 #define ROUNDUP(a) \
987 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
988 
989 void
990 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
991 {
992 	int	i;
993 
994 	for (i = 0; i < RTAX_MAX; i++) {
995 		if (addrs & (1 << i)) {
996 			rti_info[i] = sa;
997 			sa = (struct sockaddr *)((char *)(sa) +
998 			    ROUNDUP(sa->sa_len));
999 		} else
1000 			rti_info[i] = NULL;
1001 	}
1002 }
1003 
1004 void
1005 if_change(u_short ifindex, int flags, struct if_data *ifd,
1006     struct sockaddr_dl *sdl)
1007 {
1008 	struct kroute_node	*kr, *tkr;
1009 	struct kif		*kif;
1010 	u_int8_t		 reachable;
1011 
1012 	if ((kif = kif_update(ifindex, flags, ifd, sdl)) == NULL) {
1013 		log_warn("if_change:  kif_update(%u)", ifindex);
1014 		return;
1015 	}
1016 
1017 	/* notify ospfe about interface link state */
1018 	main_imsg_compose_ospfe(IMSG_IFINFO, 0, kif, sizeof(struct kif));
1019 
1020 	reachable = (kif->flags & IFF_UP) &&
1021 	    LINK_STATE_IS_UP(kif->link_state);
1022 
1023 	if (reachable == kif->nh_reachable)
1024 		return;		/* nothing changed wrt nexthop validity */
1025 
1026 	kif->nh_reachable = reachable;
1027 
1028 	/* update redistribute list */
1029 	RB_FOREACH(kr, kroute_tree, &krt) {
1030 		for (tkr = kr; tkr != NULL; tkr = tkr->next) {
1031 			if (tkr->r.ifindex == ifindex) {
1032 				if (reachable)
1033 					tkr->r.flags &= ~F_DOWN;
1034 				else
1035 					tkr->r.flags |= F_DOWN;
1036 
1037 			}
1038 		}
1039 		kr_redistribute(kr);
1040 	}
1041 }
1042 
1043 void
1044 if_newaddr(u_short ifindex, struct sockaddr_in *ifa, struct sockaddr_in *mask,
1045     struct sockaddr_in *brd)
1046 {
1047 	struct kif_node *kif;
1048 	struct kif_addr *ka;
1049 
1050 	if (ifa == NULL || ifa->sin_family != AF_INET)
1051 		return;
1052 	if ((kif = kif_find(ifindex)) == NULL) {
1053 		log_warnx("if_newaddr: corresponding if %d not found", ifindex);
1054 		return;
1055 	}
1056 	if ((ka = calloc(1, sizeof(struct kif_addr))) == NULL)
1057 		fatal("if_newaddr");
1058 	ka->addr = ifa->sin_addr;
1059 	if (mask)
1060 		ka->mask = mask->sin_addr;
1061 	else
1062 		ka->mask.s_addr = INADDR_NONE;
1063 	if (brd)
1064 		ka->dstbrd = brd->sin_addr;
1065 	else
1066 		ka->dstbrd.s_addr = INADDR_NONE;
1067 
1068 	TAILQ_INSERT_TAIL(&kif->addrs, ka, entry);
1069 }
1070 
1071 void
1072 if_deladdr(u_short ifindex, struct sockaddr_in *ifa, struct sockaddr_in *mask,
1073     struct sockaddr_in *brd)
1074 {
1075 	struct kif_node *kif;
1076 	struct kif_addr *ka, *nka;
1077 	struct ifaddrdel ifc;
1078 
1079 	if (ifa == NULL || ifa->sin_family != AF_INET)
1080 		return;
1081 	if ((kif = kif_find(ifindex)) == NULL) {
1082 		log_warnx("if_deladdr: corresponding if %d not found", ifindex);
1083 		return;
1084 	}
1085 
1086 	for (ka = TAILQ_FIRST(&kif->addrs); ka != NULL; ka = nka) {
1087 		nka = TAILQ_NEXT(ka, entry);
1088 
1089 		if (ka->addr.s_addr == ifa->sin_addr.s_addr) {
1090 			TAILQ_REMOVE(&kif->addrs, ka, entry);
1091 			ifc.addr = ifa->sin_addr;
1092 			ifc.ifindex = ifindex;
1093 			main_imsg_compose_ospfe(IMSG_IFADDRDEL, 0, &ifc,
1094 			    sizeof(ifc));
1095 			free(ka);
1096 			return;
1097 		}
1098 	}
1099 }
1100 
1101 void
1102 if_announce(void *msg)
1103 {
1104 	struct if_announcemsghdr	*ifan;
1105 	struct kif_node			*kif;
1106 
1107 	ifan = msg;
1108 
1109 	switch (ifan->ifan_what) {
1110 	case IFAN_ARRIVAL:
1111 		kif = kif_insert(ifan->ifan_index);
1112 		strlcpy(kif->k.ifname, ifan->ifan_name, sizeof(kif->k.ifname));
1113 		break;
1114 	case IFAN_DEPARTURE:
1115 		kif = kif_find(ifan->ifan_index);
1116 		kif_remove(kif);
1117 		break;
1118 	}
1119 }
1120 
1121 /* rtsock */
1122 int
1123 send_rtmsg(int fd, int action, struct kroute *kroute)
1124 {
1125 	struct iovec		iov[5];
1126 	struct rt_msghdr	hdr;
1127 	struct sockaddr_in	prefix;
1128 	struct sockaddr_in	nexthop;
1129 	struct sockaddr_in	mask;
1130 	struct sockaddr_rtlabel	sa_rl;
1131 	int			iovcnt = 0;
1132 	const char		*label;
1133 
1134 	if (kr_state.fib_sync == 0)
1135 		return (0);
1136 
1137 	/* initialize header */
1138 	bzero(&hdr, sizeof(hdr));
1139 	hdr.rtm_version = RTM_VERSION;
1140 	hdr.rtm_type = action;
1141 	hdr.rtm_priority = RTP_OSPF;
1142 	hdr.rtm_tableid = kr_state.rdomain;	/* rtableid */
1143 	if (action == RTM_CHANGE)
1144 		hdr.rtm_fmask = RTF_REJECT|RTF_BLACKHOLE;
1145 	else
1146 		hdr.rtm_flags = RTF_MPATH;
1147 	hdr.rtm_seq = kr_state.rtseq++;	/* overflow doesn't matter */
1148 	hdr.rtm_msglen = sizeof(hdr);
1149 	/* adjust iovec */
1150 	iov[iovcnt].iov_base = &hdr;
1151 	iov[iovcnt++].iov_len = sizeof(hdr);
1152 
1153 	bzero(&prefix, sizeof(prefix));
1154 	prefix.sin_len = sizeof(prefix);
1155 	prefix.sin_family = AF_INET;
1156 	prefix.sin_addr.s_addr = kroute->prefix.s_addr;
1157 	/* adjust header */
1158 	hdr.rtm_addrs |= RTA_DST;
1159 	hdr.rtm_msglen += sizeof(prefix);
1160 	/* adjust iovec */
1161 	iov[iovcnt].iov_base = &prefix;
1162 	iov[iovcnt++].iov_len = sizeof(prefix);
1163 
1164 	if (kroute->nexthop.s_addr != 0) {
1165 		bzero(&nexthop, sizeof(nexthop));
1166 		nexthop.sin_len = sizeof(nexthop);
1167 		nexthop.sin_family = AF_INET;
1168 		nexthop.sin_addr.s_addr = kroute->nexthop.s_addr;
1169 		/* adjust header */
1170 		hdr.rtm_flags |= RTF_GATEWAY;
1171 		hdr.rtm_addrs |= RTA_GATEWAY;
1172 		hdr.rtm_msglen += sizeof(nexthop);
1173 		/* adjust iovec */
1174 		iov[iovcnt].iov_base = &nexthop;
1175 		iov[iovcnt++].iov_len = sizeof(nexthop);
1176 	}
1177 
1178 	bzero(&mask, sizeof(mask));
1179 	mask.sin_len = sizeof(mask);
1180 	mask.sin_family = AF_INET;
1181 	mask.sin_addr.s_addr = prefixlen2mask(kroute->prefixlen);
1182 	/* adjust header */
1183 	hdr.rtm_addrs |= RTA_NETMASK;
1184 	hdr.rtm_msglen += sizeof(mask);
1185 	/* adjust iovec */
1186 	iov[iovcnt].iov_base = &mask;
1187 	iov[iovcnt++].iov_len = sizeof(mask);
1188 
1189 	if (kroute->rtlabel != 0) {
1190 		sa_rl.sr_len = sizeof(sa_rl);
1191 		sa_rl.sr_family = AF_UNSPEC;
1192 		label = rtlabel_id2name(kroute->rtlabel);
1193 		if (strlcpy(sa_rl.sr_label, label,
1194 		    sizeof(sa_rl.sr_label)) >= sizeof(sa_rl.sr_label)) {
1195 			log_warnx("send_rtmsg: invalid rtlabel");
1196 			return (-1);
1197 		}
1198 		/* adjust header */
1199 		hdr.rtm_addrs |= RTA_LABEL;
1200 		hdr.rtm_msglen += sizeof(sa_rl);
1201 		/* adjust iovec */
1202 		iov[iovcnt].iov_base = &sa_rl;
1203 		iov[iovcnt++].iov_len = sizeof(sa_rl);
1204 	}
1205 
1206 retry:
1207 	if (writev(fd, iov, iovcnt) == -1) {
1208 		if (errno == ESRCH) {
1209 			if (hdr.rtm_type == RTM_CHANGE) {
1210 				hdr.rtm_type = RTM_ADD;
1211 				goto retry;
1212 			} else if (hdr.rtm_type == RTM_DELETE) {
1213 				log_info("route %s/%u vanished before delete",
1214 				    inet_ntoa(kroute->prefix),
1215 				    kroute->prefixlen);
1216 				return (0);
1217 			}
1218 		}
1219 		log_warn("send_rtmsg: action %u, prefix %s/%u", hdr.rtm_type,
1220 		    inet_ntoa(kroute->prefix), kroute->prefixlen);
1221 		return (0);
1222 	}
1223 
1224 	return (0);
1225 }
1226 
1227 int
1228 fetchtable(void)
1229 {
1230 	size_t			 len;
1231 	int			 mib[7];
1232 	char			*buf;
1233 	int			 rv;
1234 
1235 	mib[0] = CTL_NET;
1236 	mib[1] = PF_ROUTE;
1237 	mib[2] = 0;
1238 	mib[3] = AF_INET;
1239 	mib[4] = NET_RT_DUMP;
1240 	mib[5] = 0;
1241 	mib[6] = kr_state.rdomain;	/* rtableid */
1242 
1243 	if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
1244 		log_warn("sysctl");
1245 		return (-1);
1246 	}
1247 	if ((buf = malloc(len)) == NULL) {
1248 		log_warn("fetchtable");
1249 		return (-1);
1250 	}
1251 	if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
1252 		log_warn("sysctl");
1253 		free(buf);
1254 		return (-1);
1255 	}
1256 
1257 	rv = rtmsg_process(buf, len);
1258 	free(buf);
1259 
1260 	return (rv);
1261 }
1262 
1263 int
1264 fetchifs(u_short ifindex)
1265 {
1266 	size_t			 len;
1267 	int			 mib[6];
1268 	char			*buf;
1269 	int			 rv;
1270 
1271 	mib[0] = CTL_NET;
1272 	mib[1] = PF_ROUTE;
1273 	mib[2] = 0;
1274 	mib[3] = AF_INET;
1275 	mib[4] = NET_RT_IFLIST;
1276 	mib[5] = ifindex;
1277 
1278 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
1279 		log_warn("sysctl");
1280 		return (-1);
1281 	}
1282 	if ((buf = malloc(len)) == NULL) {
1283 		log_warn("fetchif");
1284 		return (-1);
1285 	}
1286 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) {
1287 		log_warn("sysctl");
1288 		free(buf);
1289 		return (-1);
1290 	}
1291 
1292 	rv = rtmsg_process(buf, len);
1293 	free(buf);
1294 
1295 	return (rv);
1296 }
1297 
1298 int
1299 dispatch_rtmsg(void)
1300 {
1301 	char			 buf[RT_BUF_SIZE];
1302 	ssize_t			 n;
1303 
1304 	if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) {
1305 		if (errno == EAGAIN || errno == EINTR)
1306 			return (0);
1307 		log_warn("dispatch_rtmsg: read error");
1308 		return (-1);
1309 	}
1310 
1311 	if (n == 0) {
1312 		log_warnx("routing socket closed");
1313 		return (-1);
1314 	}
1315 
1316 	return (rtmsg_process(buf, n));
1317 }
1318 
1319 int
1320 rtmsg_process(char *buf, size_t len)
1321 {
1322 	struct rt_msghdr	*rtm;
1323 	struct if_msghdr	 ifm;
1324 	struct ifa_msghdr	*ifam;
1325 	struct sockaddr		*sa, *rti_info[RTAX_MAX];
1326 	struct sockaddr_in	*sa_in;
1327 	struct sockaddr_rtlabel	*label;
1328 	struct kroute_node	*kr, *okr;
1329 	struct in_addr		 prefix, nexthop;
1330 	u_int8_t		 prefixlen, prio;
1331 	int			 flags, mpath;
1332 	u_short			 ifindex = 0;
1333 	int			 rv, delay;
1334 
1335 	size_t			 offset;
1336 	char			*next;
1337 
1338 	for (offset = 0; offset < len; offset += rtm->rtm_msglen) {
1339 		next = buf + offset;
1340 		rtm = (struct rt_msghdr *)next;
1341 		if (len < offset + sizeof(u_short) ||
1342 		    len < offset + rtm->rtm_msglen)
1343 			fatalx("rtmsg_process: partial rtm in buffer");
1344 		if (rtm->rtm_version != RTM_VERSION)
1345 			continue;
1346 
1347 		prefix.s_addr = 0;
1348 		prefixlen = 0;
1349 		nexthop.s_addr = 0;
1350 		mpath = 0;
1351 		prio = 0;
1352 		flags = F_KERNEL;
1353 
1354 		sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
1355 		get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1356 
1357 		switch (rtm->rtm_type) {
1358 		case RTM_ADD:
1359 		case RTM_GET:
1360 		case RTM_CHANGE:
1361 		case RTM_DELETE:
1362 			if (rtm->rtm_errno)		/* failed attempts... */
1363 				continue;
1364 
1365 			if (rtm->rtm_tableid != kr_state.rdomain)
1366 				continue;
1367 
1368 			if (rtm->rtm_type == RTM_GET &&
1369 			    rtm->rtm_pid != kr_state.pid)
1370 				continue;
1371 
1372 			if ((sa = rti_info[RTAX_DST]) == NULL)
1373 				continue;
1374 
1375 			/* Skip ARP/ND cache and broadcast routes. */
1376 			if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST))
1377 				continue;
1378 
1379 			if (rtm->rtm_flags & RTF_MPATH)
1380 				mpath = 1;
1381 			prio = rtm->rtm_priority;
1382 			flags = (prio == RTP_OSPF) ?
1383 			    F_OSPFD_INSERTED : F_KERNEL;
1384 
1385 			switch (sa->sa_family) {
1386 			case AF_INET:
1387 				prefix.s_addr =
1388 				    ((struct sockaddr_in *)sa)->sin_addr.s_addr;
1389 				sa_in = (struct sockaddr_in *)
1390 				    rti_info[RTAX_NETMASK];
1391 				if (sa_in != NULL) {
1392 					if (sa_in->sin_len != 0)
1393 						prefixlen = mask2prefixlen(
1394 						    sa_in->sin_addr.s_addr);
1395 				} else if (rtm->rtm_flags & RTF_HOST)
1396 					prefixlen = 32;
1397 				else
1398 					prefixlen =
1399 					    prefixlen_classful(prefix.s_addr);
1400 				if (rtm->rtm_flags & RTF_STATIC)
1401 					flags |= F_STATIC;
1402 				if (rtm->rtm_flags & RTF_BLACKHOLE)
1403 					flags |= F_BLACKHOLE;
1404 				if (rtm->rtm_flags & RTF_REJECT)
1405 					flags |= F_REJECT;
1406 				if (rtm->rtm_flags & RTF_DYNAMIC)
1407 					flags |= F_DYNAMIC;
1408 				break;
1409 			default:
1410 				continue;
1411 			}
1412 
1413 			ifindex = rtm->rtm_index;
1414 			if ((sa = rti_info[RTAX_GATEWAY]) != NULL) {
1415 				switch (sa->sa_family) {
1416 				case AF_INET:
1417 					if (rtm->rtm_flags & RTF_CONNECTED) {
1418 						flags |= F_CONNECTED;
1419 						break;
1420 					}
1421 
1422 					nexthop.s_addr = ((struct
1423 					    sockaddr_in *)sa)->sin_addr.s_addr;
1424 					break;
1425 				case AF_LINK:
1426 					/*
1427 					 * Traditional BSD connected routes have
1428 					 * a gateway of type AF_LINK.
1429 					 */
1430 					flags |= F_CONNECTED;
1431 					break;
1432 				}
1433 			}
1434 		}
1435 
1436 		switch (rtm->rtm_type) {
1437 		case RTM_ADD:
1438 		case RTM_GET:
1439 		case RTM_CHANGE:
1440 			if (nexthop.s_addr == 0 && !(flags & F_CONNECTED)) {
1441 				log_warnx("no nexthop for %s/%u",
1442 				    inet_ntoa(prefix), prefixlen);
1443 				continue;
1444 			}
1445 
1446 			if ((okr = kroute_find(prefix.s_addr, prefixlen, prio))
1447 			    != NULL) {
1448 				/* get the correct route */
1449 				kr = okr;
1450 				if ((mpath || prio == RTP_OSPF) &&
1451 				    (kr = kroute_matchgw(okr, nexthop)) ==
1452 				    NULL) {
1453 					log_warnx("dispatch_rtmsg "
1454 					    "mpath route not found");
1455 					/* add routes we missed out earlier */
1456 					goto add;
1457 				}
1458 
1459 				if (kr->r.flags & F_REDISTRIBUTED)
1460 					flags |= F_REDISTRIBUTED;
1461 				kr->r.nexthop.s_addr = nexthop.s_addr;
1462 				kr->r.flags = flags;
1463 				kr->r.ifindex = ifindex;
1464 
1465 				rtlabel_unref(kr->r.rtlabel);
1466 				kr->r.rtlabel = 0;
1467 				kr->r.ext_tag = 0;
1468 				if ((label = (struct sockaddr_rtlabel *)
1469 				    rti_info[RTAX_LABEL]) != NULL) {
1470 					kr->r.rtlabel =
1471 					    rtlabel_name2id(label->sr_label);
1472 					kr->r.ext_tag =
1473 					    rtlabel_id2tag(kr->r.rtlabel);
1474 				}
1475 
1476 				if (kif_validate(kr->r.ifindex))
1477 					kr->r.flags &= ~F_DOWN;
1478 				else
1479 					kr->r.flags |= F_DOWN;
1480 
1481 				/* just readd, the RDE will care */
1482 				kr->serial = kr_state.fib_serial;
1483 				kr_redistribute(okr);
1484 			} else {
1485 add:
1486 				if ((kr = calloc(1,
1487 				    sizeof(struct kroute_node))) == NULL) {
1488 					log_warn("dispatch calloc");
1489 					return (-1);
1490 				}
1491 
1492 				kr->r.prefix.s_addr = prefix.s_addr;
1493 				kr->r.prefixlen = prefixlen;
1494 				kr->r.nexthop.s_addr = nexthop.s_addr;
1495 				kr->r.flags = flags;
1496 				kr->r.ifindex = ifindex;
1497 				kr->r.priority = prio;
1498 
1499 				if (rtm->rtm_priority == RTP_OSPF) {
1500 					log_warnx("alien OSPF route %s/%d",
1501 					    inet_ntoa(prefix), prefixlen);
1502 					rv = send_rtmsg(kr_state.fd,
1503 					    RTM_DELETE, &kr->r);
1504 					free(kr);
1505 					if (rv == -1)
1506 						return (-1);
1507 				} else {
1508 					if ((label = (struct sockaddr_rtlabel *)
1509 					    rti_info[RTAX_LABEL]) != NULL) {
1510 						kr->r.rtlabel =
1511 						    rtlabel_name2id(
1512 						    label->sr_label);
1513 						kr->r.ext_tag =
1514 						    rtlabel_id2tag(
1515 						    kr->r.rtlabel);
1516 					}
1517 
1518 					kroute_insert(kr);
1519 				}
1520 			}
1521 			break;
1522 		case RTM_DELETE:
1523 			if ((kr = kroute_find(prefix.s_addr, prefixlen, prio))
1524 			    == NULL)
1525 				continue;
1526 			if (!(kr->r.flags & F_KERNEL))
1527 				continue;
1528 			/* get the correct route */
1529 			okr = kr;
1530 			if (mpath &&
1531 			    (kr = kroute_matchgw(kr, nexthop)) == NULL) {
1532 				log_warnx("dispatch_rtmsg "
1533 				    "mpath route not found");
1534 				return (-1);
1535 			}
1536 			if (kroute_remove(kr) == -1)
1537 				return (-1);
1538 			break;
1539 		case RTM_IFINFO:
1540 			memcpy(&ifm, next, sizeof(ifm));
1541 			if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data,
1542 			    (struct sockaddr_dl *)rti_info[RTAX_IFP]);
1543 			break;
1544 		case RTM_NEWADDR:
1545 			ifam = (struct ifa_msghdr *)rtm;
1546 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
1547 			    RTA_BRD)) == 0)
1548 				break;
1549 
1550 			if_newaddr(ifam->ifam_index,
1551 			    (struct sockaddr_in *)rti_info[RTAX_IFA],
1552 			    (struct sockaddr_in *)rti_info[RTAX_NETMASK],
1553 			    (struct sockaddr_in *)rti_info[RTAX_BRD]);
1554 			break;
1555 		case RTM_DELADDR:
1556 			ifam = (struct ifa_msghdr *)rtm;
1557 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
1558 			    RTA_BRD)) == 0)
1559 				break;
1560 
1561 			if_deladdr(ifam->ifam_index,
1562 			    (struct sockaddr_in *)rti_info[RTAX_IFA],
1563 			    (struct sockaddr_in *)rti_info[RTAX_NETMASK],
1564 			    (struct sockaddr_in *)rti_info[RTAX_BRD]);
1565 			break;
1566 		case RTM_IFANNOUNCE:
1567 			if_announce(next);
1568 			break;
1569 		case RTM_DESYNC:
1570 			/*
1571 			 * We lost some routing packets. Schedule a reload
1572 			 * of the kernel route/interface information.
1573 			 */
1574 			if (kr_state.reload_state == KR_RELOAD_IDLE) {
1575 				delay = KR_RELOAD_TIMER;
1576 				log_info("desync; scheduling fib reload");
1577 			} else {
1578 				delay = KR_RELOAD_HOLD_TIMER;
1579 				log_debug("desync during KR_RELOAD_%s",
1580 				    kr_state.reload_state ==
1581 				    KR_RELOAD_FETCH ? "FETCH" : "HOLD");
1582 			}
1583 			kr_state.reload_state = KR_RELOAD_FETCH;
1584 			kr_fib_reload_arm_timer(delay);
1585 			break;
1586 		default:
1587 			/* ignore for now */
1588 			break;
1589 		}
1590 	}
1591 
1592 	return (offset);
1593 }
1594