xref: /openbsd-src/usr.sbin/ospf6d/kroute.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: kroute.c,v 1.11 2009/04/09 19:03:10 stsp 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/param.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/sysctl.h>
24 #include <sys/tree.h>
25 #include <sys/uio.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <net/if.h>
29 #include <net/if_dl.h>
30 #include <net/if_types.h>
31 #include <net/route.h>
32 #include <err.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 
40 #include "ospf6d.h"
41 #include "ospfe.h"
42 #include "log.h"
43 
44 struct {
45 	u_int32_t		rtseq;
46 	pid_t			pid;
47 	int			fib_sync;
48 	int			fd;
49 	struct event		ev;
50 } kr_state;
51 
52 struct kroute_node {
53 	RB_ENTRY(kroute_node)	 entry;
54 	struct kroute		 r;
55 	struct kroute_node	*next;
56 };
57 
58 void	kr_redist_remove(struct kroute_node *, struct kroute_node *);
59 int	kr_redist_eval(struct kroute *, struct rroute *);
60 void	kr_redistribute(struct kroute_node *);
61 int	kroute_compare(struct kroute_node *, struct kroute_node *);
62 
63 struct kroute_node	*kroute_find(const struct in6_addr *, u_int8_t);
64 struct kroute_node	*kroute_matchgw(struct kroute_node *,
65 			    struct in6_addr *);
66 int			 kroute_insert(struct kroute_node *);
67 int			 kroute_remove(struct kroute_node *);
68 void			 kroute_clear(void);
69 
70 struct iface		*kif_update(u_short, int, struct if_data *,
71 			   struct sockaddr_dl *);
72 int			 kif_validate(u_short);
73 
74 struct kroute_node	*kroute_match(struct in6_addr *);
75 
76 int		protect_lo(void);
77 void		get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
78 void		if_change(u_short, int, struct if_data *);
79 void		if_newaddr(u_short, struct sockaddr_in6 *,
80 		    struct sockaddr_in6 *, struct sockaddr_in6 *);
81 void		if_announce(void *);
82 
83 int		send_rtmsg(int, int, struct kroute *);
84 int		dispatch_rtmsg(void);
85 int		fetchtable(void);
86 
87 RB_HEAD(kroute_tree, kroute_node)	krt;
88 RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare)
89 RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare)
90 
91 int
92 kr_init(int fs)
93 {
94 	int		opt = 0, rcvbuf, default_rcvbuf;
95 	socklen_t	optlen;
96 
97 	kr_state.fib_sync = fs;
98 
99 	if ((kr_state.fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
100 		log_warn("kr_init: socket");
101 		return (-1);
102 	}
103 
104 	/* not interested in my own messages */
105 	if (setsockopt(kr_state.fd, SOL_SOCKET, SO_USELOOPBACK,
106 	    &opt, sizeof(opt)) == -1)
107 		log_warn("kr_init: setsockopt");	/* not fatal */
108 
109 	/* grow receive buffer, don't wanna miss messages */
110 	optlen = sizeof(default_rcvbuf);
111 	if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
112 	    &default_rcvbuf, &optlen) == -1)
113 		log_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
114 	else
115 		for (rcvbuf = MAX_RTSOCK_BUF;
116 		    rcvbuf > default_rcvbuf &&
117 		    setsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
118 		    &rcvbuf, sizeof(rcvbuf)) == -1 && errno == ENOBUFS;
119 		    rcvbuf /= 2)
120 			;	/* nothing */
121 
122 	kr_state.pid = getpid();
123 	kr_state.rtseq = 1;
124 
125 	RB_INIT(&krt);
126 
127 	if (fetchtable() == -1)
128 		return (-1);
129 
130 	if (protect_lo() == -1)
131 		return (-1);
132 
133 	event_set(&kr_state.ev, kr_state.fd, EV_READ | EV_PERSIST,
134 	    kr_dispatch_msg, NULL);
135 	event_add(&kr_state.ev, NULL);
136 
137 	return (0);
138 }
139 
140 int
141 kr_change(struct kroute *kroute)
142 {
143 	struct kroute_node	*kr;
144 	int			 action = RTM_ADD;
145 
146 	kroute->rtlabel = rtlabel_tag2id(kroute->ext_tag);
147 
148 	if ((kr = kroute_find(&kroute->prefix, kroute->prefixlen)) !=
149 	    NULL) {
150 		if (!(kr->r.flags & F_KERNEL))
151 			action = RTM_CHANGE;
152 		else {	/* a non-ospf route already exists. not a problem */
153 			if (!(kr->r.flags & F_BGPD_INSERTED)) {
154 				do {
155 					kr->r.flags |= F_OSPFD_INSERTED;
156 					kr = kr->next;
157 				} while (kr);
158 				return (0);
159 			}
160 			/*
161 			 * XXX as long as there is no multipath support in
162 			 * bgpd this is safe else we end up in a bad situation.
163 			 */
164 			/*
165 			 * ospf route has higher pref
166 			 * - reset flags to the ospf ones
167 			 * - use RTM_CHANGE
168 			 * - zero out ifindex (this is no longer relevant)
169 			 */
170 			action = RTM_CHANGE;
171 			kr->r.flags = kroute->flags | F_OSPFD_INSERTED;
172 			kr->r.ifindex = 0;
173 			rtlabel_unref(kr->r.rtlabel);
174 			kr->r.ext_tag = kroute->ext_tag;
175 			kr->r.rtlabel = kroute->rtlabel;
176 		}
177 	}
178 
179 	/* nexthop within 127/8 -> ignore silently */
180 	if (kr && IN6_IS_ADDR_LOOPBACK(&kr->r.nexthop))
181 		return (0);
182 
183 	/*
184 	 * Ingnore updates that did not change the route.
185 	 * Currently only the nexthop can change.
186 	 */
187 	if (kr && IN6_ARE_ADDR_EQUAL(&kr->r.nexthop, &kroute->nexthop))
188 		return (0);
189 
190 	if (send_rtmsg(kr_state.fd, action, kroute) == -1)
191 		return (-1);
192 
193 	if (action == RTM_ADD) {
194 		if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
195 			log_warn("kr_change");
196 			return (-1);
197 		}
198 		kr->r.prefix = kroute->prefix;
199 		kr->r.prefixlen = kroute->prefixlen;
200 		kr->r.nexthop = kroute->nexthop;
201 		kr->r.flags = kroute->flags | F_OSPFD_INSERTED;
202 		kr->r.ext_tag = kroute->ext_tag;
203 		kr->r.rtlabel = kroute->rtlabel;
204 
205 		if (kroute_insert(kr) == -1)
206 			free(kr);
207 	} else if (kr)
208 		kr->r.nexthop = kroute->nexthop;
209 
210 	return (0);
211 }
212 
213 int
214 kr_delete(struct kroute *kroute)
215 {
216 	struct kroute_node	*kr;
217 
218 	if ((kr = kroute_find(&kroute->prefix, kroute->prefixlen)) ==
219 	    NULL)
220 		return (0);
221 
222 	if (!(kr->r.flags & F_OSPFD_INSERTED))
223 		return (0);
224 
225 	if (kr->r.flags & F_KERNEL) {
226 		/* remove F_OSPFD_INSERTED flag, route still exists in kernel */
227 		do {
228 			kr->r.flags &= ~F_OSPFD_INSERTED;
229 			kr = kr->next;
230 		} while (kr);
231 		return (0);
232 	}
233 
234 	if (send_rtmsg(kr_state.fd, RTM_DELETE, kroute) == -1)
235 		return (-1);
236 
237 	if (kroute_remove(kr) == -1)
238 		return (-1);
239 
240 	return (0);
241 }
242 
243 void
244 kr_shutdown(void)
245 {
246 	kr_fib_decouple();
247 	kroute_clear();
248 }
249 
250 void
251 kr_fib_couple(void)
252 {
253 	struct kroute_node	*kr;
254 
255 	if (kr_state.fib_sync == 1)	/* already coupled */
256 		return;
257 
258 	kr_state.fib_sync = 1;
259 
260 	RB_FOREACH(kr, kroute_tree, &krt)
261 		if (!(kr->r.flags & F_KERNEL))
262 			send_rtmsg(kr_state.fd, RTM_ADD, &kr->r);
263 
264 	log_info("kernel routing table coupled");
265 }
266 
267 void
268 kr_fib_decouple(void)
269 {
270 	struct kroute_node	*kr;
271 
272 	if (kr_state.fib_sync == 0)	/* already decoupled */
273 		return;
274 
275 	RB_FOREACH(kr, kroute_tree, &krt)
276 		if (!(kr->r.flags & F_KERNEL))
277 			send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r);
278 
279 	kr_state.fib_sync = 0;
280 
281 	log_info("kernel routing table decoupled");
282 }
283 
284 /* ARGSUSED */
285 void
286 kr_dispatch_msg(int fd, short event, void *bula)
287 {
288 	dispatch_rtmsg();
289 }
290 
291 void
292 kr_show_route(struct imsg *imsg)
293 {
294 	struct kroute_node	*kr;
295 	struct kroute_node	*kn;
296 	int			 flags;
297 	struct in6_addr		 addr;
298 
299 	switch (imsg->hdr.type) {
300 	case IMSG_CTL_KROUTE:
301 		if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(flags)) {
302 			log_warnx("kr_show_route: wrong imsg len");
303 			return;
304 		}
305 		memcpy(&flags, imsg->data, sizeof(flags));
306 		RB_FOREACH(kr, kroute_tree, &krt)
307 			if (!flags || kr->r.flags & flags) {
308 				kn = kr;
309 				do {
310 					main_imsg_compose_ospfe(IMSG_CTL_KROUTE,
311 					    imsg->hdr.pid,
312 					    &kn->r, sizeof(kn->r));
313 				} while ((kn = kn->next) != NULL);
314 			}
315 		break;
316 	case IMSG_CTL_KROUTE_ADDR:
317 		if (imsg->hdr.len != IMSG_HEADER_SIZE +
318 		    sizeof(struct in6_addr)) {
319 			log_warnx("kr_show_route: wrong imsg len");
320 			return;
321 		}
322 		memcpy(&addr, imsg->data, sizeof(addr));
323 		kr = NULL;
324 		kr = kroute_match(&addr);
325 		if (kr != NULL)
326 			main_imsg_compose_ospfe(IMSG_CTL_KROUTE, imsg->hdr.pid,
327 			    &kr->r, sizeof(kr->r));
328 		break;
329 	default:
330 		log_debug("kr_show_route: error handling imsg");
331 		break;
332 	}
333 
334 	main_imsg_compose_ospfe(IMSG_CTL_END, imsg->hdr.pid, NULL, 0);
335 }
336 
337 void
338 kr_redist_remove(struct kroute_node *kh, struct kroute_node *kn)
339 {
340 	struct rroute	 rr;
341 
342 	/* was the route redistributed? */
343 	if ((kn->r.flags & F_REDISTRIBUTED) == 0)
344 		return;
345 
346 	/* remove redistributed flag */
347 	kn->r.flags &= ~F_REDISTRIBUTED;
348 	rr.kr = kn->r;
349 	rr.metric = DEFAULT_REDIST_METRIC;	/* some dummy value */
350 
351 	/* probably inform the RDE (check if no other path is redistributed) */
352 	for (kn = kh; kn; kn = kn->next)
353 		if (kn->r.flags & F_REDISTRIBUTED)
354 			break;
355 
356 	if (kn == NULL)
357 		main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, &rr,
358 		    sizeof(struct rroute));
359 }
360 
361 int
362 kr_redist_eval(struct kroute *kr, struct rroute *rr)
363 {
364 	u_int32_t	 metric = 0;
365 
366 	/* Only non-ospfd routes are considered for redistribution. */
367 	if (!(kr->flags & F_KERNEL))
368 		goto dont_redistribute;
369 
370 	/* Dynamic routes are not redistributable. */
371 	if (kr->flags & F_DYNAMIC)
372 		goto dont_redistribute;
373 
374 	/* interface is not up and running so don't announce */
375 	if (kr->flags & F_DOWN)
376 		goto dont_redistribute;
377 
378 	/*
379 	 * We consider unspecified, loopback, multicast, link- and site-local,
380 	 * IPv4 mapped and IPv4 compatible addresses as not redistributable.
381 	 */
382 	if (IN6_IS_ADDR_UNSPECIFIED(&kr->prefix) ||
383 	    IN6_IS_ADDR_LOOPBACK(&kr->prefix) ||
384 	    IN6_IS_ADDR_MULTICAST(&kr->prefix) ||
385 	    IN6_IS_ADDR_LINKLOCAL(&kr->prefix) ||
386 	    IN6_IS_ADDR_SITELOCAL(&kr->prefix) ||
387 	    IN6_IS_ADDR_V4MAPPED(&kr->prefix) ||
388 	    IN6_IS_ADDR_V4COMPAT(&kr->prefix))
389 		goto dont_redistribute;
390 	/*
391 	 * Consider networks with nexthop loopback as not redistributable.
392 	 */
393 	if (IN6_IS_ADDR_LOOPBACK(&kr->nexthop))
394 		goto dont_redistribute;
395 
396 	/* Should we redistrubute this route? */
397 	if (!ospf_redistribute(kr, &metric))
398 		goto dont_redistribute;
399 
400 	/* prefix should be redistributed */
401 	kr->flags |= F_REDISTRIBUTED;
402 	/*
403 	 * only on of all multipath routes can be redistributed so
404 	 * redistribute the best one.
405 	 */
406 	if (rr->metric > metric) {
407 		rr->kr = *kr;
408 		rr->metric = metric;
409 	}
410 	return (1);
411 
412 dont_redistribute:
413 	/* was the route redistributed? */
414 	if ((kr->flags & F_REDISTRIBUTED) == 0)
415 		return (0);
416 
417 	kr->flags &= ~F_REDISTRIBUTED;
418 	return (1);
419 }
420 
421 void
422 kr_redistribute(struct kroute_node *kh)
423 {
424 	struct kroute_node	*kn;
425 	struct rroute		 rr;
426 	int			 redistribute = 0;
427 
428 	bzero(&rr, sizeof(rr));
429 	rr.metric = UINT_MAX;
430 	for (kn = kh; kn; kn = kn->next)
431 		if (kr_redist_eval(&kn->r, &rr))
432 			redistribute = 1;
433 
434 	if (!redistribute)
435 		return;
436 
437 	if (rr.kr.flags & F_REDISTRIBUTED) {
438 		main_imsg_compose_rde(IMSG_NETWORK_ADD, 0, &rr,
439 		    sizeof(struct rroute));
440 	} else {
441 		rr.metric = DEFAULT_REDIST_METRIC;	/* some dummy value */
442 		rr.kr = kh->r;
443 		main_imsg_compose_rde(IMSG_NETWORK_DEL, 0, &rr,
444 		    sizeof(struct rroute));
445 	}
446 }
447 
448 void
449 kr_reload(void)
450 {
451 	struct kroute_node	*kr, *kn;
452 	u_int32_t		 dummy;
453 	int			 r;
454 
455 	RB_FOREACH(kr, kroute_tree, &krt) {
456 		for (kn = kr; kn; kn = kn->next) {
457 			r = ospf_redistribute(&kn->r, &dummy);
458 			/*
459 			 * if it is redistributed, redistribute again metric
460 			 * may have changed.
461 			 */
462 			if ((kn->r.flags & F_REDISTRIBUTED && !r) || r)
463 				break;
464 		}
465 		if (kn) {
466 			/*
467 			 * kr_redistribute copes with removes and RDE with
468 			 * duplicates
469 			 */
470 			kr_redistribute(kr);
471 		}
472 	}
473 }
474 
475 /* rb-tree compare */
476 int
477 kroute_compare(struct kroute_node *a, struct kroute_node *b)
478 {
479 	int	i;
480 
481 	/* XXX maybe switch a & b */
482 	i = memcmp(&a->r.prefix, &b->r.prefix, sizeof(a->r.prefix));
483 	if (i)
484 		return (i);
485 	if (a->r.prefixlen < b->r.prefixlen)
486 		return (-1);
487 	if (a->r.prefixlen > b->r.prefixlen)
488 		return (1);
489 	return (0);
490 }
491 
492 /* tree management */
493 struct kroute_node *
494 kroute_find(const struct in6_addr *prefix, u_int8_t prefixlen)
495 {
496 	struct kroute_node	s;
497 
498 	s.r.prefix = *prefix;
499 	s.r.prefixlen = prefixlen;
500 
501 	return (RB_FIND(kroute_tree, &krt, &s));
502 }
503 
504 struct kroute_node *
505 kroute_matchgw(struct kroute_node *kr, struct in6_addr *nh)
506 {
507 	while (kr) {
508 		if (IN6_ARE_ADDR_EQUAL(&kr->r.nexthop, nh))
509 			return (kr);
510 		kr = kr->next;
511 	}
512 
513 	return (NULL);
514 }
515 
516 int
517 kroute_insert(struct kroute_node *kr)
518 {
519 	struct kroute_node	*krm;
520 
521 	if ((krm = RB_INSERT(kroute_tree, &krt, kr)) != NULL) {
522 		/*
523 		 * Multipath route, add at end of list and clone the
524 		 * ospfd inserted flag.
525 		 */
526 		kr->r.flags |= krm->r.flags & F_OSPFD_INSERTED;
527 		while (krm->next != NULL)
528 			krm = krm->next;
529 		krm->next = kr;
530 		kr->next = NULL; /* to be sure */
531 	} else
532 		krm = kr;
533 
534 	if (!(kr->r.flags & F_KERNEL)) {
535 		/* don't validate or redistribute ospf route */
536 		kr->r.flags &= ~F_DOWN;
537 		return (0);
538 	}
539 
540 	if (kif_validate(kr->r.ifindex))
541 		kr->r.flags &= ~F_DOWN;
542 	else
543 		kr->r.flags |= F_DOWN;
544 
545 	kr_redistribute(krm);
546 	return (0);
547 }
548 
549 int
550 kroute_remove(struct kroute_node *kr)
551 {
552 	struct kroute_node	*krm;
553 
554 	if ((krm = RB_FIND(kroute_tree, &krt, kr)) == NULL) {
555 		log_warnx("kroute_remove failed to find %s/%u",
556 		    log_in6addr(&kr->r.prefix), kr->r.prefixlen);
557 		return (-1);
558 	}
559 
560 	if (krm == kr) {
561 		/* head element */
562 		if (RB_REMOVE(kroute_tree, &krt, kr) == NULL) {
563 			log_warnx("kroute_remove failed for %s/%u",
564 			    log_in6addr(&kr->r.prefix), kr->r.prefixlen);
565 			return (-1);
566 		}
567 		if (kr->next != NULL) {
568 			if (RB_INSERT(kroute_tree, &krt, kr->next) != NULL) {
569 				log_warnx("kroute_remove failed to add %s/%u",
570 				    log_in6addr(&kr->r.prefix),
571 				    kr->r.prefixlen);
572 				return (-1);
573 			}
574 		}
575 	} else {
576 		/* somewhere in the list */
577 		while (krm->next != kr && krm->next != NULL)
578 			krm = krm->next;
579 		if (krm->next == NULL) {
580 			log_warnx("kroute_remove multipath list corrupted "
581 			    "for %s/%u", log_in6addr(&kr->r.prefix),
582 			    kr->r.prefixlen);
583 			return (-1);
584 		}
585 		krm->next = kr->next;
586 	}
587 
588 	kr_redist_remove(krm, kr);
589 	rtlabel_unref(kr->r.rtlabel);
590 
591 	free(kr);
592 	return (0);
593 }
594 
595 void
596 kroute_clear(void)
597 {
598 	struct kroute_node	*kr;
599 
600 	while ((kr = RB_MIN(kroute_tree, &krt)) != NULL)
601 		kroute_remove(kr);
602 }
603 
604 struct iface *
605 kif_update(u_short ifindex, int flags, struct if_data *ifd,
606     struct sockaddr_dl *sdl)
607 {
608 	struct iface	*iface;
609 	char		 ifname[IF_NAMESIZE];
610 
611 	if ((iface = if_find(ifindex)) == NULL) {
612 		if (sdl && sdl->sdl_family == AF_LINK) {
613 			bzero(ifname, sizeof(ifname));
614 			if (sdl->sdl_nlen >= sizeof(ifname))
615 				memcpy(ifname, sdl->sdl_data,
616 				    sizeof(ifname) - 1);
617 			else if (sdl->sdl_nlen > 0)
618 				memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
619 		}
620 
621 		if ((iface = if_new(ifindex, ifname)) == NULL)
622 			return (NULL);
623 		iface->cflags |= F_IFACE_AVAIL;
624 	}
625 
626 	if_update(iface, ifd->ifi_mtu, flags, ifd->ifi_type,
627 	    ifd->ifi_link_state, ifd->ifi_baudrate);
628 
629 	return (iface);
630 }
631 
632 int
633 kif_validate(u_short ifindex)
634 {
635 	struct iface	*iface;
636 
637 	if ((iface = if_find(ifindex)) == NULL) {
638 		log_warnx("interface with index %u not found", ifindex);
639 		return (1);
640 	}
641 
642 	return (iface->nh_reachable);
643 }
644 
645 struct kroute_node *
646 kroute_match(struct in6_addr *key)
647 {
648 	int			 i;
649 	struct kroute_node	*kr;
650 	struct in6_addr		 ina;
651 
652 	/* we will never match the default route */
653 	for (i = 128; i > 0; i--) {
654 		inet6applymask(&ina, key, i);
655 		if ((kr = kroute_find(&ina, i)) != NULL)
656 			return (kr);
657 	}
658 
659 	/* if we don't have a match yet, try to find a default route */
660 	if ((kr = kroute_find(&in6addr_any, 0)) != NULL)
661 			return (kr);
662 
663 	return (NULL);
664 }
665 
666 /* misc */
667 int
668 protect_lo(void)
669 {
670 	struct kroute_node	*kr;
671 
672 	/* special protection for loopback */
673 	if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
674 		log_warn("protect_lo");
675 		return (-1);
676 	}
677 	memcpy(&kr->r.prefix, &in6addr_loopback, sizeof(kr->r.prefix));
678 	kr->r.prefixlen = 128;
679 	kr->r.flags = F_KERNEL|F_CONNECTED;
680 
681 	if (RB_INSERT(kroute_tree, &krt, kr) != NULL)
682 		free(kr);	/* kernel route already there, no problem */
683 
684 	return (0);
685 }
686 
687 u_int8_t
688 mask2prefixlen(struct sockaddr_in6 *sa_in6)
689 {
690 	u_int8_t	l = 0, i, len;
691 
692 	/*
693 	 * sin6_len is the size of the sockaddr so substract the offset of
694 	 * the possibly truncated sin6_addr struct.
695 	 */
696 	len = sa_in6->sin6_len -
697 	    (u_int8_t)(&((struct sockaddr_in6 *)NULL)->sin6_addr);
698 	for (i = 0; i < len; i++) {
699 		/* this "beauty" is adopted from sbin/route/show.c ... */
700 		switch (sa_in6->sin6_addr.s6_addr[i]) {
701 		case 0xff:
702 			l += 8;
703 			break;
704 		case 0xfe:
705 			l += 7;
706 			return (l);
707 		case 0xfc:
708 			l += 6;
709 			return (l);
710 		case 0xf8:
711 			l += 5;
712 			return (l);
713 		case 0xf0:
714 			l += 4;
715 			return (l);
716 		case 0xe0:
717 			l += 3;
718 			return (l);
719 		case 0xc0:
720 			l += 2;
721 			return (l);
722 		case 0x80:
723 			l += 1;
724 			return (l);
725 		case 0x00:
726 			return (l);
727 		default:
728 			fatalx("non continguous inet6 netmask");
729 		}
730 	}
731 
732 	return (l);
733 }
734 
735 struct in6_addr *
736 prefixlen2mask(u_int8_t prefixlen)
737 {
738 	static struct in6_addr	mask;
739 	int			i;
740 
741 	bzero(&mask, sizeof(mask));
742 	for (i = 0; i < prefixlen / 8; i++)
743 		mask.s6_addr[i] = 0xff;
744 	i = prefixlen % 8;
745 	if (i)
746 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
747 
748 	return (&mask);
749 }
750 
751 void
752 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
753 {
754 	struct in6_addr	mask;
755 	int		i;
756 
757 	bzero(&mask, sizeof(mask));
758 	for (i = 0; i < prefixlen / 8; i++)
759 		mask.s6_addr[i] = 0xff;
760 	i = prefixlen % 8;
761 	if (i)
762 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
763 
764 	for (i = 0; i < 16; i++)
765 		dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
766 }
767 
768 #define	ROUNDUP(a, size)	\
769     (((a) & ((size) - 1)) ? (1 + ((a) | ((size) - 1))) : (a))
770 
771 void
772 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
773 {
774 	int	i;
775 
776 	for (i = 0; i < RTAX_MAX; i++) {
777 		if (addrs & (1 << i)) {
778 			rti_info[i] = sa;
779 			sa = (struct sockaddr *)((char *)(sa) +
780 			    ROUNDUP(sa->sa_len, sizeof(long)));
781 		} else
782 			rti_info[i] = NULL;
783 	}
784 }
785 
786 void
787 if_change(u_short ifindex, int flags, struct if_data *ifd)
788 {
789 	struct kroute_node	*kr, *tkr;
790 	struct iface		*iface;
791 	u_int8_t		 reachable;
792 
793 	if ((iface = kif_update(ifindex, flags, ifd, NULL)) == NULL) {
794 		log_warn("if_change: kif_update(%u)", ifindex);
795 		return;
796 	}
797 
798 	reachable = (iface->flags & IFF_UP) &&
799 	    (LINK_STATE_IS_UP(iface->linkstate) ||
800 	    (iface->linkstate == LINK_STATE_UNKNOWN &&
801 	    iface->media_type != IFT_CARP));
802 
803 	if (reachable == iface->nh_reachable)
804 		return;		/* nothing changed wrt nexthop validity */
805 
806 	iface->nh_reachable = reachable;
807 
808 	/* notify ospfe about interface link state */
809 	if (iface->cflags & F_IFACE_CONFIGURED)
810 		main_imsg_compose_ospfe(IMSG_IFINFO, 0, iface,
811 		    sizeof(struct iface));
812 
813 	/* update redistribute list */
814 	RB_FOREACH(kr, kroute_tree, &krt) {
815 		for (tkr = kr; tkr != NULL; tkr = tkr->next) {
816 			if (tkr->r.ifindex == ifindex) {
817 				if (reachable)
818 					tkr->r.flags &= ~F_DOWN;
819 				else
820 					tkr->r.flags |= F_DOWN;
821 
822 			}
823 		}
824 		kr_redistribute(kr);
825 	}
826 }
827 
828 void
829 if_newaddr(u_short ifindex, struct sockaddr_in6 *ifa, struct sockaddr_in6 *mask,
830     struct sockaddr_in6 *brd)
831 {
832 	struct iface		*iface;
833 	struct iface_addr	*ia;
834 
835 	if (ifa == NULL || ifa->sin6_family != AF_INET6)
836 		return;
837 	if ((iface = if_find(ifindex)) == NULL) {
838 		log_warnx("if_newaddr: corresponding if %i not found", ifindex);
839 		return;
840 	}
841 
842 	/* We only care about link-local and global-scope. */
843 	if (IN6_IS_ADDR_UNSPECIFIED(&ifa->sin6_addr) ||
844 	    IN6_IS_ADDR_LOOPBACK(&ifa->sin6_addr) ||
845 	    IN6_IS_ADDR_MULTICAST(&ifa->sin6_addr) ||
846 	    IN6_IS_ADDR_SITELOCAL(&ifa->sin6_addr) ||
847 	    IN6_IS_ADDR_V4MAPPED(&ifa->sin6_addr) ||
848 	    IN6_IS_ADDR_V4COMPAT(&ifa->sin6_addr))
849 	    	return;
850 
851 	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
852 	if (IN6_IS_ADDR_LINKLOCAL(&ifa->sin6_addr)) {
853 		ifa->sin6_addr.s6_addr[2] = 0;
854 		ifa->sin6_addr.s6_addr[3] = 0;
855 	}
856 
857 	if (IN6_IS_ADDR_LINKLOCAL(&ifa->sin6_addr))
858 		iface->addr = ifa->sin6_addr;
859 
860 	if ((ia = calloc(1, sizeof(struct iface_addr))) == NULL)
861 		fatal("if_newaddr");
862 
863 	ia->addr = ifa->sin6_addr;
864 
865 	if (mask)
866 		ia->prefixlen = mask2prefixlen(mask);
867 	else
868 		ia->prefixlen = 0;
869 	if (brd && brd->sin6_family == AF_INET6)
870 		ia->dstbrd = brd->sin6_addr;
871 	else
872 		bzero(&ia->dstbrd, sizeof(ia->dstbrd));
873 
874 	switch (iface->type) {
875 	case IF_TYPE_BROADCAST:
876 	case IF_TYPE_NBMA:
877 		log_debug("if_newaddr: ifindex %u, addr %s/%d",
878 		    ifindex, log_in6addr(&ia->addr), ia->prefixlen);
879 		break;
880 	case IF_TYPE_VIRTUALLINK:	/* FIXME */
881 		break;
882 	case IF_TYPE_POINTOPOINT:
883 	case IF_TYPE_POINTOMULTIPOINT:
884 		log_debug("if_newaddr: ifindex %u, addr %s/%d, "
885 		    "dest %s", ifindex, log_in6addr(&ia->addr),
886 		    ia->prefixlen, log_in6addr(&ia->dstbrd));
887 		break;
888 	default:
889 		fatalx("if_newaddr: unknown interface type");
890 	}
891 
892 	TAILQ_INSERT_TAIL(&iface->ifa_list, ia, entry);
893 }
894 
895 void
896 if_announce(void *msg)
897 {
898 	struct if_announcemsghdr	*ifan;
899 	struct iface			*iface;
900 
901 	ifan = msg;
902 
903 	switch (ifan->ifan_what) {
904 	case IFAN_ARRIVAL:
905 		if ((iface = if_new(ifan->ifan_index, ifan->ifan_name)) == NULL)
906 			fatal("if_announce failed");
907 		iface->cflags |= F_IFACE_AVAIL;
908 		break;
909 	case IFAN_DEPARTURE:
910 		iface = if_find(ifan->ifan_index);
911 		if (iface->cflags & F_IFACE_CONFIGURED) {
912 			main_imsg_compose_rde(IMSG_IFDELETE, 0,
913 			    &iface->ifindex, sizeof(iface->ifindex));
914 			main_imsg_compose_ospfe(IMSG_IFDELETE, 0,
915 			    &iface->ifindex, sizeof(iface->ifindex));
916 		}
917 		if_del(iface);
918 		break;
919 	}
920 }
921 
922 /* rtsock */
923 int
924 send_rtmsg(int fd, int action, struct kroute *kroute)
925 {
926 	struct iovec		iov[5];
927 	struct rt_msghdr	hdr;
928 	struct sockaddr_in6	prefix;
929 	struct sockaddr_in6	nexthop;
930 	struct sockaddr_in6	mask;
931 	struct sockaddr_rtlabel	sa_rl;
932 	int			iovcnt = 0;
933 	const char		*label;
934 
935 	if (kr_state.fib_sync == 0)
936 		return (0);
937 
938 	/* initialize header */
939 	bzero(&hdr, sizeof(hdr));
940 	hdr.rtm_version = RTM_VERSION;
941 	hdr.rtm_type = action;
942 	hdr.rtm_flags = RTF_PROTO2;
943 	hdr.rtm_priority = RTP_OSPF;
944 	if (action == RTM_CHANGE)	/* force PROTO2 reset the other flags */
945 		hdr.rtm_fmask = RTF_PROTO2|RTF_PROTO1|RTF_REJECT|RTF_BLACKHOLE;
946 	hdr.rtm_seq = kr_state.rtseq++;	/* overflow doesn't matter */
947 	hdr.rtm_msglen = sizeof(hdr);
948 	/* adjust iovec */
949 	iov[iovcnt].iov_base = &hdr;
950 	iov[iovcnt++].iov_len = sizeof(hdr);
951 
952 	bzero(&prefix, sizeof(prefix));
953 	prefix.sin6_len = sizeof(prefix);
954 	prefix.sin6_family = AF_INET6;
955 	prefix.sin6_addr = kroute->prefix;
956 	/* adjust header */
957 	hdr.rtm_addrs |= RTA_DST;
958 	hdr.rtm_msglen += sizeof(prefix);
959 	/* adjust iovec */
960 	iov[iovcnt].iov_base = &prefix;
961 	iov[iovcnt++].iov_len = sizeof(prefix);
962 
963 	if (!IN6_IS_ADDR_UNSPECIFIED(&kroute->nexthop)) {
964 		bzero(&nexthop, sizeof(nexthop));
965 		nexthop.sin6_len = sizeof(nexthop);
966 		nexthop.sin6_family = AF_INET6;
967 		nexthop.sin6_addr = kroute->nexthop;
968 		/* adjust header */
969 		hdr.rtm_flags |= RTF_GATEWAY;
970 		hdr.rtm_addrs |= RTA_GATEWAY;
971 		hdr.rtm_msglen += sizeof(nexthop);
972 		/* adjust iovec */
973 		iov[iovcnt].iov_base = &nexthop;
974 		iov[iovcnt++].iov_len = sizeof(nexthop);
975 	}
976 
977 	bzero(&mask, sizeof(mask));
978 	mask.sin6_len = sizeof(mask);
979 	mask.sin6_family = AF_INET6;
980 	mask.sin6_addr = *prefixlen2mask(kroute->prefixlen);
981 	/* adjust header */
982 	hdr.rtm_addrs |= RTA_NETMASK;
983 	hdr.rtm_msglen += sizeof(mask);
984 	/* adjust iovec */
985 	iov[iovcnt].iov_base = &mask;
986 	iov[iovcnt++].iov_len = sizeof(mask);
987 
988 	if (kroute->rtlabel != 0) {
989 		sa_rl.sr_len = sizeof(sa_rl);
990 		sa_rl.sr_family = AF_UNSPEC;
991 		label = rtlabel_id2name(kroute->rtlabel);
992 		if (strlcpy(sa_rl.sr_label, label,
993 		    sizeof(sa_rl.sr_label)) >= sizeof(sa_rl.sr_label)) {
994 			log_warnx("send_rtmsg: invalid rtlabel");
995 			return (-1);
996 		}
997 		/* adjust header */
998 		hdr.rtm_addrs |= RTA_LABEL;
999 		hdr.rtm_msglen += sizeof(sa_rl);
1000 		/* adjust iovec */
1001 		iov[iovcnt].iov_base = &sa_rl;
1002 		iov[iovcnt++].iov_len = sizeof(sa_rl);
1003 	}
1004 
1005 retry:
1006 	if (writev(fd, iov, iovcnt) == -1) {
1007 		switch (errno) {
1008 		case ESRCH:
1009 			if (hdr.rtm_type == RTM_CHANGE) {
1010 				hdr.rtm_type = RTM_ADD;
1011 				goto retry;
1012 			} else if (hdr.rtm_type == RTM_DELETE) {
1013 				log_info("route %s/%u vanished before delete",
1014 				    log_sockaddr(&prefix), kroute->prefixlen);
1015 				return (0);
1016 			} else {
1017 				log_warn("send_rtmsg: action %u, "
1018 				    "prefix %s/%u", hdr.rtm_type,
1019 				    log_sockaddr(&prefix), kroute->prefixlen);
1020 				return (0);
1021 			}
1022 			break;
1023 		default:
1024 			log_warn("send_rtmsg: action %u, prefix %s/%u",
1025 			    hdr.rtm_type, log_sockaddr(&prefix),
1026 			    kroute->prefixlen);
1027 			return (0);
1028 		}
1029 	}
1030 
1031 	return (0);
1032 }
1033 
1034 int
1035 fetchtable(void)
1036 {
1037 	size_t			 len;
1038 	int			 mib[7];
1039 	char			*buf, *next, *lim;
1040 	struct rt_msghdr	*rtm;
1041 	struct sockaddr		*sa, *rti_info[RTAX_MAX];
1042 	struct sockaddr_in6	*sa_in6;
1043 	struct sockaddr_rtlabel	*label;
1044 	struct kroute_node	*kr;
1045 
1046 	mib[0] = CTL_NET;
1047 	mib[1] = AF_ROUTE;
1048 	mib[2] = 0;
1049 	mib[3] = AF_INET;
1050 	mib[4] = NET_RT_DUMP;
1051 	mib[5] = 0;
1052 	mib[6] = 0;	/* rtableid */
1053 
1054 	if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
1055 		log_warn("sysctl");
1056 		return (-1);
1057 	}
1058 	if ((buf = malloc(len)) == NULL) {
1059 		log_warn("fetchtable");
1060 		return (-1);
1061 	}
1062 	if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
1063 		log_warn("sysctl");
1064 		free(buf);
1065 		return (-1);
1066 	}
1067 
1068 	lim = buf + len;
1069 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
1070 		rtm = (struct rt_msghdr *)next;
1071 		if (rtm->rtm_version != RTM_VERSION)
1072 			continue;
1073 		sa = (struct sockaddr *)(rtm + 1);
1074 		get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1075 
1076 		if ((sa = rti_info[RTAX_DST]) == NULL)
1077 			continue;
1078 
1079 		if (rtm->rtm_flags & RTF_LLINFO)	/* arp cache */
1080 			continue;
1081 
1082 		if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
1083 			log_warn("fetchtable");
1084 			free(buf);
1085 			return (-1);
1086 		}
1087 
1088 		kr->r.flags = F_KERNEL;
1089 
1090 		switch (sa->sa_family) {
1091 		case AF_INET6:
1092 			kr->r.prefix =
1093 			    ((struct sockaddr_in6 *)sa)->sin6_addr;
1094 			sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
1095 			if (rtm->rtm_flags & RTF_STATIC)
1096 				kr->r.flags |= F_STATIC;
1097 			if (rtm->rtm_flags & RTF_DYNAMIC)
1098 				kr->r.flags |= F_DYNAMIC;
1099 			if (rtm->rtm_flags & RTF_PROTO1)
1100 				kr->r.flags |= F_BGPD_INSERTED;
1101 			if (sa_in6 != NULL) {
1102 				if (sa_in6->sin6_len == 0)
1103 					break;
1104 				kr->r.prefixlen =
1105 				    mask2prefixlen(sa_in6);
1106 			} else if (rtm->rtm_flags & RTF_HOST)
1107 				kr->r.prefixlen = 128;
1108 			else
1109 				fatalx("classful IPv6 route?!!");
1110 			break;
1111 		default:
1112 			free(kr);
1113 			continue;
1114 		}
1115 
1116 		kr->r.ifindex = rtm->rtm_index;
1117 		if ((sa = rti_info[RTAX_GATEWAY]) != NULL)
1118 			switch (sa->sa_family) {
1119 			case AF_INET6:
1120 				kr->r.nexthop =
1121 				    ((struct sockaddr_in6 *)sa)->sin6_addr;
1122 				break;
1123 			case AF_LINK:
1124 				kr->r.flags |= F_CONNECTED;
1125 				break;
1126 			}
1127 
1128 		if (rtm->rtm_flags & RTF_PROTO2)  {
1129 			send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r);
1130 			free(kr);
1131 		} else {
1132 			if ((label = (struct sockaddr_rtlabel *)
1133 			    rti_info[RTAX_LABEL]) != NULL) {
1134 				kr->r.rtlabel =
1135 				    rtlabel_name2id(label->sr_label);
1136 				kr->r.ext_tag =
1137 				    rtlabel_id2tag(kr->r.rtlabel);
1138 			}
1139 			kroute_insert(kr);
1140 		}
1141 
1142 	}
1143 	free(buf);
1144 	return (0);
1145 }
1146 
1147 int
1148 fetchifs(u_short ifindex)
1149 {
1150 	size_t			 len;
1151 	int			 mib[6];
1152 	char			*buf, *next, *lim;
1153 	struct rt_msghdr	*rtm;
1154 	struct if_msghdr	 ifm;
1155 	struct ifa_msghdr	*ifam;
1156 	struct iface		*iface;
1157 	struct sockaddr		*sa, *rti_info[RTAX_MAX];
1158 
1159 	mib[0] = CTL_NET;
1160 	mib[1] = AF_ROUTE;
1161 	mib[2] = 0;
1162 	mib[3] = AF_INET6;
1163 	mib[4] = NET_RT_IFLIST;
1164 	mib[5] = ifindex;
1165 
1166 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
1167 		log_warn("sysctl");
1168 		return (-1);
1169 	}
1170 	if ((buf = malloc(len)) == NULL) {
1171 		log_warn("fetchif");
1172 		return (-1);
1173 	}
1174 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) {
1175 		log_warn("sysctl");
1176 		free(buf);
1177 		return (-1);
1178 	}
1179 
1180 	lim = buf + len;
1181 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
1182 		rtm = (struct rt_msghdr *)next;
1183 		if (rtm->rtm_version != RTM_VERSION)
1184 			continue;
1185 		switch (rtm->rtm_type) {
1186 		case RTM_IFINFO:
1187 			bcopy(rtm, &ifm, sizeof ifm);
1188 			sa = (struct sockaddr *)(next + sizeof(ifm));
1189 			get_rtaddrs(ifm.ifm_addrs, sa, rti_info);
1190 
1191 			if ((iface = kif_update(ifm.ifm_index,
1192 			    ifm.ifm_flags, &ifm.ifm_data,
1193 			    (struct sockaddr_dl *)rti_info[RTAX_IFP])) == NULL)
1194 				fatal("fetchifs");
1195 
1196 			iface->nh_reachable = (iface->flags & IFF_UP) &&
1197 			    (LINK_STATE_IS_UP(ifm.ifm_data.ifi_link_state) ||
1198 			    (ifm.ifm_data.ifi_link_state ==
1199 			    LINK_STATE_UNKNOWN &&
1200 			    ifm.ifm_data.ifi_type != IFT_CARP));
1201 			break;
1202 		case RTM_NEWADDR:
1203 			ifam = (struct ifa_msghdr *)rtm;
1204 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
1205 			    RTA_BRD)) == 0)
1206 				break;
1207 			sa = (struct sockaddr *)(ifam + 1);
1208 			get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
1209 
1210 			if_newaddr(ifam->ifam_index,
1211 			    (struct sockaddr_in6 *)rti_info[RTAX_IFA],
1212 			    (struct sockaddr_in6 *)rti_info[RTAX_NETMASK],
1213 			    (struct sockaddr_in6 *)rti_info[RTAX_BRD]);
1214 			break;
1215 		}
1216 	}
1217 	free(buf);
1218 	return (0);
1219 }
1220 
1221 int
1222 dispatch_rtmsg(void)
1223 {
1224 	char			 buf[RT_BUF_SIZE];
1225 	ssize_t			 n;
1226 	char			*next, *lim;
1227 	struct rt_msghdr	*rtm;
1228 	struct if_msghdr	 ifm;
1229 	struct ifa_msghdr	*ifam;
1230 	struct sockaddr		*sa, *rti_info[RTAX_MAX];
1231 	struct sockaddr_in6	*sa_in6;
1232 	struct sockaddr_rtlabel	*label;
1233 	struct kroute_node	*kr, *okr;
1234 	struct in6_addr		 prefix, nexthop;
1235 	u_int8_t		 prefixlen;
1236 	int			 flags, mpath;
1237 	u_short			 ifindex = 0;
1238 
1239 	if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) {
1240 		log_warn("dispatch_rtmsg: read error");
1241 		return (-1);
1242 	}
1243 
1244 	if (n == 0) {
1245 		log_warnx("routing socket closed");
1246 		return (-1);
1247 	}
1248 
1249 	lim = buf + n;
1250 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
1251 		rtm = (struct rt_msghdr *)next;
1252 		if (rtm->rtm_version != RTM_VERSION)
1253 			continue;
1254 
1255 		bzero(&prefix, sizeof(prefix));
1256 		bzero(&nexthop, sizeof(nexthop));
1257 		prefixlen = 0;
1258 		flags = F_KERNEL;
1259 		mpath = 0;
1260 
1261 		if (rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE ||
1262 		    rtm->rtm_type == RTM_DELETE) {
1263 			sa = (struct sockaddr *)(rtm + 1);
1264 			get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1265 
1266 			if (rtm->rtm_tableid != 0)
1267 				continue;
1268 
1269 			if (rtm->rtm_pid == kr_state.pid) /* caused by us */
1270 				continue;
1271 
1272 			if (rtm->rtm_errno)		/* failed attempts... */
1273 				continue;
1274 
1275 			if (rtm->rtm_flags & RTF_LLINFO)	/* arp cache */
1276 				continue;
1277 
1278 #ifdef RTF_MPATH
1279 			if (rtm->rtm_flags & RTF_MPATH)
1280 				mpath = 1;
1281 #endif
1282 			switch (sa->sa_family) {
1283 			case AF_INET6:
1284 				prefix =
1285 				    ((struct sockaddr_in6 *)sa)->sin6_addr;
1286 				sa_in6 = (struct sockaddr_in6 *)
1287 				    rti_info[RTAX_NETMASK];
1288 				if (sa_in6 != NULL) {
1289 					if (sa_in6->sin6_len != 0)
1290 						prefixlen = mask2prefixlen(
1291 						    sa_in6);
1292 				} else if (rtm->rtm_flags & RTF_HOST)
1293 					prefixlen = 128;
1294 				else
1295 					fatalx("classful IPv6 address?!!");
1296 				if (rtm->rtm_flags & RTF_STATIC)
1297 					flags |= F_STATIC;
1298 				if (rtm->rtm_flags & RTF_DYNAMIC)
1299 					flags |= F_DYNAMIC;
1300 				if (rtm->rtm_flags & RTF_PROTO1)
1301 					flags |= F_BGPD_INSERTED;
1302 				break;
1303 			default:
1304 				continue;
1305 			}
1306 
1307 			ifindex = rtm->rtm_index;
1308 			if ((sa = rti_info[RTAX_GATEWAY]) != NULL) {
1309 				switch (sa->sa_family) {
1310 				case AF_INET:
1311 					nexthop = ((struct sockaddr_in6 *)
1312 					    sa)->sin6_addr;
1313 					break;
1314 				case AF_LINK:
1315 					flags |= F_CONNECTED;
1316 					break;
1317 				}
1318 			}
1319 		}
1320 
1321 		switch (rtm->rtm_type) {
1322 		case RTM_ADD:
1323 		case RTM_CHANGE:
1324 			if (IN6_IS_ADDR_UNSPECIFIED(&nexthop) == 0 &&
1325 			    !(flags & F_CONNECTED)) {
1326 				log_warnx("dispatch_rtmsg no nexthop for %s/%u",
1327 				    log_in6addr(&prefix), prefixlen);
1328 				continue;
1329 			}
1330 
1331 			if ((okr = kroute_find(&prefix, prefixlen)) !=
1332 			    NULL) {
1333 				/* just add new multipath routes */
1334 				if (mpath && rtm->rtm_type == RTM_ADD)
1335 					goto add;
1336 				/* get the correct route */
1337 				kr = okr;
1338 				if (mpath && (kr = kroute_matchgw(okr,
1339 				    &nexthop)) == NULL) {
1340 					log_warnx("dispatch_rtmsg mpath route"
1341 					    " not found");
1342 					/* add routes we missed out earlier */
1343 					goto add;
1344 				}
1345 
1346 				/*
1347 				 * ospf route overridden by kernel. Preference
1348 				 * of the route is not checked because this is
1349 				 * forced -- most probably by a user.
1350 				 */
1351 				if (kr->r.flags & F_OSPFD_INSERTED)
1352 					flags |= F_OSPFD_INSERTED;
1353 				if (kr->r.flags & F_REDISTRIBUTED)
1354 					flags |= F_REDISTRIBUTED;
1355 				kr->r.nexthop = nexthop;
1356 				kr->r.flags = flags;
1357 				kr->r.ifindex = ifindex;
1358 
1359 				rtlabel_unref(kr->r.rtlabel);
1360 				kr->r.rtlabel = 0;
1361 				kr->r.ext_tag = 0;
1362 				if ((label = (struct sockaddr_rtlabel *)
1363 				    rti_info[RTAX_LABEL]) != NULL) {
1364 					kr->r.rtlabel =
1365 					    rtlabel_name2id(label->sr_label);
1366 					kr->r.ext_tag =
1367 					    rtlabel_id2tag(kr->r.rtlabel);
1368 				}
1369 
1370 				if (kif_validate(kr->r.ifindex))
1371 					kr->r.flags &= ~F_DOWN;
1372 				else
1373 					kr->r.flags |= F_DOWN;
1374 
1375 				/* just readd, the RDE will care */
1376 				kr_redistribute(okr);
1377 			} else {
1378 add:
1379 				if ((kr = calloc(1,
1380 				    sizeof(struct kroute_node))) == NULL) {
1381 					log_warn("dispatch_rtmsg");
1382 					return (-1);
1383 				}
1384 				kr->r.prefix = prefix;
1385 				kr->r.prefixlen = prefixlen;
1386 				kr->r.nexthop = nexthop;
1387 				kr->r.flags = flags;
1388 				kr->r.ifindex = ifindex;
1389 
1390 				if ((label = (struct sockaddr_rtlabel *)
1391 				    rti_info[RTAX_LABEL]) != NULL) {
1392 					kr->r.rtlabel =
1393 					    rtlabel_name2id(label->sr_label);
1394 					kr->r.ext_tag =
1395 					    rtlabel_id2tag(kr->r.rtlabel);
1396 				}
1397 
1398 				kroute_insert(kr);
1399 			}
1400 			break;
1401 		case RTM_DELETE:
1402 			if ((kr = kroute_find(&prefix, prefixlen)) ==
1403 			    NULL)
1404 				continue;
1405 			if (!(kr->r.flags & F_KERNEL))
1406 				continue;
1407 			/* get the correct route */
1408 			okr = kr;
1409 			if (mpath &&
1410 			    (kr = kroute_matchgw(kr, &nexthop)) == NULL) {
1411 				log_warnx("dispatch_rtmsg mpath route"
1412 				    " not found");
1413 				return (-1);
1414 			}
1415 			/*
1416 			 * last route is getting removed request the
1417 			 * ospf route from the RDE to insert instead
1418 			 */
1419 			if (okr == kr && kr->next == NULL &&
1420 			    kr->r.flags & F_OSPFD_INSERTED)
1421 				main_imsg_compose_rde(IMSG_KROUTE_GET, 0,
1422 				    &kr->r, sizeof(struct kroute));
1423 			if (kroute_remove(kr) == -1)
1424 				return (-1);
1425 			break;
1426 		case RTM_IFINFO:
1427 			memcpy(&ifm, next, sizeof(ifm));
1428 			if_change(ifm.ifm_index, ifm.ifm_flags,
1429 			    &ifm.ifm_data);
1430 			break;
1431 		case RTM_NEWADDR:
1432 			ifam = (struct ifa_msghdr *)rtm;
1433 			if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA |
1434 			    RTA_BRD)) == 0)
1435 				break;
1436 			sa = (struct sockaddr *)(ifam + 1);
1437 			get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
1438 
1439 			if_newaddr(ifam->ifam_index,
1440 			    (struct sockaddr_in6 *)rti_info[RTAX_IFA],
1441 			    (struct sockaddr_in6 *)rti_info[RTAX_NETMASK],
1442 			    (struct sockaddr_in6 *)rti_info[RTAX_BRD]);
1443 			break;
1444 		case RTM_IFANNOUNCE:
1445 			if_announce(next);
1446 			break;
1447 		default:
1448 			/* ignore for now */
1449 			break;
1450 		}
1451 	}
1452 	return (0);
1453 }
1454