1 /*	$OpenBSD: kroute.c,v 1.241 2021/01/18 12:15:36 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/ioctl.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_media.h>
30 #include <net/if_types.h>
31 #include <net/route.h>
32 #include <netmpls/mpls.h>
33 #include <err.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include "bgpd.h"
42 #include "log.h"
43 
44 struct ktable		**krt;
45 u_int			  krt_size;
46 
47 struct {
48 	u_int32_t		rtseq;
49 	pid_t			pid;
50 	int			fd;
51 } kr_state;
52 
53 struct kroute_node {
54 	RB_ENTRY(kroute_node)	 entry;
55 	struct kroute		 r;
56 	struct kroute_node	*next;
57 };
58 
59 struct kroute6_node {
60 	RB_ENTRY(kroute6_node)	 entry;
61 	struct kroute6		 r;
62 	struct kroute6_node	*next;
63 };
64 
65 struct knexthop_node {
66 	RB_ENTRY(knexthop_node)	 entry;
67 	struct bgpd_addr	 nexthop;
68 	void			*kroute;
69 };
70 
71 struct kredist_node {
72 	RB_ENTRY(kredist_node)	 entry;
73 	struct bgpd_addr	 prefix;
74 	u_int64_t		 rd;
75 	u_int8_t		 prefixlen;
76 	u_int8_t		 dynamic;
77 };
78 
79 struct kif_kr {
80 	LIST_ENTRY(kif_kr)	 entry;
81 	struct kroute_node	*kr;
82 };
83 
84 struct kif_kr6 {
85 	LIST_ENTRY(kif_kr6)	 entry;
86 	struct kroute6_node	*kr;
87 };
88 
89 LIST_HEAD(kif_kr_head, kif_kr);
90 LIST_HEAD(kif_kr6_head, kif_kr6);
91 
92 struct kif_node {
93 	RB_ENTRY(kif_node)	 entry;
94 	struct kif		 k;
95 	struct kif_kr_head	 kroute_l;
96 	struct kif_kr6_head	 kroute6_l;
97 };
98 
99 int	ktable_new(u_int, u_int, char *, int, u_int8_t);
100 void	ktable_free(u_int, u_int8_t);
101 void	ktable_destroy(struct ktable *, u_int8_t);
102 struct ktable	*ktable_get(u_int);
103 
104 int	kr4_change(struct ktable *, struct kroute_full *, u_int8_t);
105 int	kr6_change(struct ktable *, struct kroute_full *, u_int8_t);
106 int	krVPN4_change(struct ktable *, struct kroute_full *, u_int8_t);
107 int	krVPN6_change(struct ktable *, struct kroute_full *, u_int8_t);
108 int	kr4_delete(struct ktable *, struct kroute_full *, u_int8_t);
109 int	kr6_delete(struct ktable *, struct kroute_full *, u_int8_t);
110 int	krVPN4_delete(struct ktable *, struct kroute_full *, u_int8_t);
111 int	krVPN6_delete(struct ktable *, struct kroute_full *, u_int8_t);
112 void	kr_net_delete(struct network *);
113 int	kr_net_match(struct ktable *, struct network_config *, u_int16_t, int);
114 struct network *kr_net_find(struct ktable *, struct network *);
115 void	kr_net_clear(struct ktable *);
116 void	kr_redistribute(int, struct ktable *, struct kroute *);
117 void	kr_redistribute6(int, struct ktable *, struct kroute6 *);
118 struct kroute_full *kr_tofull(struct kroute *);
119 struct kroute_full *kr6_tofull(struct kroute6 *);
120 int	kroute_compare(struct kroute_node *, struct kroute_node *);
121 int	kroute6_compare(struct kroute6_node *, struct kroute6_node *);
122 int	knexthop_compare(struct knexthop_node *, struct knexthop_node *);
123 int	kredist_compare(struct kredist_node *, struct kredist_node *);
124 int	kif_compare(struct kif_node *, struct kif_node *);
125 void	kr_fib_update_prio(u_int, u_int8_t);
126 
127 struct kroute_node	*kroute_find(struct ktable *, in_addr_t, u_int8_t,
128 			    u_int8_t);
129 struct kroute_node	*kroute_matchgw(struct kroute_node *,
130 			    struct sockaddr_in *);
131 int			 kroute_insert(struct ktable *, struct kroute_node *);
132 int			 kroute_remove(struct ktable *, struct kroute_node *);
133 void			 kroute_clear(struct ktable *);
134 
135 struct kroute6_node	*kroute6_find(struct ktable *, const struct in6_addr *,
136 			    u_int8_t, u_int8_t);
137 struct kroute6_node	*kroute6_matchgw(struct kroute6_node *,
138 			    struct sockaddr_in6 *);
139 int			 kroute6_insert(struct ktable *, struct kroute6_node *);
140 int			 kroute6_remove(struct ktable *, struct kroute6_node *);
141 void			 kroute6_clear(struct ktable *);
142 
143 struct knexthop_node	*knexthop_find(struct ktable *, struct bgpd_addr *);
144 int			 knexthop_insert(struct ktable *,
145 			    struct knexthop_node *);
146 int			 knexthop_remove(struct ktable *,
147 			    struct knexthop_node *);
148 void			 knexthop_clear(struct ktable *);
149 
150 struct kif_node		*kif_find(int);
151 int			 kif_insert(struct kif_node *);
152 int			 kif_remove(struct kif_node *, u_int);
153 void			 kif_clear(u_int);
154 
155 int			 kif_kr_insert(struct kroute_node *);
156 int			 kif_kr_remove(struct kroute_node *);
157 
158 int			 kif_kr6_insert(struct kroute6_node *);
159 int			 kif_kr6_remove(struct kroute6_node *);
160 
161 int			 kroute_validate(struct kroute *);
162 int			 kroute6_validate(struct kroute6 *);
163 void			 knexthop_validate(struct ktable *,
164 			    struct knexthop_node *);
165 void			 knexthop_track(struct ktable *, void *);
166 void			 knexthop_send_update(struct knexthop_node *);
167 struct kroute_node	*kroute_match(struct ktable *, in_addr_t, int);
168 struct kroute6_node	*kroute6_match(struct ktable *, struct in6_addr *, int);
169 void			 kroute_detach_nexthop(struct ktable *,
170 			    struct knexthop_node *);
171 
172 int		protect_lo(struct ktable *);
173 u_int8_t	prefixlen_classful(in_addr_t);
174 u_int8_t	mask2prefixlen(in_addr_t);
175 u_int8_t	mask2prefixlen6(struct sockaddr_in6 *);
176 uint64_t	ift2ifm(uint8_t);
177 const char	*get_media_descr(uint64_t);
178 const char	*get_linkstate(uint8_t, int);
179 void		get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
180 void		if_change(u_short, int, struct if_data *, u_int);
181 void		if_announce(void *, u_int);
182 
183 int		send_rtmsg(int, int, struct ktable *, struct kroute *,
184 		    u_int8_t);
185 int		send_rt6msg(int, int, struct ktable *, struct kroute6 *,
186 		    u_int8_t);
187 int		dispatch_rtmsg(u_int);
188 int		fetchtable(struct ktable *, u_int8_t);
189 int		fetchifs(int);
190 int		dispatch_rtmsg_addr(struct rt_msghdr *,
191 		    struct sockaddr *[RTAX_MAX], struct ktable *);
192 
193 RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare)
194 RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare)
195 
196 RB_PROTOTYPE(kroute6_tree, kroute6_node, entry, kroute6_compare)
197 RB_GENERATE(kroute6_tree, kroute6_node, entry, kroute6_compare)
198 
199 RB_PROTOTYPE(knexthop_tree, knexthop_node, entry, knexthop_compare)
200 RB_GENERATE(knexthop_tree, knexthop_node, entry, knexthop_compare)
201 
202 RB_PROTOTYPE(kredist_tree, kredist_node, entry, kredist_compare)
203 RB_GENERATE(kredist_tree, kredist_node, entry, kredist_compare)
204 
205 RB_HEAD(kif_tree, kif_node)		kit;
RB_PROTOTYPE(kif_tree,kif_node,entry,kif_compare)206 RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare)
207 RB_GENERATE(kif_tree, kif_node, entry, kif_compare)
208 
209 #define KT2KNT(x)	(&(ktable_get((x)->nhtableid)->knt))
210 
211 /*
212  * exported functions
213  */
214 
215 int
216 kr_init(int *fd)
217 {
218 	int		opt = 0, rcvbuf, default_rcvbuf;
219 	unsigned int	tid = RTABLE_ANY;
220 	socklen_t	optlen;
221 
222 	if ((kr_state.fd = socket(AF_ROUTE,
223 	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) {
224 		log_warn("%s: socket", __func__);
225 		return (-1);
226 	}
227 
228 	/* not interested in my own messages */
229 	if (setsockopt(kr_state.fd, SOL_SOCKET, SO_USELOOPBACK,
230 	    &opt, sizeof(opt)) == -1)
231 		log_warn("%s: setsockopt", __func__);	/* not fatal */
232 
233 	/* grow receive buffer, don't wanna miss messages */
234 	optlen = sizeof(default_rcvbuf);
235 	if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
236 	    &default_rcvbuf, &optlen) == -1)
237 		log_warn("%s: getsockopt SOL_SOCKET SO_RCVBUF", __func__);
238 	else
239 		for (rcvbuf = MAX_RTSOCK_BUF;
240 		    rcvbuf > default_rcvbuf &&
241 		    setsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF,
242 		    &rcvbuf, sizeof(rcvbuf)) == -1 && errno == ENOBUFS;
243 		    rcvbuf /= 2)
244 			;	/* nothing */
245 
246 	if (setsockopt(kr_state.fd, AF_ROUTE, ROUTE_TABLEFILTER, &tid,
247 	    sizeof(tid)) == -1) {
248 		log_warn("%s: setsockopt AF_ROUTE ROUTE_TABLEFILTER", __func__);
249 		return (-1);
250 	}
251 
252 	kr_state.pid = getpid();
253 	kr_state.rtseq = 1;
254 
255 	RB_INIT(&kit);
256 
257 	if (fetchifs(0) == -1)
258 		return (-1);
259 
260 	*fd = kr_state.fd;
261 	return (0);
262 }
263 
264 int
ktable_new(u_int rtableid,u_int rdomid,char * name,int fs,u_int8_t fib_prio)265 ktable_new(u_int rtableid, u_int rdomid, char *name, int fs, u_int8_t fib_prio)
266 {
267 	struct ktable	**xkrt;
268 	struct ktable	 *kt;
269 	size_t		  oldsize;
270 
271 	/* resize index table if needed */
272 	if (rtableid >= krt_size) {
273 		oldsize = sizeof(struct ktable *) * krt_size;
274 		if ((xkrt = reallocarray(krt, rtableid + 1,
275 		    sizeof(struct ktable *))) == NULL) {
276 			log_warn("%s", __func__);
277 			return (-1);
278 		}
279 		krt = xkrt;
280 		krt_size = rtableid + 1;
281 		bzero((char *)krt + oldsize,
282 		    krt_size * sizeof(struct ktable *) - oldsize);
283 	}
284 
285 	if (krt[rtableid])
286 		fatalx("ktable_new: table already exists.");
287 
288 	/* allocate new element */
289 	kt = krt[rtableid] = calloc(1, sizeof(struct ktable));
290 	if (kt == NULL) {
291 		log_warn("%s", __func__);
292 		return (-1);
293 	}
294 
295 	/* initialize structure ... */
296 	strlcpy(kt->descr, name, sizeof(kt->descr));
297 	RB_INIT(&kt->krt);
298 	RB_INIT(&kt->krt6);
299 	RB_INIT(&kt->knt);
300 	TAILQ_INIT(&kt->krn);
301 	kt->fib_conf = kt->fib_sync = fs;
302 	kt->rtableid = rtableid;
303 	kt->nhtableid = rdomid;
304 	/* bump refcount of rdomain table for the nexthop lookups */
305 	ktable_get(kt->nhtableid)->nhrefcnt++;
306 
307 	/* ... and load it */
308 	if (fetchtable(kt, fib_prio) == -1)
309 		return (-1);
310 	if (protect_lo(kt) == -1)
311 		return (-1);
312 
313 	/* everything is up and running */
314 	kt->state = RECONF_REINIT;
315 	log_debug("%s: %s with rtableid %d rdomain %d", __func__, name,
316 	    rtableid, rdomid);
317 	return (0);
318 }
319 
320 void
ktable_free(u_int rtableid,u_int8_t fib_prio)321 ktable_free(u_int rtableid, u_int8_t fib_prio)
322 {
323 	struct ktable	*kt, *nkt;
324 
325 	if ((kt = ktable_get(rtableid)) == NULL)
326 		return;
327 
328 	/* decouple from kernel, no new routes will be entered from here */
329 	kr_fib_decouple(kt->rtableid, fib_prio);
330 
331 	/* first unhook from the nexthop table */
332 	nkt = ktable_get(kt->nhtableid);
333 	nkt->nhrefcnt--;
334 
335 	/*
336 	 * Evil little details:
337 	 *   If kt->nhrefcnt > 0 then kt == nkt and nothing needs to be done.
338 	 *   If kt != nkt then kt->nhrefcnt must be 0 and kt must be killed.
339 	 *   If nkt is no longer referenced it must be killed (possible double
340 	 *   free so check that kt != nkt).
341 	 */
342 	if (kt != nkt && nkt->nhrefcnt <= 0)
343 		ktable_destroy(nkt, fib_prio);
344 	if (kt->nhrefcnt <= 0)
345 		ktable_destroy(kt, fib_prio);
346 }
347 
348 void
ktable_destroy(struct ktable * kt,u_int8_t fib_prio)349 ktable_destroy(struct ktable *kt, u_int8_t fib_prio)
350 {
351 	/* decouple just to be sure, does not hurt */
352 	kr_fib_decouple(kt->rtableid, fib_prio);
353 
354 	log_debug("%s: freeing ktable %s rtableid %u", __func__, kt->descr,
355 	    kt->rtableid);
356 	/* only clear nexthop table if it is the main rdomain table */
357 	if (kt->rtableid == kt->nhtableid)
358 		knexthop_clear(kt);
359 	kroute_clear(kt);
360 	kroute6_clear(kt);
361 	kr_net_clear(kt);
362 
363 	krt[kt->rtableid] = NULL;
364 	free(kt);
365 }
366 
367 struct ktable *
ktable_get(u_int rtableid)368 ktable_get(u_int rtableid)
369 {
370 	if (rtableid >= krt_size)
371 		return (NULL);
372 	return (krt[rtableid]);
373 }
374 
375 int
ktable_update(u_int rtableid,char * name,int flags,u_int8_t fib_prio)376 ktable_update(u_int rtableid, char *name, int flags, u_int8_t fib_prio)
377 {
378 	struct ktable	*kt, *rkt;
379 	u_int		 rdomid;
380 
381 	if (!ktable_exists(rtableid, &rdomid))
382 		fatalx("King Bula lost a table");	/* may not happen */
383 
384 	if (rdomid != rtableid || flags & F_RIB_NOFIB) {
385 		rkt = ktable_get(rdomid);
386 		if (rkt == NULL) {
387 			char buf[32];
388 			snprintf(buf, sizeof(buf), "rdomain_%d", rdomid);
389 			if (ktable_new(rdomid, rdomid, buf, 0, fib_prio))
390 				return (-1);
391 		} else {
392 			/* there is no need for full fib synchronisation if
393 			 * the table is only used for nexthop lookups.
394 			 */
395 			if (rkt->state == RECONF_DELETE) {
396 				rkt->fib_conf = 0;
397 				rkt->state = RECONF_KEEP;
398 			}
399 		}
400 	}
401 
402 	if (flags & (F_RIB_NOFIB | F_RIB_NOEVALUATE))
403 		/* only rdomain table must exist */
404 		return (0);
405 
406 	kt = ktable_get(rtableid);
407 	if (kt == NULL) {
408 		if (ktable_new(rtableid, rdomid, name,
409 		    !(flags & F_RIB_NOFIBSYNC), fib_prio))
410 			return (-1);
411 	} else {
412 		/* fib sync has higher preference then no sync */
413 		if (kt->state == RECONF_DELETE) {
414 			kt->fib_conf = !(flags & F_RIB_NOFIBSYNC);
415 			kt->state = RECONF_KEEP;
416 		} else if (!kt->fib_conf)
417 			kt->fib_conf = !(flags & F_RIB_NOFIBSYNC);
418 
419 		strlcpy(kt->descr, name, sizeof(kt->descr));
420 	}
421 	return (0);
422 }
423 
424 int
ktable_exists(u_int rtableid,u_int * rdomid)425 ktable_exists(u_int rtableid, u_int *rdomid)
426 {
427 	size_t			 len;
428 	struct rt_tableinfo	 info;
429 	int			 mib[6];
430 
431 	mib[0] = CTL_NET;
432 	mib[1] = PF_ROUTE;
433 	mib[2] = 0;
434 	mib[3] = 0;
435 	mib[4] = NET_RT_TABLE;
436 	mib[5] = rtableid;
437 
438 	len = sizeof(info);
439 	if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) {
440 		if (errno == ENOENT)
441 			/* table nonexistent */
442 			return (0);
443 		log_warn("%s: sysctl", __func__);
444 		/* must return 0 so that the table is considered non-existent */
445 		return (0);
446 	}
447 	if (rdomid)
448 		*rdomid = info.rti_domainid;
449 	return (1);
450 }
451 
452 int
kr_change(u_int rtableid,struct kroute_full * kl,u_int8_t fib_prio)453 kr_change(u_int rtableid, struct kroute_full *kl, u_int8_t fib_prio)
454 {
455 	struct ktable		*kt;
456 
457 	if ((kt = ktable_get(rtableid)) == NULL)
458 		/* too noisy during reloads, just ignore */
459 		return (0);
460 	switch (kl->prefix.aid) {
461 	case AID_INET:
462 		return (kr4_change(kt, kl, fib_prio));
463 	case AID_INET6:
464 		return (kr6_change(kt, kl, fib_prio));
465 	case AID_VPN_IPv4:
466 		return (krVPN4_change(kt, kl, fib_prio));
467 	case AID_VPN_IPv6:
468 		return (krVPN6_change(kt, kl, fib_prio));
469 	}
470 	log_warnx("%s: not handled AID", __func__);
471 	return (-1);
472 }
473 
474 int
kr4_change(struct ktable * kt,struct kroute_full * kl,u_int8_t fib_prio)475 kr4_change(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
476 {
477 	struct kroute_node	*kr;
478 	int			 action = RTM_ADD;
479 	u_int16_t		 labelid;
480 
481 	/* for blackhole and reject routes nexthop needs to be 127.0.0.1 */
482 	if (kl->flags & (F_BLACKHOLE|F_REJECT))
483 		kl->nexthop.v4.s_addr = htonl(INADDR_LOOPBACK);
484 	/* nexthop within 127/8 -> ignore silently */
485 	else if ((kl->nexthop.v4.s_addr & htonl(IN_CLASSA_NET)) ==
486 	    htonl(INADDR_LOOPBACK & IN_CLASSA_NET))
487 		return (0);
488 
489 	labelid = rtlabel_name2id(kl->label);
490 
491 	if ((kr = kroute_find(kt, kl->prefix.v4.s_addr, kl->prefixlen,
492 	    fib_prio)) != NULL)
493 		action = RTM_CHANGE;
494 
495 	if (action == RTM_ADD) {
496 		if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
497 			log_warn("%s", __func__);
498 			return (-1);
499 		}
500 		kr->r.prefix.s_addr = kl->prefix.v4.s_addr;
501 		kr->r.prefixlen = kl->prefixlen;
502 		kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr;
503 		kr->r.flags = kl->flags | F_BGPD_INSERTED;
504 		kr->r.priority = fib_prio;
505 		kr->r.labelid = labelid;
506 
507 		if (kroute_insert(kt, kr) == -1) {
508 			free(kr);
509 			return (-1);
510 		}
511 	} else {
512 		kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr;
513 		rtlabel_unref(kr->r.labelid);
514 		kr->r.labelid = labelid;
515 		if (kl->flags & F_BLACKHOLE)
516 			kr->r.flags |= F_BLACKHOLE;
517 		else
518 			kr->r.flags &= ~F_BLACKHOLE;
519 		if (kl->flags & F_REJECT)
520 			kr->r.flags |= F_REJECT;
521 		else
522 			kr->r.flags &= ~F_REJECT;
523 	}
524 
525 	if (send_rtmsg(kr_state.fd, action, kt, &kr->r, fib_prio) == -1)
526 		return (-1);
527 
528 	return (0);
529 }
530 
531 int
kr6_change(struct ktable * kt,struct kroute_full * kl,u_int8_t fib_prio)532 kr6_change(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
533 {
534 	struct kroute6_node	*kr6;
535 	struct in6_addr		 lo6 = IN6ADDR_LOOPBACK_INIT;
536 	int			 action = RTM_ADD;
537 	u_int16_t		 labelid;
538 
539 	/* for blackhole and reject routes nexthop needs to be ::1 */
540 	if (kl->flags & (F_BLACKHOLE|F_REJECT))
541 		bcopy(&lo6, &kl->nexthop.v6, sizeof(kl->nexthop.v6));
542 	/* nexthop to loopback -> ignore silently */
543 	else if (IN6_IS_ADDR_LOOPBACK(&kl->nexthop.v6))
544 		return (0);
545 
546 	labelid = rtlabel_name2id(kl->label);
547 
548 	if ((kr6 = kroute6_find(kt, &kl->prefix.v6, kl->prefixlen, fib_prio)) !=
549 	    NULL)
550 		action = RTM_CHANGE;
551 
552 	if (action == RTM_ADD) {
553 		if ((kr6 = calloc(1, sizeof(struct kroute6_node))) == NULL) {
554 			log_warn("%s", __func__);
555 			return (-1);
556 		}
557 		memcpy(&kr6->r.prefix, &kl->prefix.v6, sizeof(struct in6_addr));
558 		kr6->r.prefixlen = kl->prefixlen;
559 		memcpy(&kr6->r.nexthop, &kl->nexthop.v6,
560 		    sizeof(struct in6_addr));
561 		kr6->r.flags = kl->flags | F_BGPD_INSERTED;
562 		kr6->r.priority = fib_prio;
563 		kr6->r.labelid = labelid;
564 
565 		if (kroute6_insert(kt, kr6) == -1) {
566 			free(kr6);
567 			return (-1);
568 		}
569 	} else {
570 		memcpy(&kr6->r.nexthop, &kl->nexthop.v6,
571 		    sizeof(struct in6_addr));
572 		rtlabel_unref(kr6->r.labelid);
573 		kr6->r.labelid = labelid;
574 		if (kl->flags & F_BLACKHOLE)
575 			kr6->r.flags |= F_BLACKHOLE;
576 		else
577 			kr6->r.flags &= ~F_BLACKHOLE;
578 		if (kl->flags & F_REJECT)
579 			kr6->r.flags |= F_REJECT;
580 		else
581 			kr6->r.flags &= ~F_REJECT;
582 	}
583 
584 	if (send_rt6msg(kr_state.fd, action, kt, &kr6->r, fib_prio) == -1)
585 		return (-1);
586 
587 	return (0);
588 }
589 
590 int
krVPN4_change(struct ktable * kt,struct kroute_full * kl,u_int8_t fib_prio)591 krVPN4_change(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
592 {
593 	struct kroute_node	*kr;
594 	int			 action = RTM_ADD;
595 	u_int32_t		 mplslabel = 0;
596 	u_int16_t		 labelid;
597 
598 	/* nexthop within 127/8 -> ignore silently */
599 	if ((kl->nexthop.v4.s_addr & htonl(IN_CLASSA_NET)) ==
600 	    htonl(INADDR_LOOPBACK & IN_CLASSA_NET))
601 		return (0);
602 
603 	/* only single MPLS label are supported for now */
604 	if (kl->prefix.labellen != 3) {
605 		log_warnx("%s: %s/%u has not a single label", __func__,
606 		    log_addr(&kl->prefix), kl->prefixlen);
607 		return (0);
608 	}
609 	mplslabel = (kl->prefix.labelstack[0] << 24) |
610 	    (kl->prefix.labelstack[1] << 16) |
611 	    (kl->prefix.labelstack[2] << 8);
612 	mplslabel = htonl(mplslabel);
613 
614 	labelid = rtlabel_name2id(kl->label);
615 
616 	/* for blackhole and reject routes nexthop needs to be 127.0.0.1 */
617 	if (kl->flags & (F_BLACKHOLE|F_REJECT))
618 		kl->nexthop.v4.s_addr = htonl(INADDR_LOOPBACK);
619 
620 	if ((kr = kroute_find(kt, kl->prefix.v4.s_addr, kl->prefixlen,
621 	    fib_prio)) != NULL)
622 		action = RTM_CHANGE;
623 
624 	if (action == RTM_ADD) {
625 		if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
626 			log_warn("%s", __func__);
627 			return (-1);
628 		}
629 		kr->r.prefix.s_addr = kl->prefix.v4.s_addr;
630 		kr->r.prefixlen = kl->prefixlen;
631 		kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr;
632 		kr->r.flags = kl->flags | F_BGPD_INSERTED | F_MPLS;
633 		kr->r.priority = fib_prio;
634 		kr->r.labelid = labelid;
635 		kr->r.mplslabel = mplslabel;
636 		kr->r.ifindex = kl->ifindex;
637 
638 		if (kroute_insert(kt, kr) == -1) {
639 			free(kr);
640 			return (-1);
641 		}
642 	} else {
643 		kr->r.mplslabel = mplslabel;
644 		kr->r.ifindex = kl->ifindex;
645 		kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr;
646 		rtlabel_unref(kr->r.labelid);
647 		kr->r.labelid = labelid;
648 		if (kl->flags & F_BLACKHOLE)
649 			kr->r.flags |= F_BLACKHOLE;
650 		else
651 			kr->r.flags &= ~F_BLACKHOLE;
652 		if (kl->flags & F_REJECT)
653 			kr->r.flags |= F_REJECT;
654 		else
655 			kr->r.flags &= ~F_REJECT;
656 	}
657 
658 	if (send_rtmsg(kr_state.fd, action, kt, &kr->r, fib_prio) == -1)
659 		return (-1);
660 
661 	return (0);
662 }
663 
664 int
krVPN6_change(struct ktable * kt,struct kroute_full * kl,u_int8_t fib_prio)665 krVPN6_change(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
666 {
667 	struct kroute6_node	*kr6;
668 	struct in6_addr		 lo6 = IN6ADDR_LOOPBACK_INIT;
669 	int			 action = RTM_ADD;
670 	u_int32_t		 mplslabel = 0;
671 	u_int16_t		 labelid;
672 
673 	/* nexthop to loopback -> ignore silently */
674 	if (IN6_IS_ADDR_LOOPBACK(&kl->nexthop.v6))
675 		return (0);
676 
677 	/* only single MPLS label are supported for now */
678 	if (kl->prefix.labellen != 3) {
679 		log_warnx("%s: %s/%u has not a single label", __func__,
680 		    log_addr(&kl->prefix), kl->prefixlen);
681 		return (0);
682 	}
683 	mplslabel = (kl->prefix.labelstack[0] << 24) |
684 	    (kl->prefix.labelstack[1] << 16) |
685 	    (kl->prefix.labelstack[2] << 8);
686 	mplslabel = htonl(mplslabel);
687 
688 	/* for blackhole and reject routes nexthop needs to be ::1 */
689 	if (kl->flags & (F_BLACKHOLE|F_REJECT))
690 		bcopy(&lo6, &kl->nexthop.v6, sizeof(kl->nexthop.v6));
691 
692 	labelid = rtlabel_name2id(kl->label);
693 
694 	if ((kr6 = kroute6_find(kt, &kl->prefix.v6, kl->prefixlen,
695 	    fib_prio)) != NULL)
696 		action = RTM_CHANGE;
697 
698 	if (action == RTM_ADD) {
699 		if ((kr6 = calloc(1, sizeof(struct kroute6_node))) == NULL) {
700 			log_warn("%s", __func__);
701 			return (-1);
702 		}
703 		memcpy(&kr6->r.prefix, &kl->prefix.v6, sizeof(struct in6_addr));
704 		kr6->r.prefixlen = kl->prefixlen;
705 		memcpy(&kr6->r.nexthop, &kl->nexthop.v6,
706 		    sizeof(struct in6_addr));
707 		kr6->r.flags = kl->flags | F_BGPD_INSERTED | F_MPLS;
708 		kr6->r.priority = fib_prio;
709 		kr6->r.labelid = labelid;
710 		kr6->r.mplslabel = mplslabel;
711 		kr6->r.ifindex = kl->ifindex;
712 
713 		if (kroute6_insert(kt, kr6) == -1) {
714 			free(kr6);
715 			return (-1);
716 		}
717 	} else {
718 		kr6->r.mplslabel = mplslabel;
719 		kr6->r.ifindex = kl->ifindex;
720 		memcpy(&kr6->r.nexthop, &kl->nexthop.v6,
721 		    sizeof(struct in6_addr));
722 		rtlabel_unref(kr6->r.labelid);
723 		kr6->r.labelid = labelid;
724 		if (kl->flags & F_BLACKHOLE)
725 			kr6->r.flags |= F_BLACKHOLE;
726 		else
727 			kr6->r.flags &= ~F_BLACKHOLE;
728 		if (kl->flags & F_REJECT)
729 			kr6->r.flags |= F_REJECT;
730 		else
731 			kr6->r.flags &= ~F_REJECT;
732 	}
733 
734 	if (send_rt6msg(kr_state.fd, action, kt, &kr6->r, fib_prio) == -1)
735 		return (-1);
736 
737 	return (0);
738 }
739 
740 int
kr_delete(u_int rtableid,struct kroute_full * kl,u_int8_t fib_prio)741 kr_delete(u_int rtableid, struct kroute_full *kl, u_int8_t fib_prio)
742 {
743 	struct ktable		*kt;
744 
745 	if ((kt = ktable_get(rtableid)) == NULL)
746 		/* too noisy during reloads, just ignore */
747 		return (0);
748 
749 	switch (kl->prefix.aid) {
750 	case AID_INET:
751 		return (kr4_delete(kt, kl, fib_prio));
752 	case AID_INET6:
753 		return (kr6_delete(kt, kl, fib_prio));
754 	case AID_VPN_IPv4:
755 		return (krVPN4_delete(kt, kl, fib_prio));
756 	case AID_VPN_IPv6:
757 		return (krVPN6_delete(kt, kl, fib_prio));
758 	}
759 	log_warnx("%s: not handled AID", __func__);
760 	return (-1);
761 }
762 
763 int
kr_flush(u_int rtableid)764 kr_flush(u_int rtableid)
765 {
766 	struct ktable		*kt;
767 	struct kroute_node	*kr, *next;
768 	struct kroute6_node	*kr6, *next6;
769 
770 	if ((kt = ktable_get(rtableid)) == NULL)
771 		/* too noisy during reloads, just ignore */
772 		return (0);
773 
774 	RB_FOREACH_SAFE(kr, kroute_tree, &kt->krt, next)
775 		if ((kr->r.flags & F_BGPD_INSERTED)) {
776 			if (kt->fib_sync)	/* coupled */
777 				send_rtmsg(kr_state.fd, RTM_DELETE, kt,
778 				    &kr->r, kr->r.priority);
779 			rtlabel_unref(kr->r.labelid);
780 
781 			if (kroute_remove(kt, kr) == -1)
782 				return (-1);
783 		}
784 	RB_FOREACH_SAFE(kr6, kroute6_tree, &kt->krt6, next6)
785 		if ((kr6->r.flags & F_BGPD_INSERTED)) {
786 			if (kt->fib_sync)	/* coupled */
787 				send_rt6msg(kr_state.fd, RTM_DELETE, kt,
788 				    &kr6->r, kr6->r.priority);
789 			rtlabel_unref(kr6->r.labelid);
790 
791 			if (kroute6_remove(kt, kr6) == -1)
792 				return (-1);
793 		}
794 
795 	kt->fib_sync = 0;
796 	return (0);
797 }
798 
799 int
kr4_delete(struct ktable * kt,struct kroute_full * kl,u_int8_t fib_prio)800 kr4_delete(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
801 {
802 	struct kroute_node	*kr;
803 
804 	if ((kr = kroute_find(kt, kl->prefix.v4.s_addr, kl->prefixlen,
805 	    fib_prio)) == NULL)
806 		return (0);
807 
808 	if (!(kr->r.flags & F_BGPD_INSERTED))
809 		return (0);
810 
811 	if (send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r, fib_prio) == -1)
812 		return (-1);
813 
814 	rtlabel_unref(kr->r.labelid);
815 
816 	if (kroute_remove(kt, kr) == -1)
817 		return (-1);
818 
819 	return (0);
820 }
821 
822 int
kr6_delete(struct ktable * kt,struct kroute_full * kl,u_int8_t fib_prio)823 kr6_delete(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
824 {
825 	struct kroute6_node	*kr6;
826 
827 	if ((kr6 = kroute6_find(kt, &kl->prefix.v6, kl->prefixlen, fib_prio)) ==
828 	    NULL)
829 		return (0);
830 
831 	if (!(kr6->r.flags & F_BGPD_INSERTED))
832 		return (0);
833 
834 	if (send_rt6msg(kr_state.fd, RTM_DELETE, kt, &kr6->r, fib_prio) == -1)
835 		return (-1);
836 
837 	rtlabel_unref(kr6->r.labelid);
838 
839 	if (kroute6_remove(kt, kr6) == -1)
840 		return (-1);
841 
842 	return (0);
843 }
844 
845 int
krVPN4_delete(struct ktable * kt,struct kroute_full * kl,u_int8_t fib_prio)846 krVPN4_delete(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
847 {
848 	struct kroute_node	*kr;
849 
850 	if ((kr = kroute_find(kt, kl->prefix.v4.s_addr, kl->prefixlen,
851 	    fib_prio)) == NULL)
852 		return (0);
853 
854 	if (!(kr->r.flags & F_BGPD_INSERTED))
855 		return (0);
856 
857 	if (send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r, fib_prio) == -1)
858 		return (-1);
859 
860 	rtlabel_unref(kr->r.labelid);
861 
862 	if (kroute_remove(kt, kr) == -1)
863 		return (-1);
864 
865 	return (0);
866 }
867 
868 int
krVPN6_delete(struct ktable * kt,struct kroute_full * kl,u_int8_t fib_prio)869 krVPN6_delete(struct ktable *kt, struct kroute_full *kl, u_int8_t fib_prio)
870 {
871 	struct kroute6_node	*kr6;
872 
873 	if ((kr6 = kroute6_find(kt, &kl->prefix.v6, kl->prefixlen,
874 	    fib_prio)) == NULL)
875 		return (0);
876 
877 	if (!(kr6->r.flags & F_BGPD_INSERTED))
878 		return (0);
879 
880 	if (send_rt6msg(kr_state.fd, RTM_DELETE, kt, &kr6->r, fib_prio) == -1)
881 		return (-1);
882 
883 	rtlabel_unref(kr6->r.labelid);
884 
885 	if (kroute6_remove(kt, kr6) == -1)
886 		return (-1);
887 
888 	return (0);
889 }
890 
891 void
kr_shutdown(u_int8_t fib_prio,u_int rdomain)892 kr_shutdown(u_int8_t fib_prio, u_int rdomain)
893 {
894 	u_int	i;
895 
896 	for (i = krt_size; i > 0; i--)
897 		ktable_free(i - 1, fib_prio);
898 	kif_clear(rdomain);
899 	free(krt);
900 }
901 
902 void
kr_fib_couple(u_int rtableid,u_int8_t fib_prio)903 kr_fib_couple(u_int rtableid, u_int8_t fib_prio)
904 {
905 	struct ktable		*kt;
906 	struct kroute_node	*kr;
907 	struct kroute6_node	*kr6;
908 
909 	if ((kt = ktable_get(rtableid)) == NULL)  /* table does not exist */
910 		return;
911 
912 	if (kt->fib_sync)	/* already coupled */
913 		return;
914 
915 	kt->fib_sync = 1;
916 
917 	RB_FOREACH(kr, kroute_tree, &kt->krt)
918 		if ((kr->r.flags & F_BGPD_INSERTED))
919 			send_rtmsg(kr_state.fd, RTM_ADD, kt, &kr->r, fib_prio);
920 	RB_FOREACH(kr6, kroute6_tree, &kt->krt6)
921 		if ((kr6->r.flags & F_BGPD_INSERTED))
922 			send_rt6msg(kr_state.fd, RTM_ADD, kt, &kr6->r,
923 			    fib_prio);
924 
925 	log_info("kernel routing table %u (%s) coupled", kt->rtableid,
926 	    kt->descr);
927 }
928 
929 void
kr_fib_couple_all(u_int8_t fib_prio)930 kr_fib_couple_all(u_int8_t fib_prio)
931 {
932 	u_int	 i;
933 
934 	for (i = krt_size; i > 0; i--)
935 		kr_fib_couple(i - 1, fib_prio);
936 }
937 
938 void
kr_fib_decouple(u_int rtableid,u_int8_t fib_prio)939 kr_fib_decouple(u_int rtableid, u_int8_t fib_prio)
940 {
941 	struct ktable		*kt;
942 	struct kroute_node	*kr;
943 	struct kroute6_node	*kr6;
944 
945 	if ((kt = ktable_get(rtableid)) == NULL)  /* table does not exist */
946 		return;
947 
948 	if (!kt->fib_sync)	/* already decoupled */
949 		return;
950 
951 	RB_FOREACH(kr, kroute_tree, &kt->krt)
952 		if ((kr->r.flags & F_BGPD_INSERTED))
953 			send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r,
954 			    fib_prio);
955 	RB_FOREACH(kr6, kroute6_tree, &kt->krt6)
956 		if ((kr6->r.flags & F_BGPD_INSERTED))
957 			send_rt6msg(kr_state.fd, RTM_DELETE, kt, &kr6->r,
958 			    fib_prio);
959 
960 	kt->fib_sync = 0;
961 
962 	log_info("kernel routing table %u (%s) decoupled", kt->rtableid,
963 	    kt->descr);
964 }
965 
966 void
kr_fib_decouple_all(u_int8_t fib_prio)967 kr_fib_decouple_all(u_int8_t fib_prio)
968 {
969 	u_int	 i;
970 
971 	for (i = krt_size; i > 0; i--)
972 		kr_fib_decouple(i - 1, fib_prio);
973 }
974 
975 void
kr_fib_update_prio(u_int rtableid,u_int8_t fib_prio)976 kr_fib_update_prio(u_int rtableid, u_int8_t fib_prio)
977 {
978 	struct ktable		*kt;
979 	struct kroute_node	*kr;
980 	struct kroute6_node	*kr6;
981 
982 	if ((kt = ktable_get(rtableid)) == NULL)  /* table does not exist */
983 		return;
984 
985 	RB_FOREACH(kr, kroute_tree, &kt->krt)
986 		if ((kr->r.flags & F_BGPD_INSERTED))
987 			kr->r.priority = fib_prio;
988 
989 	RB_FOREACH(kr6, kroute6_tree, &kt->krt6)
990 		if ((kr6->r.flags & F_BGPD_INSERTED))
991 			kr6->r.priority = fib_prio;
992 }
993 
994 void
kr_fib_update_prio_all(u_int8_t fib_prio)995 kr_fib_update_prio_all(u_int8_t fib_prio)
996 {
997 	u_int	 i;
998 
999 	for (i = krt_size; i > 0; i--)
1000 		kr_fib_update_prio(i - 1, fib_prio);
1001 }
1002 
1003 int
kr_dispatch_msg(u_int rdomain)1004 kr_dispatch_msg(u_int rdomain)
1005 {
1006 	return (dispatch_rtmsg(rdomain));
1007 }
1008 
1009 int
kr_nexthop_add(u_int rtableid,struct bgpd_addr * addr,struct bgpd_config * conf)1010 kr_nexthop_add(u_int rtableid, struct bgpd_addr *addr, struct bgpd_config *conf)
1011 {
1012 	struct ktable		*kt;
1013 	struct knexthop_node	*h;
1014 
1015 	if (rtableid == 0)
1016 		rtableid = conf->default_tableid;
1017 
1018 	if ((kt = ktable_get(rtableid)) == NULL) {
1019 		log_warnx("%s: non-existent rtableid %d", __func__, rtableid);
1020 		return (0);
1021 	}
1022 	if ((h = knexthop_find(kt, addr)) != NULL) {
1023 		/* should not happen... this is actually an error path */
1024 		knexthop_send_update(h);
1025 	} else {
1026 		if ((h = calloc(1, sizeof(struct knexthop_node))) == NULL) {
1027 			log_warn("%s", __func__);
1028 			return (-1);
1029 		}
1030 		memcpy(&h->nexthop, addr, sizeof(h->nexthop));
1031 
1032 		if (knexthop_insert(kt, h) == -1)
1033 			return (-1);
1034 	}
1035 
1036 	return (0);
1037 }
1038 
1039 void
kr_nexthop_delete(u_int rtableid,struct bgpd_addr * addr,struct bgpd_config * conf)1040 kr_nexthop_delete(u_int rtableid, struct bgpd_addr *addr,
1041     struct bgpd_config *conf)
1042 {
1043 	struct ktable		*kt;
1044 	struct knexthop_node	*kn;
1045 
1046 	if (rtableid == 0)
1047 		rtableid = conf->default_tableid;
1048 
1049 	if ((kt = ktable_get(rtableid)) == NULL) {
1050 		log_warnx("%s: non-existent rtableid %d", __func__,
1051 		    rtableid);
1052 		return;
1053 	}
1054 	if ((kn = knexthop_find(kt, addr)) == NULL)
1055 		return;
1056 
1057 	knexthop_remove(kt, kn);
1058 }
1059 
1060 static struct ctl_show_interface *
kr_show_interface(struct kif * kif)1061 kr_show_interface(struct kif *kif)
1062 {
1063 	static struct ctl_show_interface iface;
1064 	uint64_t ifms_type;
1065 
1066 	bzero(&iface, sizeof(iface));
1067 	strlcpy(iface.ifname, kif->ifname, sizeof(iface.ifname));
1068 
1069 	snprintf(iface.linkstate, sizeof(iface.linkstate),
1070 	    "%s", get_linkstate(kif->if_type, kif->link_state));
1071 
1072 	if ((ifms_type = ift2ifm(kif->if_type)) != 0)
1073 		snprintf(iface.media, sizeof(iface.media),
1074 		    "%s", get_media_descr(ifms_type));
1075 
1076 	iface.baudrate = kif->baudrate;
1077 	iface.rdomain = kif->rdomain;
1078 	iface.nh_reachable = kif->nh_reachable;
1079 	iface.is_up = (kif->flags & IFF_UP) == IFF_UP;
1080 
1081 	return &iface;
1082 }
1083 
1084 void
kr_show_route(struct imsg * imsg)1085 kr_show_route(struct imsg *imsg)
1086 {
1087 	struct ktable		*kt;
1088 	struct kroute_node	*kr, *kn;
1089 	struct kroute6_node	*kr6, *kn6;
1090 	struct bgpd_addr	*addr;
1091 	int			 flags;
1092 	sa_family_t		 af;
1093 	struct ctl_show_nexthop	 snh;
1094 	struct knexthop_node	*h;
1095 	struct kif_node		*kif;
1096 	u_int			 i;
1097 	u_short			 ifindex = 0;
1098 
1099 	switch (imsg->hdr.type) {
1100 	case IMSG_CTL_KROUTE:
1101 		if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(flags) +
1102 		    sizeof(af)) {
1103 			log_warnx("%s: wrong imsg len", __func__);
1104 			break;
1105 		}
1106 		kt = ktable_get(imsg->hdr.peerid);
1107 		if (kt == NULL) {
1108 			log_warnx("%s: table %u does not exist", __func__,
1109 			    imsg->hdr.peerid);
1110 			break;
1111 		}
1112 		memcpy(&flags, imsg->data, sizeof(flags));
1113 		memcpy(&af, (char *)imsg->data + sizeof(flags), sizeof(af));
1114 		if (!af || af == AF_INET)
1115 			RB_FOREACH(kr, kroute_tree, &kt->krt) {
1116 				if (flags && (kr->r.flags & flags) == 0)
1117 					continue;
1118 				kn = kr;
1119 				do {
1120 					send_imsg_session(IMSG_CTL_KROUTE,
1121 					    imsg->hdr.pid, kr_tofull(&kn->r),
1122 					    sizeof(struct kroute_full));
1123 				} while ((kn = kn->next) != NULL);
1124 			}
1125 		if (!af || af == AF_INET6)
1126 			RB_FOREACH(kr6, kroute6_tree, &kt->krt6) {
1127 				if (flags && (kr6->r.flags & flags) == 0)
1128 					continue;
1129 				kn6 = kr6;
1130 				do {
1131 					send_imsg_session(IMSG_CTL_KROUTE,
1132 					    imsg->hdr.pid, kr6_tofull(&kn6->r),
1133 					    sizeof(struct kroute_full));
1134 				} while ((kn6 = kn6->next) != NULL);
1135 			}
1136 		break;
1137 	case IMSG_CTL_KROUTE_ADDR:
1138 		if (imsg->hdr.len != IMSG_HEADER_SIZE +
1139 		    sizeof(struct bgpd_addr)) {
1140 			log_warnx("%s: wrong imsg len", __func__);
1141 			break;
1142 		}
1143 		kt = ktable_get(imsg->hdr.peerid);
1144 		if (kt == NULL) {
1145 			log_warnx("%s: table %u does not exist", __func__,
1146 			    imsg->hdr.peerid);
1147 			break;
1148 		}
1149 		addr = imsg->data;
1150 		kr = NULL;
1151 		switch (addr->aid) {
1152 		case AID_INET:
1153 			kr = kroute_match(kt, addr->v4.s_addr, 1);
1154 			if (kr != NULL)
1155 				send_imsg_session(IMSG_CTL_KROUTE,
1156 				    imsg->hdr.pid, kr_tofull(&kr->r),
1157 				    sizeof(struct kroute_full));
1158 			break;
1159 		case AID_INET6:
1160 			kr6 = kroute6_match(kt, &addr->v6, 1);
1161 			if (kr6 != NULL)
1162 				send_imsg_session(IMSG_CTL_KROUTE,
1163 				    imsg->hdr.pid, kr6_tofull(&kr6->r),
1164 				    sizeof(struct kroute_full));
1165 			break;
1166 		}
1167 		break;
1168 	case IMSG_CTL_SHOW_NEXTHOP:
1169 		kt = ktable_get(imsg->hdr.peerid);
1170 		if (kt == NULL) {
1171 			log_warnx("%s: table %u does not exist", __func__,
1172 			    imsg->hdr.peerid);
1173 			break;
1174 		}
1175 		RB_FOREACH(h, knexthop_tree, KT2KNT(kt)) {
1176 			bzero(&snh, sizeof(snh));
1177 			memcpy(&snh.addr, &h->nexthop, sizeof(snh.addr));
1178 			if (h->kroute != NULL) {
1179 				switch (h->nexthop.aid) {
1180 				case AID_INET:
1181 					kr = h->kroute;
1182 					snh.valid = kroute_validate(&kr->r);
1183 					snh.krvalid = 1;
1184 					memcpy(&snh.kr.kr4, &kr->r,
1185 					    sizeof(snh.kr.kr4));
1186 					ifindex = kr->r.ifindex;
1187 					break;
1188 				case AID_INET6:
1189 					kr6 = h->kroute;
1190 					snh.valid = kroute6_validate(&kr6->r);
1191 					snh.krvalid = 1;
1192 					memcpy(&snh.kr.kr6, &kr6->r,
1193 					    sizeof(snh.kr.kr6));
1194 					ifindex = kr6->r.ifindex;
1195 					break;
1196 				}
1197 				if ((kif = kif_find(ifindex)) != NULL)
1198 					memcpy(&snh.iface,
1199 					    kr_show_interface(&kif->k),
1200 					    sizeof(snh.iface));
1201 			}
1202 			send_imsg_session(IMSG_CTL_SHOW_NEXTHOP, imsg->hdr.pid,
1203 			    &snh, sizeof(snh));
1204 		}
1205 		break;
1206 	case IMSG_CTL_SHOW_INTERFACE:
1207 		RB_FOREACH(kif, kif_tree, &kit)
1208 			send_imsg_session(IMSG_CTL_SHOW_INTERFACE,
1209 			    imsg->hdr.pid, kr_show_interface(&kif->k),
1210 			    sizeof(struct ctl_show_interface));
1211 		break;
1212 	case IMSG_CTL_SHOW_FIB_TABLES:
1213 		for (i = 0; i < krt_size; i++) {
1214 			struct ktable	ktab;
1215 
1216 			if ((kt = ktable_get(i)) == NULL)
1217 				continue;
1218 
1219 			ktab = *kt;
1220 			/* do not leak internal information */
1221 			RB_INIT(&ktab.krt);
1222 			RB_INIT(&ktab.krt6);
1223 			RB_INIT(&ktab.knt);
1224 			TAILQ_INIT(&ktab.krn);
1225 
1226 			send_imsg_session(IMSG_CTL_SHOW_FIB_TABLES,
1227 			    imsg->hdr.pid, &ktab, sizeof(ktab));
1228 		}
1229 		break;
1230 	default:	/* nada */
1231 		break;
1232 	}
1233 
1234 	send_imsg_session(IMSG_CTL_END, imsg->hdr.pid, NULL, 0);
1235 }
1236 
1237 void
kr_ifinfo(char * ifname)1238 kr_ifinfo(char *ifname)
1239 {
1240 	struct kif_node	*kif;
1241 
1242 	RB_FOREACH(kif, kif_tree, &kit)
1243 		if (!strcmp(ifname, kif->k.ifname)) {
1244 			send_imsg_session(IMSG_IFINFO, 0,
1245 			    &kif->k, sizeof(kif->k));
1246 			return;
1247 		}
1248 }
1249 
1250 void
kr_net_delete(struct network * n)1251 kr_net_delete(struct network *n)
1252 {
1253 	filterset_free(&n->net.attrset);
1254 	free(n);
1255 }
1256 
1257 static int
kr_net_redist_add(struct ktable * kt,struct network_config * net,struct filter_set_head * attr,int dynamic)1258 kr_net_redist_add(struct ktable *kt, struct network_config *net,
1259     struct filter_set_head *attr, int dynamic)
1260 {
1261 	struct kredist_node *r, *xr;
1262 
1263 	if ((r = calloc(1, sizeof(*r))) == NULL)
1264 		fatal("%s", __func__);
1265 	r->prefix = net->prefix;
1266 	r->prefixlen = net->prefixlen;
1267 	r->rd = net->rd;
1268 	r->dynamic = dynamic;
1269 
1270 	xr = RB_INSERT(kredist_tree, &kt->kredist, r);
1271 	if (xr != NULL) {
1272 		free(r);
1273 
1274 		if (dynamic != xr->dynamic && dynamic) {
1275 			/*
1276 			 * ignore update a non-dynamic announcement is
1277 			 * already present which has preference.
1278 			 */
1279 			return 0;
1280 		}
1281 		/*
1282 		 * only equal or non-dynamic announcement ends up here.
1283 		 * In both cases reset the dynamic flag (nop for equal) and
1284 		 * redistribute.
1285 		 */
1286 		xr->dynamic = dynamic;
1287 	}
1288 
1289 	if (send_network(IMSG_NETWORK_ADD, net, attr) == -1)
1290 		log_warnx("%s: faild to send network update", __func__);
1291 	return 1;
1292 }
1293 
1294 static void
kr_net_redist_del(struct ktable * kt,struct network_config * net,int dynamic)1295 kr_net_redist_del(struct ktable *kt, struct network_config *net, int dynamic)
1296 {
1297 	struct kredist_node *r, node;
1298 
1299 	bzero(&node, sizeof(node));
1300 	node.prefix = net->prefix;
1301 	node.prefixlen = net->prefixlen;
1302 	node.rd = net->rd;
1303 
1304 	r = RB_FIND(kredist_tree, &kt->kredist, &node);
1305 	if (r == NULL || dynamic != r->dynamic)
1306 		return;
1307 
1308 	if (RB_REMOVE(kredist_tree, &kt->kredist, r) == NULL) {
1309 		log_warnx("%s: failed to remove network %s/%u", __func__,
1310 		    log_addr(&node.prefix), node.prefixlen);
1311 		return;
1312 	}
1313 	free(r);
1314 
1315 	if (send_network(IMSG_NETWORK_REMOVE, net, NULL) == -1)
1316 		log_warnx("%s: faild to send network removal", __func__);
1317 }
1318 
1319 int
kr_net_match(struct ktable * kt,struct network_config * net,u_int16_t flags,int loopback)1320 kr_net_match(struct ktable *kt, struct network_config *net, u_int16_t flags,
1321     int loopback)
1322 {
1323 	struct network		*xn;
1324 
1325 	TAILQ_FOREACH(xn, &kt->krn, entry) {
1326 		if (xn->net.prefix.aid != net->prefix.aid)
1327 			continue;
1328 		switch (xn->net.type) {
1329 		case NETWORK_DEFAULT:
1330 			/* static match already redistributed */
1331 			continue;
1332 		case NETWORK_STATIC:
1333 			/* Skip networks with nexthop on loopback. */
1334 			if (loopback)
1335 				continue;
1336 			if (flags & F_STATIC)
1337 				break;
1338 			continue;
1339 		case NETWORK_CONNECTED:
1340 			/* Skip networks with nexthop on loopback. */
1341 			if (loopback)
1342 				continue;
1343 			if (flags & F_CONNECTED)
1344 				break;
1345 			continue;
1346 		case NETWORK_RTLABEL:
1347 			if (net->rtlabel == xn->net.rtlabel)
1348 				break;
1349 			continue;
1350 		case NETWORK_PRIORITY:
1351 			if (net->priority == xn->net.priority)
1352 				break;
1353 			continue;
1354 		case NETWORK_MRTCLONE:
1355 		case NETWORK_PREFIXSET:
1356 			/* must not happen */
1357 			log_warnx("%s: found a NETWORK_PREFIXSET, "
1358 			    "please send a bug report", __func__);
1359 			continue;
1360 		}
1361 
1362 		net->rd = xn->net.rd;
1363 		if (kr_net_redist_add(kt, net, &xn->net.attrset, 1))
1364 			return (1);
1365 	}
1366 	return (0);
1367 }
1368 
1369 struct network *
kr_net_find(struct ktable * kt,struct network * n)1370 kr_net_find(struct ktable *kt, struct network *n)
1371 {
1372 	struct network		*xn;
1373 
1374 	TAILQ_FOREACH(xn, &kt->krn, entry) {
1375 		if (n->net.type != xn->net.type ||
1376 		    n->net.prefixlen != xn->net.prefixlen ||
1377 		    n->net.rd != xn->net.rd)
1378 			continue;
1379 		if (memcmp(&n->net.prefix, &xn->net.prefix,
1380 		    sizeof(n->net.prefix)) == 0)
1381 			return (xn);
1382 	}
1383 	return (NULL);
1384 }
1385 
1386 void
kr_net_reload(u_int rtableid,u_int64_t rd,struct network_head * nh)1387 kr_net_reload(u_int rtableid, u_int64_t rd, struct network_head *nh)
1388 {
1389 	struct network		*n, *xn;
1390 	struct ktable		*kt;
1391 
1392 	if ((kt = ktable_get(rtableid)) == NULL)
1393 		fatalx("%s: non-existent rtableid %d", __func__, rtableid);
1394 
1395 	while ((n = TAILQ_FIRST(nh)) != NULL) {
1396 		TAILQ_REMOVE(nh, n, entry);
1397 		n->net.old = 0;
1398 		n->net.rd = rd;
1399 		xn = kr_net_find(kt, n);
1400 		if (xn) {
1401 			xn->net.old = 0;
1402 			filterset_free(&xn->net.attrset);
1403 			filterset_move(&n->net.attrset, &xn->net.attrset);
1404 			kr_net_delete(n);
1405 		} else
1406 			TAILQ_INSERT_TAIL(&kt->krn, n, entry);
1407 	}
1408 }
1409 
1410 void
kr_net_clear(struct ktable * kt)1411 kr_net_clear(struct ktable *kt)
1412 {
1413 	struct network *n, *xn;
1414 
1415 	TAILQ_FOREACH_SAFE(n, &kt->krn, entry, xn) {
1416 		TAILQ_REMOVE(&kt->krn, n, entry);
1417 		if (n->net.type == NETWORK_DEFAULT)
1418 			kr_net_redist_del(kt, &n->net, 0);
1419 		kr_net_delete(n);
1420 	}
1421 }
1422 
1423 void
kr_redistribute(int type,struct ktable * kt,struct kroute * kr)1424 kr_redistribute(int type, struct ktable *kt, struct kroute *kr)
1425 {
1426 	struct network_config	 net;
1427 	u_int32_t		 a;
1428 	int			 loflag = 0;
1429 
1430 	bzero(&net, sizeof(net));
1431 	net.prefix.aid = AID_INET;
1432 	net.prefix.v4.s_addr = kr->prefix.s_addr;
1433 	net.prefixlen = kr->prefixlen;
1434 	net.rtlabel = kr->labelid;
1435 	net.priority = kr->priority;
1436 
1437 	/* shortcut for removals */
1438 	if (type == IMSG_NETWORK_REMOVE) {
1439 		kr_net_redist_del(kt, &net, 1);
1440 		return;
1441 	}
1442 
1443 	if (!(kr->flags & F_KERNEL))
1444 		return;
1445 
1446 	/* Dynamic routes are not redistributable. */
1447 	if (kr->flags & F_DYNAMIC)
1448 		return;
1449 
1450 	/*
1451 	 * We consider the loopback net, multicast and experimental addresses
1452 	 * as not redistributable.
1453 	 */
1454 	a = ntohl(kr->prefix.s_addr);
1455 	if (IN_MULTICAST(a) || IN_BADCLASS(a) ||
1456 	    (a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
1457 		return;
1458 
1459 	/* Check if the nexthop is the loopback addr. */
1460 	if (kr->nexthop.s_addr == htonl(INADDR_LOOPBACK))
1461 		loflag = 1;
1462 
1463 	/*
1464 	 * never allow 0.0.0.0/0 the default route can only be redistributed
1465 	 * with announce default.
1466 	 */
1467 	if (kr->prefix.s_addr == INADDR_ANY && kr->prefixlen == 0)
1468 		return;
1469 
1470 	if (kr_net_match(kt, &net, kr->flags, loflag) == 0)
1471 		/* no longer matches, if still present remove it */
1472 		kr_net_redist_del(kt, &net, 1);
1473 }
1474 
1475 void
kr_redistribute6(int type,struct ktable * kt,struct kroute6 * kr6)1476 kr_redistribute6(int type, struct ktable *kt, struct kroute6 *kr6)
1477 {
1478 	struct network_config	net;
1479 	int			loflag = 0;
1480 
1481 	bzero(&net, sizeof(net));
1482 	net.prefix.aid = AID_INET6;
1483 	memcpy(&net.prefix.v6, &kr6->prefix, sizeof(struct in6_addr));
1484 	net.prefixlen = kr6->prefixlen;
1485 	net.rtlabel = kr6->labelid;
1486 	net.priority = kr6->priority;
1487 
1488 	/* shortcut for removals */
1489 	if (type == IMSG_NETWORK_REMOVE) {
1490 		kr_net_redist_del(kt, &net, 1);
1491 		return;
1492 	}
1493 
1494 	if (!(kr6->flags & F_KERNEL))
1495 		return;
1496 
1497 	/* Dynamic routes are not redistributable. */
1498 	if (kr6->flags & F_DYNAMIC)
1499 		return;
1500 
1501 	/*
1502 	 * We consider unspecified, loopback, multicast, link- and site-local,
1503 	 * IPv4 mapped and IPv4 compatible addresses as not redistributable.
1504 	 */
1505 	if (IN6_IS_ADDR_UNSPECIFIED(&kr6->prefix) ||
1506 	    IN6_IS_ADDR_LOOPBACK(&kr6->prefix) ||
1507 	    IN6_IS_ADDR_MULTICAST(&kr6->prefix) ||
1508 	    IN6_IS_ADDR_LINKLOCAL(&kr6->prefix) ||
1509 	    IN6_IS_ADDR_SITELOCAL(&kr6->prefix) ||
1510 	    IN6_IS_ADDR_V4MAPPED(&kr6->prefix) ||
1511 	    IN6_IS_ADDR_V4COMPAT(&kr6->prefix))
1512 		return;
1513 
1514 	/* Check if the nexthop is the loopback addr. */
1515 	if (IN6_IS_ADDR_LOOPBACK(&kr6->nexthop))
1516 		loflag = 1;
1517 
1518 	/*
1519 	 * never allow ::/0 the default route can only be redistributed
1520 	 * with announce default.
1521 	 */
1522 	if (kr6->prefixlen == 0 &&
1523 	    memcmp(&kr6->prefix, &in6addr_any, sizeof(struct in6_addr)) == 0)
1524 		return;
1525 
1526 	if (kr_net_match(kt, &net, kr6->flags, loflag) == 0)
1527 		/* no longer matches, if still present remove it */
1528 		kr_net_redist_del(kt, &net, 1);
1529 }
1530 
1531 void
ktable_preload(void)1532 ktable_preload(void)
1533 {
1534 	struct ktable	*kt;
1535 	struct network	*n;
1536 	u_int		 i;
1537 
1538 	for (i = 0; i < krt_size; i++) {
1539 		if ((kt = ktable_get(i)) == NULL)
1540 			continue;
1541 		kt->state = RECONF_DELETE;
1542 
1543 		/* mark all networks as old */
1544 		TAILQ_FOREACH(n, &kt->krn, entry)
1545 			n->net.old = 1;
1546 	}
1547 }
1548 
1549 void
ktable_postload(u_int8_t fib_prio)1550 ktable_postload(u_int8_t fib_prio)
1551 {
1552 	struct ktable	*kt;
1553 	struct network	*n, *xn;
1554 	u_int		 i;
1555 
1556 	for (i = krt_size; i > 0; i--) {
1557 		if ((kt = ktable_get(i - 1)) == NULL)
1558 			continue;
1559 		if (kt->state == RECONF_DELETE) {
1560 			ktable_free(i - 1, fib_prio);
1561 			continue;
1562 		} else if (kt->state == RECONF_REINIT)
1563 			kt->fib_sync = kt->fib_conf;
1564 
1565 		/* cleanup old networks */
1566 		TAILQ_FOREACH_SAFE(n, &kt->krn, entry, xn) {
1567 			if (n->net.old) {
1568 				TAILQ_REMOVE(&kt->krn, n, entry);
1569 				if (n->net.type == NETWORK_DEFAULT)
1570 					kr_net_redist_del(kt, &n->net, 0);
1571 				kr_net_delete(n);
1572 			}
1573 		}
1574 	}
1575 }
1576 
1577 int
kr_reload(void)1578 kr_reload(void)
1579 {
1580 	struct ktable		*kt;
1581 	struct kroute_node	*kr;
1582 	struct kroute6_node	*kr6;
1583 	struct knexthop_node	*nh;
1584 	struct network		*n;
1585 	u_int			 rid;
1586 	int			 hasdyn = 0;
1587 
1588 	for (rid = 0; rid < krt_size; rid++) {
1589 		if ((kt = ktable_get(rid)) == NULL)
1590 			continue;
1591 
1592 		/* if this is the main nexthop table revalidate nexthops */
1593 		if (kt->rtableid == kt->nhtableid)
1594 			RB_FOREACH(nh, knexthop_tree, KT2KNT(kt))
1595 				knexthop_validate(kt, nh);
1596 
1597 		TAILQ_FOREACH(n, &kt->krn, entry)
1598 			if (n->net.type == NETWORK_DEFAULT) {
1599 				kr_net_redist_add(kt, &n->net,
1600 				    &n->net.attrset, 0);
1601 			} else
1602 				hasdyn = 1;
1603 
1604 		if (hasdyn) {
1605 			/* only evaluate the full tree if we need */
1606 			RB_FOREACH(kr, kroute_tree, &kt->krt)
1607 				kr_redistribute(IMSG_NETWORK_ADD, kt, &kr->r);
1608 			RB_FOREACH(kr6, kroute6_tree, &kt->krt6)
1609 				kr_redistribute6(IMSG_NETWORK_ADD, kt, &kr6->r);
1610 		}
1611 	}
1612 
1613 	return (0);
1614 }
1615 
1616 struct kroute_full *
kr_tofull(struct kroute * kr)1617 kr_tofull(struct kroute *kr)
1618 {
1619 	static struct kroute_full	kf;
1620 
1621 	bzero(&kf, sizeof(kf));
1622 
1623 	kf.prefix.aid = AID_INET;
1624 	kf.prefix.v4.s_addr = kr->prefix.s_addr;
1625 	kf.nexthop.aid = AID_INET;
1626 	kf.nexthop.v4.s_addr = kr->nexthop.s_addr;
1627 	strlcpy(kf.label, rtlabel_id2name(kr->labelid), sizeof(kf.label));
1628 	kf.labelid = kr->labelid;
1629 	kf.flags = kr->flags;
1630 	kf.ifindex = kr->ifindex;
1631 	kf.prefixlen = kr->prefixlen;
1632 	kf.priority = kr->priority;
1633 
1634 	return (&kf);
1635 }
1636 
1637 struct kroute_full *
kr6_tofull(struct kroute6 * kr6)1638 kr6_tofull(struct kroute6 *kr6)
1639 {
1640 	static struct kroute_full	kf;
1641 
1642 	bzero(&kf, sizeof(kf));
1643 
1644 	kf.prefix.aid = AID_INET6;
1645 	memcpy(&kf.prefix.v6, &kr6->prefix, sizeof(struct in6_addr));
1646 	kf.nexthop.aid = AID_INET6;
1647 	memcpy(&kf.nexthop.v6, &kr6->nexthop, sizeof(struct in6_addr));
1648 	strlcpy(kf.label, rtlabel_id2name(kr6->labelid), sizeof(kf.label));
1649 	kf.labelid = kr6->labelid;
1650 	kf.flags = kr6->flags;
1651 	kf.ifindex = kr6->ifindex;
1652 	kf.prefixlen = kr6->prefixlen;
1653 	kf.priority = kr6->priority;
1654 
1655 	return (&kf);
1656 }
1657 
1658 /*
1659  * RB-tree compare functions
1660  */
1661 
1662 int
kroute_compare(struct kroute_node * a,struct kroute_node * b)1663 kroute_compare(struct kroute_node *a, struct kroute_node *b)
1664 {
1665 	if (ntohl(a->r.prefix.s_addr) < ntohl(b->r.prefix.s_addr))
1666 		return (-1);
1667 	if (ntohl(a->r.prefix.s_addr) > ntohl(b->r.prefix.s_addr))
1668 		return (1);
1669 	if (a->r.prefixlen < b->r.prefixlen)
1670 		return (-1);
1671 	if (a->r.prefixlen > b->r.prefixlen)
1672 		return (1);
1673 
1674 	/* if the priority is RTP_ANY finish on the first address hit */
1675 	if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY)
1676 		return (0);
1677 	if (a->r.priority < b->r.priority)
1678 		return (-1);
1679 	if (a->r.priority > b->r.priority)
1680 		return (1);
1681 	return (0);
1682 }
1683 
1684 int
kroute6_compare(struct kroute6_node * a,struct kroute6_node * b)1685 kroute6_compare(struct kroute6_node *a, struct kroute6_node *b)
1686 {
1687 	int i;
1688 
1689 	for (i = 0; i < 16; i++) {
1690 		if (a->r.prefix.s6_addr[i] < b->r.prefix.s6_addr[i])
1691 			return (-1);
1692 		if (a->r.prefix.s6_addr[i] > b->r.prefix.s6_addr[i])
1693 			return (1);
1694 	}
1695 
1696 	if (a->r.prefixlen < b->r.prefixlen)
1697 		return (-1);
1698 	if (a->r.prefixlen > b->r.prefixlen)
1699 		return (1);
1700 
1701 	/* if the priority is RTP_ANY finish on the first address hit */
1702 	if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY)
1703 		return (0);
1704 	if (a->r.priority < b->r.priority)
1705 		return (-1);
1706 	if (a->r.priority > b->r.priority)
1707 		return (1);
1708 	return (0);
1709 }
1710 
1711 int
knexthop_compare(struct knexthop_node * a,struct knexthop_node * b)1712 knexthop_compare(struct knexthop_node *a, struct knexthop_node *b)
1713 {
1714 	int	i;
1715 
1716 	if (a->nexthop.aid != b->nexthop.aid)
1717 		return (b->nexthop.aid - a->nexthop.aid);
1718 
1719 	switch (a->nexthop.aid) {
1720 	case AID_INET:
1721 		if (ntohl(a->nexthop.v4.s_addr) < ntohl(b->nexthop.v4.s_addr))
1722 			return (-1);
1723 		if (ntohl(a->nexthop.v4.s_addr) > ntohl(b->nexthop.v4.s_addr))
1724 			return (1);
1725 		break;
1726 	case AID_INET6:
1727 		for (i = 0; i < 16; i++) {
1728 			if (a->nexthop.v6.s6_addr[i] < b->nexthop.v6.s6_addr[i])
1729 				return (-1);
1730 			if (a->nexthop.v6.s6_addr[i] > b->nexthop.v6.s6_addr[i])
1731 				return (1);
1732 		}
1733 		break;
1734 	default:
1735 		fatalx("%s: unknown AF", __func__);
1736 	}
1737 
1738 	return (0);
1739 }
1740 
1741 int
kredist_compare(struct kredist_node * a,struct kredist_node * b)1742 kredist_compare(struct kredist_node *a, struct kredist_node *b)
1743 {
1744 	int	i;
1745 
1746 	if (a->prefix.aid != b->prefix.aid)
1747 		return (b->prefix.aid - a->prefix.aid);
1748 
1749 	if (a->prefixlen < b->prefixlen)
1750 		return (-1);
1751 	if (a->prefixlen > b->prefixlen)
1752 		return (1);
1753 
1754 	switch (a->prefix.aid) {
1755 	case AID_INET:
1756 		if (ntohl(a->prefix.v4.s_addr) < ntohl(b->prefix.v4.s_addr))
1757 			return (-1);
1758 		if (ntohl(a->prefix.v4.s_addr) > ntohl(b->prefix.v4.s_addr))
1759 			return (1);
1760 		break;
1761 	case AID_INET6:
1762 		for (i = 0; i < 16; i++) {
1763 			if (a->prefix.v6.s6_addr[i] < b->prefix.v6.s6_addr[i])
1764 				return (-1);
1765 			if (a->prefix.v6.s6_addr[i] > b->prefix.v6.s6_addr[i])
1766 				return (1);
1767 		}
1768 		break;
1769 	default:
1770 		fatalx("%s: unknown AF", __func__);
1771 	}
1772 
1773 	if (a->rd < b->rd)
1774 		return (-1);
1775 	if (a->rd > b->rd)
1776 		return (1);
1777 
1778 	return (0);
1779 }
1780 
1781 int
kif_compare(struct kif_node * a,struct kif_node * b)1782 kif_compare(struct kif_node *a, struct kif_node *b)
1783 {
1784 	return (b->k.ifindex - a->k.ifindex);
1785 }
1786 
1787 
1788 /*
1789  * tree management functions
1790  */
1791 
1792 struct kroute_node *
kroute_find(struct ktable * kt,in_addr_t prefix,u_int8_t prefixlen,u_int8_t prio)1793 kroute_find(struct ktable *kt, in_addr_t prefix, u_int8_t prefixlen,
1794     u_int8_t prio)
1795 {
1796 	struct kroute_node	s;
1797 	struct kroute_node	*kn, *tmp;
1798 
1799 	s.r.prefix.s_addr = prefix;
1800 	s.r.prefixlen = prefixlen;
1801 	s.r.priority = prio;
1802 
1803 	kn = RB_FIND(kroute_tree, &kt->krt, &s);
1804 	if (kn && prio == RTP_ANY) {
1805 		tmp = RB_PREV(kroute_tree, &kt->krt, kn);
1806 		while (tmp) {
1807 			if (kroute_compare(&s, tmp) == 0)
1808 				kn = tmp;
1809 			else
1810 				break;
1811 			tmp = RB_PREV(kroute_tree, &kt->krt, kn);
1812 		}
1813 	}
1814 	return (kn);
1815 }
1816 
1817 struct kroute_node *
kroute_matchgw(struct kroute_node * kr,struct sockaddr_in * sa_in)1818 kroute_matchgw(struct kroute_node *kr, struct sockaddr_in *sa_in)
1819 {
1820 	in_addr_t	nexthop;
1821 
1822 	if (sa_in == NULL) {
1823 		log_warnx("%s: no nexthop defined", __func__);
1824 		return (NULL);
1825 	}
1826 	nexthop = sa_in->sin_addr.s_addr;
1827 
1828 	while (kr) {
1829 		if (kr->r.nexthop.s_addr == nexthop)
1830 			return (kr);
1831 		kr = kr->next;
1832 	}
1833 
1834 	return (NULL);
1835 }
1836 
1837 int
kroute_insert(struct ktable * kt,struct kroute_node * kr)1838 kroute_insert(struct ktable *kt, struct kroute_node *kr)
1839 {
1840 	struct kroute_node	*krm;
1841 	struct knexthop_node	*h;
1842 	in_addr_t		 mask, ina;
1843 
1844 	if ((krm = RB_INSERT(kroute_tree, &kt->krt, kr)) != NULL) {
1845 		/* multipath route, add at end of list */
1846 		while (krm->next != NULL)
1847 			krm = krm->next;
1848 		krm->next = kr;
1849 		kr->next = NULL; /* to be sure */
1850 	}
1851 
1852 	/* XXX this is wrong for nexthop validated via BGP */
1853 	if (kr->r.flags & F_KERNEL) {
1854 		mask = prefixlen2mask(kr->r.prefixlen);
1855 		ina = ntohl(kr->r.prefix.s_addr);
1856 		RB_FOREACH(h, knexthop_tree, KT2KNT(kt))
1857 			if (h->nexthop.aid == AID_INET &&
1858 			    (ntohl(h->nexthop.v4.s_addr) & mask) == ina)
1859 				knexthop_validate(kt, h);
1860 
1861 		if (kr->r.flags & F_CONNECTED)
1862 			if (kif_kr_insert(kr) == -1)
1863 				return (-1);
1864 
1865 		if (krm == NULL)
1866 			/* redistribute multipath routes only once */
1867 			kr_redistribute(IMSG_NETWORK_ADD, kt, &kr->r);
1868 	}
1869 	return (0);
1870 }
1871 
1872 
1873 int
kroute_remove(struct ktable * kt,struct kroute_node * kr)1874 kroute_remove(struct ktable *kt, struct kroute_node *kr)
1875 {
1876 	struct kroute_node	*krm;
1877 	struct knexthop_node	*s;
1878 
1879 	if ((krm = RB_FIND(kroute_tree, &kt->krt, kr)) == NULL) {
1880 		log_warnx("%s: failed to find %s/%u", __func__,
1881 		    inet_ntoa(kr->r.prefix), kr->r.prefixlen);
1882 		return (-1);
1883 	}
1884 
1885 	if (krm == kr) {
1886 		/* head element */
1887 		if (RB_REMOVE(kroute_tree, &kt->krt, kr) == NULL) {
1888 			log_warnx("%s: failed for %s/%u", __func__,
1889 			    inet_ntoa(kr->r.prefix), kr->r.prefixlen);
1890 			return (-1);
1891 		}
1892 		if (kr->next != NULL) {
1893 			if (RB_INSERT(kroute_tree, &kt->krt, kr->next) !=
1894 			    NULL) {
1895 				log_warnx("%s: failed to add %s/%u", __func__,
1896 				    inet_ntoa(kr->r.prefix), kr->r.prefixlen);
1897 				return (-1);
1898 			}
1899 		}
1900 	} else {
1901 		/* somewhere in the list */
1902 		while (krm->next != kr && krm->next != NULL)
1903 			krm = krm->next;
1904 		if (krm->next == NULL) {
1905 			log_warnx("%s: multipath list corrupted "
1906 			    "for %s/%u", inet_ntoa(kr->r.prefix), __func__,
1907 			    kr->r.prefixlen);
1908 			return (-1);
1909 		}
1910 		krm->next = kr->next;
1911 	}
1912 
1913 	/* check whether a nexthop depends on this kroute */
1914 	if (kr->r.flags & F_NEXTHOP)
1915 		RB_FOREACH(s, knexthop_tree, KT2KNT(kt))
1916 			if (s->kroute == kr)
1917 				knexthop_validate(kt, s);
1918 
1919 	if (kr->r.flags & F_KERNEL && kr == krm && kr->next == NULL)
1920 		/* again remove only once */
1921 		kr_redistribute(IMSG_NETWORK_REMOVE, kt, &kr->r);
1922 
1923 	if (kr->r.flags & F_CONNECTED)
1924 		if (kif_kr_remove(kr) == -1) {
1925 			free(kr);
1926 			return (-1);
1927 		}
1928 
1929 	free(kr);
1930 	return (0);
1931 }
1932 
1933 void
kroute_clear(struct ktable * kt)1934 kroute_clear(struct ktable *kt)
1935 {
1936 	struct kroute_node	*kr;
1937 
1938 	while ((kr = RB_MIN(kroute_tree, &kt->krt)) != NULL)
1939 		kroute_remove(kt, kr);
1940 }
1941 
1942 struct kroute6_node *
kroute6_find(struct ktable * kt,const struct in6_addr * prefix,u_int8_t prefixlen,u_int8_t prio)1943 kroute6_find(struct ktable *kt, const struct in6_addr *prefix,
1944     u_int8_t prefixlen, u_int8_t prio)
1945 {
1946 	struct kroute6_node	s;
1947 	struct kroute6_node	*kn6, *tmp;
1948 
1949 	memcpy(&s.r.prefix, prefix, sizeof(struct in6_addr));
1950 	s.r.prefixlen = prefixlen;
1951 	s.r.priority = prio;
1952 
1953 	kn6 = RB_FIND(kroute6_tree, &kt->krt6, &s);
1954 	if (kn6 && prio == RTP_ANY) {
1955 		tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6);
1956 		while (tmp) {
1957 			if (kroute6_compare(&s, tmp) == 0)
1958 				kn6 = tmp;
1959 			else
1960 				break;
1961 			tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6);
1962 		}
1963 	}
1964 	return (kn6);
1965 }
1966 
1967 struct kroute6_node *
kroute6_matchgw(struct kroute6_node * kr,struct sockaddr_in6 * sa_in6)1968 kroute6_matchgw(struct kroute6_node *kr, struct sockaddr_in6 *sa_in6)
1969 {
1970 	struct in6_addr	nexthop;
1971 
1972 	if (sa_in6 == NULL) {
1973 		log_warnx("%s: no nexthop defined", __func__);
1974 		return (NULL);
1975 	}
1976 	memcpy(&nexthop, &sa_in6->sin6_addr, sizeof(nexthop));
1977 
1978 	while (kr) {
1979 		if (memcmp(&kr->r.nexthop, &nexthop, sizeof(nexthop)) == 0)
1980 			return (kr);
1981 		kr = kr->next;
1982 	}
1983 
1984 	return (NULL);
1985 }
1986 
1987 int
kroute6_insert(struct ktable * kt,struct kroute6_node * kr)1988 kroute6_insert(struct ktable *kt, struct kroute6_node *kr)
1989 {
1990 	struct kroute6_node	*krm;
1991 	struct knexthop_node	*h;
1992 	struct in6_addr		 ina, inb;
1993 
1994 	if ((krm = RB_INSERT(kroute6_tree, &kt->krt6, kr)) != NULL) {
1995 		/* multipath route, add at end of list */
1996 		while (krm->next != NULL)
1997 			krm = krm->next;
1998 		krm->next = kr;
1999 		kr->next = NULL; /* to be sure */
2000 	}
2001 
2002 	/* XXX this is wrong for nexthop validated via BGP */
2003 	if (kr->r.flags & F_KERNEL) {
2004 		inet6applymask(&ina, &kr->r.prefix, kr->r.prefixlen);
2005 		RB_FOREACH(h, knexthop_tree, KT2KNT(kt))
2006 			if (h->nexthop.aid == AID_INET6) {
2007 				inet6applymask(&inb, &h->nexthop.v6,
2008 				    kr->r.prefixlen);
2009 				if (memcmp(&ina, &inb, sizeof(ina)) == 0)
2010 					knexthop_validate(kt, h);
2011 			}
2012 
2013 		if (kr->r.flags & F_CONNECTED)
2014 			if (kif_kr6_insert(kr) == -1)
2015 				return (-1);
2016 
2017 		if (krm == NULL)
2018 			/* redistribute multipath routes only once */
2019 			kr_redistribute6(IMSG_NETWORK_ADD, kt, &kr->r);
2020 	}
2021 
2022 	return (0);
2023 }
2024 
2025 int
kroute6_remove(struct ktable * kt,struct kroute6_node * kr)2026 kroute6_remove(struct ktable *kt, struct kroute6_node *kr)
2027 {
2028 	struct kroute6_node	*krm;
2029 	struct knexthop_node	*s;
2030 
2031 	if ((krm = RB_FIND(kroute6_tree, &kt->krt6, kr)) == NULL) {
2032 		log_warnx("%s: failed for %s/%u", __func__,
2033 		    log_in6addr(&kr->r.prefix), kr->r.prefixlen);
2034 		return (-1);
2035 	}
2036 
2037 	if (krm == kr) {
2038 		/* head element */
2039 		if (RB_REMOVE(kroute6_tree, &kt->krt6, kr) == NULL) {
2040 			log_warnx("%s: failed for %s/%u", __func__,
2041 			    log_in6addr(&kr->r.prefix), kr->r.prefixlen);
2042 			return (-1);
2043 		}
2044 		if (kr->next != NULL) {
2045 			if (RB_INSERT(kroute6_tree, &kt->krt6, kr->next) !=
2046 			    NULL) {
2047 				log_warnx("%s: failed to add %s/%u", __func__,
2048 				    log_in6addr(&kr->r.prefix),
2049 				    kr->r.prefixlen);
2050 				return (-1);
2051 			}
2052 		}
2053 	} else {
2054 		/* somewhere in the list */
2055 		while (krm->next != kr && krm->next != NULL)
2056 			krm = krm->next;
2057 		if (krm->next == NULL) {
2058 			log_warnx("%s: multipath list corrupted "
2059 			    "for %s/%u", __func__, log_in6addr(&kr->r.prefix),
2060 			    kr->r.prefixlen);
2061 			return (-1);
2062 		}
2063 		krm->next = kr->next;
2064 	}
2065 
2066 	/* check whether a nexthop depends on this kroute */
2067 	if (kr->r.flags & F_NEXTHOP)
2068 		RB_FOREACH(s, knexthop_tree, KT2KNT(kt))
2069 			if (s->kroute == kr)
2070 				knexthop_validate(kt, s);
2071 
2072 	if (kr->r.flags & F_KERNEL && kr == krm && kr->next == NULL)
2073 		/* again remove only once */
2074 		kr_redistribute6(IMSG_NETWORK_REMOVE, kt, &kr->r);
2075 
2076 	if (kr->r.flags & F_CONNECTED)
2077 		if (kif_kr6_remove(kr) == -1) {
2078 			free(kr);
2079 			return (-1);
2080 		}
2081 
2082 	free(kr);
2083 	return (0);
2084 }
2085 
2086 void
kroute6_clear(struct ktable * kt)2087 kroute6_clear(struct ktable *kt)
2088 {
2089 	struct kroute6_node	*kr;
2090 
2091 	while ((kr = RB_MIN(kroute6_tree, &kt->krt6)) != NULL)
2092 		kroute6_remove(kt, kr);
2093 }
2094 
2095 struct knexthop_node *
knexthop_find(struct ktable * kt,struct bgpd_addr * addr)2096 knexthop_find(struct ktable *kt, struct bgpd_addr *addr)
2097 {
2098 	struct knexthop_node	s;
2099 
2100 	bzero(&s, sizeof(s));
2101 	memcpy(&s.nexthop, addr, sizeof(s.nexthop));
2102 
2103 	return (RB_FIND(knexthop_tree, KT2KNT(kt), &s));
2104 }
2105 
2106 int
knexthop_insert(struct ktable * kt,struct knexthop_node * kn)2107 knexthop_insert(struct ktable *kt, struct knexthop_node *kn)
2108 {
2109 	if (RB_INSERT(knexthop_tree, KT2KNT(kt), kn) != NULL) {
2110 		log_warnx("%s: failed for %s", __func__,
2111 		    log_addr(&kn->nexthop));
2112 		free(kn);
2113 		return (-1);
2114 	}
2115 
2116 	knexthop_validate(kt, kn);
2117 
2118 	return (0);
2119 }
2120 
2121 int
knexthop_remove(struct ktable * kt,struct knexthop_node * kn)2122 knexthop_remove(struct ktable *kt, struct knexthop_node *kn)
2123 {
2124 	kroute_detach_nexthop(kt, kn);
2125 
2126 	if (RB_REMOVE(knexthop_tree, KT2KNT(kt), kn) == NULL) {
2127 		log_warnx("%s: failed for %s", __func__,
2128 		    log_addr(&kn->nexthop));
2129 		return (-1);
2130 	}
2131 
2132 	free(kn);
2133 	return (0);
2134 }
2135 
2136 void
knexthop_clear(struct ktable * kt)2137 knexthop_clear(struct ktable *kt)
2138 {
2139 	struct knexthop_node	*kn;
2140 
2141 	while ((kn = RB_MIN(knexthop_tree, KT2KNT(kt))) != NULL)
2142 		knexthop_remove(kt, kn);
2143 }
2144 
2145 struct kif_node *
kif_find(int ifindex)2146 kif_find(int ifindex)
2147 {
2148 	struct kif_node	s;
2149 
2150 	bzero(&s, sizeof(s));
2151 	s.k.ifindex = ifindex;
2152 
2153 	return (RB_FIND(kif_tree, &kit, &s));
2154 }
2155 
2156 int
kif_insert(struct kif_node * kif)2157 kif_insert(struct kif_node *kif)
2158 {
2159 	LIST_INIT(&kif->kroute_l);
2160 	LIST_INIT(&kif->kroute6_l);
2161 
2162 	if (RB_INSERT(kif_tree, &kit, kif) != NULL) {
2163 		log_warnx("RB_INSERT(kif_tree, &kit, kif)");
2164 		free(kif);
2165 		return (-1);
2166 	}
2167 
2168 	return (0);
2169 }
2170 
2171 int
kif_remove(struct kif_node * kif,u_int rdomain)2172 kif_remove(struct kif_node *kif, u_int rdomain)
2173 {
2174 	struct ktable	*kt;
2175 	struct kif_kr	*kkr;
2176 	struct kif_kr6	*kkr6;
2177 
2178 	if (RB_REMOVE(kif_tree, &kit, kif) == NULL) {
2179 		log_warnx("RB_REMOVE(kif_tree, &kit, kif)");
2180 		return (-1);
2181 	}
2182 
2183 	if ((kt = ktable_get(rdomain)) == NULL)
2184 		goto done;
2185 
2186 	while ((kkr = LIST_FIRST(&kif->kroute_l)) != NULL) {
2187 		LIST_REMOVE(kkr, entry);
2188 		kkr->kr->r.flags &= ~F_NEXTHOP;
2189 		kroute_remove(kt, kkr->kr);
2190 		free(kkr);
2191 	}
2192 
2193 	while ((kkr6 = LIST_FIRST(&kif->kroute6_l)) != NULL) {
2194 		LIST_REMOVE(kkr6, entry);
2195 		kkr6->kr->r.flags &= ~F_NEXTHOP;
2196 		kroute6_remove(kt, kkr6->kr);
2197 		free(kkr6);
2198 	}
2199 done:
2200 	free(kif);
2201 	return (0);
2202 }
2203 
2204 void
kif_clear(u_int rdomain)2205 kif_clear(u_int rdomain)
2206 {
2207 	struct kif_node	*kif;
2208 
2209 	while ((kif = RB_MIN(kif_tree, &kit)) != NULL)
2210 		kif_remove(kif, rdomain);
2211 }
2212 
2213 int
kif_kr_insert(struct kroute_node * kr)2214 kif_kr_insert(struct kroute_node *kr)
2215 {
2216 	struct kif_node	*kif;
2217 	struct kif_kr	*kkr;
2218 
2219 	if ((kif = kif_find(kr->r.ifindex)) == NULL) {
2220 		if (kr->r.ifindex)
2221 			log_warnx("%s: interface with index %u not found",
2222 			    __func__, kr->r.ifindex);
2223 		return (0);
2224 	}
2225 
2226 	if (kif->k.nh_reachable)
2227 		kr->r.flags &= ~F_DOWN;
2228 	else
2229 		kr->r.flags |= F_DOWN;
2230 
2231 	if ((kkr = calloc(1, sizeof(struct kif_kr))) == NULL) {
2232 		log_warn("%s", __func__);
2233 		return (-1);
2234 	}
2235 
2236 	kkr->kr = kr;
2237 
2238 	LIST_INSERT_HEAD(&kif->kroute_l, kkr, entry);
2239 
2240 	return (0);
2241 }
2242 
2243 int
kif_kr_remove(struct kroute_node * kr)2244 kif_kr_remove(struct kroute_node *kr)
2245 {
2246 	struct kif_node	*kif;
2247 	struct kif_kr	*kkr;
2248 
2249 	if ((kif = kif_find(kr->r.ifindex)) == NULL) {
2250 		if (kr->r.ifindex)
2251 			log_warnx("%s: interface with index %u not found",
2252 			    __func__, kr->r.ifindex);
2253 		return (0);
2254 	}
2255 
2256 	for (kkr = LIST_FIRST(&kif->kroute_l); kkr != NULL && kkr->kr != kr;
2257 	    kkr = LIST_NEXT(kkr, entry))
2258 		;	/* nothing */
2259 
2260 	if (kkr == NULL) {
2261 		log_warnx("%s: can't remove connected route from interface "
2262 		    "with index %u: not found", __func__, kr->r.ifindex);
2263 		return (-1);
2264 	}
2265 
2266 	LIST_REMOVE(kkr, entry);
2267 	free(kkr);
2268 
2269 	return (0);
2270 }
2271 
2272 int
kif_kr6_insert(struct kroute6_node * kr)2273 kif_kr6_insert(struct kroute6_node *kr)
2274 {
2275 	struct kif_node	*kif;
2276 	struct kif_kr6	*kkr6;
2277 
2278 	if ((kif = kif_find(kr->r.ifindex)) == NULL) {
2279 		if (kr->r.ifindex)
2280 			log_warnx("%s: interface with index %u not found",
2281 			    __func__, kr->r.ifindex);
2282 		return (0);
2283 	}
2284 
2285 	if (kif->k.nh_reachable)
2286 		kr->r.flags &= ~F_DOWN;
2287 	else
2288 		kr->r.flags |= F_DOWN;
2289 
2290 	if ((kkr6 = calloc(1, sizeof(struct kif_kr6))) == NULL) {
2291 		log_warn("%s", __func__);
2292 		return (-1);
2293 	}
2294 
2295 	kkr6->kr = kr;
2296 
2297 	LIST_INSERT_HEAD(&kif->kroute6_l, kkr6, entry);
2298 
2299 	return (0);
2300 }
2301 
2302 int
kif_kr6_remove(struct kroute6_node * kr)2303 kif_kr6_remove(struct kroute6_node *kr)
2304 {
2305 	struct kif_node	*kif;
2306 	struct kif_kr6	*kkr6;
2307 
2308 	if ((kif = kif_find(kr->r.ifindex)) == NULL) {
2309 		if (kr->r.ifindex)
2310 			log_warnx("%s: interface with index %u not found",
2311 			    __func__, kr->r.ifindex);
2312 		return (0);
2313 	}
2314 
2315 	for (kkr6 = LIST_FIRST(&kif->kroute6_l); kkr6 != NULL && kkr6->kr != kr;
2316 	    kkr6 = LIST_NEXT(kkr6, entry))
2317 		;	/* nothing */
2318 
2319 	if (kkr6 == NULL) {
2320 		log_warnx("%s: can't remove connected route from interface "
2321 		    "with index %u: not found", __func__, kr->r.ifindex);
2322 		return (-1);
2323 	}
2324 
2325 	LIST_REMOVE(kkr6, entry);
2326 	free(kkr6);
2327 
2328 	return (0);
2329 }
2330 
2331 /*
2332  * nexthop validation
2333  */
2334 
2335 static int
kif_validate(struct kif * kif)2336 kif_validate(struct kif *kif)
2337 {
2338 	if (!(kif->flags & IFF_UP))
2339 		return (0);
2340 
2341 	/*
2342 	 * we treat link_state == LINK_STATE_UNKNOWN as valid,
2343 	 * not all interfaces have a concept of "link state" and/or
2344 	 * do not report up
2345 	 */
2346 
2347 	if (kif->link_state == LINK_STATE_DOWN)
2348 		return (0);
2349 
2350 	return (1);
2351 }
2352 
2353 /*
2354  * return 1 when the interface is up and the link state is up or unknwown
2355  * except when this is a carp interface, then return 1 only when link state
2356  * is up
2357  */
2358 static int
kif_depend_state(struct kif * kif)2359 kif_depend_state(struct kif *kif)
2360 {
2361 	if (!(kif->flags & IFF_UP))
2362 		return (0);
2363 
2364 
2365 	if (kif->if_type == IFT_CARP &&
2366 	    kif->link_state == LINK_STATE_UNKNOWN)
2367 		return (0);
2368 
2369 	return LINK_STATE_IS_UP(kif->link_state);
2370 }
2371 
2372 
2373 int
kroute_validate(struct kroute * kr)2374 kroute_validate(struct kroute *kr)
2375 {
2376 	struct kif_node		*kif;
2377 
2378 	if (kr->flags & (F_REJECT | F_BLACKHOLE))
2379 		return (0);
2380 
2381 	if ((kif = kif_find(kr->ifindex)) == NULL) {
2382 		if (kr->ifindex)
2383 			log_warnx("%s: interface with index %d not found, "
2384 			    "referenced from route for %s/%u", __func__,
2385 			    kr->ifindex, inet_ntoa(kr->prefix),
2386 			    kr->prefixlen);
2387 		return (1);
2388 	}
2389 
2390 	return (kif->k.nh_reachable);
2391 }
2392 
2393 int
kroute6_validate(struct kroute6 * kr)2394 kroute6_validate(struct kroute6 *kr)
2395 {
2396 	struct kif_node		*kif;
2397 
2398 	if (kr->flags & (F_REJECT | F_BLACKHOLE))
2399 		return (0);
2400 
2401 	if ((kif = kif_find(kr->ifindex)) == NULL) {
2402 		if (kr->ifindex)
2403 			log_warnx("%s: interface with index %d not found, "
2404 			    "referenced from route for %s/%u", __func__,
2405 			    kr->ifindex, log_in6addr(&kr->prefix),
2406 			    kr->prefixlen);
2407 		return (1);
2408 	}
2409 
2410 	return (kif->k.nh_reachable);
2411 }
2412 
2413 void
knexthop_validate(struct ktable * kt,struct knexthop_node * kn)2414 knexthop_validate(struct ktable *kt, struct knexthop_node *kn)
2415 {
2416 	void			*oldk;
2417 	struct kroute_node	*kr;
2418 	struct kroute6_node	*kr6;
2419 
2420 	oldk = kn->kroute;
2421 	kroute_detach_nexthop(kt, kn);
2422 
2423 	if ((kt = ktable_get(kt->nhtableid)) == NULL)
2424 		fatalx("%s: lost nexthop routing table", __func__);
2425 
2426 	switch (kn->nexthop.aid) {
2427 	case AID_INET:
2428 		kr = kroute_match(kt, kn->nexthop.v4.s_addr, 0);
2429 
2430 		if (kr) {
2431 			kn->kroute = kr;
2432 			kr->r.flags |= F_NEXTHOP;
2433 		}
2434 
2435 		/*
2436 		 * Send update if nexthop route changed under us if
2437 		 * the route remains the same then the NH state has not
2438 		 * changed. State changes are tracked by knexthop_track().
2439 		 */
2440 		if (kr != oldk)
2441 			knexthop_send_update(kn);
2442 		break;
2443 	case AID_INET6:
2444 		kr6 = kroute6_match(kt, &kn->nexthop.v6, 0);
2445 
2446 		if (kr6) {
2447 			kn->kroute = kr6;
2448 			kr6->r.flags |= F_NEXTHOP;
2449 		}
2450 
2451 		if (kr6 != oldk)
2452 			knexthop_send_update(kn);
2453 		break;
2454 	}
2455 }
2456 
2457 void
knexthop_track(struct ktable * kt,void * krp)2458 knexthop_track(struct ktable *kt, void *krp)
2459 {
2460 	struct knexthop_node	*kn;
2461 
2462 	RB_FOREACH(kn, knexthop_tree, KT2KNT(kt))
2463 		if (kn->kroute == krp)
2464 			knexthop_send_update(kn);
2465 }
2466 
2467 void
knexthop_send_update(struct knexthop_node * kn)2468 knexthop_send_update(struct knexthop_node *kn)
2469 {
2470 	struct kroute_nexthop	 n;
2471 	struct kroute_node	*kr;
2472 	struct kroute6_node	*kr6;
2473 
2474 	bzero(&n, sizeof(n));
2475 	memcpy(&n.nexthop, &kn->nexthop, sizeof(n.nexthop));
2476 
2477 	if (kn->kroute == NULL) {
2478 		n.valid = 0;	/* NH is not valid */
2479 		send_nexthop_update(&n);
2480 		return;
2481 	}
2482 
2483 	switch (kn->nexthop.aid) {
2484 	case AID_INET:
2485 		kr = kn->kroute;
2486 		n.valid = kroute_validate(&kr->r);
2487 		n.connected = kr->r.flags & F_CONNECTED;
2488 		if (kr->r.nexthop.s_addr != 0) {
2489 			n.gateway.aid = AID_INET;
2490 			n.gateway.v4.s_addr = kr->r.nexthop.s_addr;
2491 		}
2492 		if (n.connected) {
2493 			n.net.aid = AID_INET;
2494 			n.net.v4.s_addr = kr->r.prefix.s_addr;
2495 			n.netlen = kr->r.prefixlen;
2496 		}
2497 		break;
2498 	case AID_INET6:
2499 		kr6 = kn->kroute;
2500 		n.valid = kroute6_validate(&kr6->r);
2501 		n.connected = kr6->r.flags & F_CONNECTED;
2502 		if (memcmp(&kr6->r.nexthop, &in6addr_any,
2503 		    sizeof(struct in6_addr)) != 0) {
2504 			n.gateway.aid = AID_INET6;
2505 			memcpy(&n.gateway.v6, &kr6->r.nexthop,
2506 			    sizeof(struct in6_addr));
2507 		}
2508 		if (n.connected) {
2509 			n.net.aid = AID_INET6;
2510 			memcpy(&n.net.v6, &kr6->r.prefix,
2511 			    sizeof(struct in6_addr));
2512 			n.netlen = kr6->r.prefixlen;
2513 		}
2514 		break;
2515 	}
2516 	send_nexthop_update(&n);
2517 }
2518 
2519 struct kroute_node *
kroute_match(struct ktable * kt,in_addr_t key,int matchall)2520 kroute_match(struct ktable *kt, in_addr_t key, int matchall)
2521 {
2522 	int			 i;
2523 	struct kroute_node	*kr;
2524 	in_addr_t		 ina;
2525 
2526 	ina = ntohl(key);
2527 
2528 	/* this will never match the default route */
2529 	for (i = 32; i > 0; i--)
2530 		if ((kr = kroute_find(kt, htonl(ina & prefixlen2mask(i)), i,
2531 		    RTP_ANY)) != NULL)
2532 			if (matchall || bgpd_filternexthop(&kr->r, NULL) == 0)
2533 			    return (kr);
2534 
2535 	/* so if there is no match yet, lookup the default route */
2536 	if ((kr = kroute_find(kt, 0, 0, RTP_ANY)) != NULL)
2537 		if (matchall || bgpd_filternexthop(&kr->r, NULL) == 0)
2538 			return (kr);
2539 
2540 	return (NULL);
2541 }
2542 
2543 struct kroute6_node *
kroute6_match(struct ktable * kt,struct in6_addr * key,int matchall)2544 kroute6_match(struct ktable *kt, struct in6_addr *key, int matchall)
2545 {
2546 	int			 i;
2547 	struct kroute6_node	*kr6;
2548 	struct in6_addr		 ina;
2549 
2550 	/* this will never match the default route */
2551 	for (i = 128; i > 0; i--) {
2552 		inet6applymask(&ina, key, i);
2553 		if ((kr6 = kroute6_find(kt, &ina, i, RTP_ANY)) != NULL)
2554 			if (matchall || bgpd_filternexthop(NULL, &kr6->r) == 0)
2555 				return (kr6);
2556 	}
2557 
2558 	/* so if there is no match yet, lookup the default route */
2559 	if ((kr6 = kroute6_find(kt, &in6addr_any, 0, RTP_ANY)) != NULL)
2560 		if (matchall || bgpd_filternexthop(NULL, &kr6->r) == 0)
2561 			return (kr6);
2562 
2563 	return (NULL);
2564 }
2565 
2566 void
kroute_detach_nexthop(struct ktable * kt,struct knexthop_node * kn)2567 kroute_detach_nexthop(struct ktable *kt, struct knexthop_node *kn)
2568 {
2569 	struct knexthop_node	*s;
2570 	struct kroute_node	*k;
2571 	struct kroute6_node	*k6;
2572 
2573 	if (kn->kroute == NULL)
2574 		return;
2575 
2576 	/*
2577 	 * check whether there's another nexthop depending on this kroute
2578 	 * if not remove the flag
2579 	 */
2580 	RB_FOREACH(s, knexthop_tree, KT2KNT(kt))
2581 		if (s->kroute == kn->kroute && s != kn)
2582 			break;
2583 
2584 	if (s == NULL) {
2585 		switch (kn->nexthop.aid) {
2586 		case AID_INET:
2587 			k = kn->kroute;
2588 			k->r.flags &= ~F_NEXTHOP;
2589 			break;
2590 		case AID_INET6:
2591 			k6 = kn->kroute;
2592 			k6->r.flags &= ~F_NEXTHOP;
2593 			break;
2594 		}
2595 	}
2596 
2597 	kn->kroute = NULL;
2598 }
2599 
2600 /*
2601  * misc helpers
2602  */
2603 
2604 int
protect_lo(struct ktable * kt)2605 protect_lo(struct ktable *kt)
2606 {
2607 	struct kroute_node	*kr;
2608 	struct kroute6_node	*kr6;
2609 
2610 	/* special protection for 127/8 */
2611 	if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) {
2612 		log_warn("%s", __func__);
2613 		return (-1);
2614 	}
2615 	kr->r.prefix.s_addr = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
2616 	kr->r.prefixlen = 8;
2617 	kr->r.flags = F_KERNEL|F_CONNECTED;
2618 
2619 	if (RB_INSERT(kroute_tree, &kt->krt, kr) != NULL)
2620 		free(kr);	/* kernel route already there, no problem */
2621 
2622 	/* special protection for loopback */
2623 	if ((kr6 = calloc(1, sizeof(struct kroute6_node))) == NULL) {
2624 		log_warn("%s", __func__);
2625 		return (-1);
2626 	}
2627 	memcpy(&kr6->r.prefix, &in6addr_loopback, sizeof(kr6->r.prefix));
2628 	kr6->r.prefixlen = 128;
2629 	kr6->r.flags = F_KERNEL|F_CONNECTED;
2630 
2631 	if (RB_INSERT(kroute6_tree, &kt->krt6, kr6) != NULL)
2632 		free(kr6);	/* kernel route already there, no problem */
2633 
2634 	return (0);
2635 }
2636 
2637 u_int8_t
prefixlen_classful(in_addr_t ina)2638 prefixlen_classful(in_addr_t ina)
2639 {
2640 	/* it hurt to write this. */
2641 
2642 	if (ina >= 0xf0000000U)		/* class E */
2643 		return (32);
2644 	else if (ina >= 0xe0000000U)	/* class D */
2645 		return (4);
2646 	else if (ina >= 0xc0000000U)	/* class C */
2647 		return (24);
2648 	else if (ina >= 0x80000000U)	/* class B */
2649 		return (16);
2650 	else				/* class A */
2651 		return (8);
2652 }
2653 
2654 u_int8_t
mask2prefixlen(in_addr_t ina)2655 mask2prefixlen(in_addr_t ina)
2656 {
2657 	if (ina == 0)
2658 		return (0);
2659 	else
2660 		return (33 - ffs(ntohl(ina)));
2661 }
2662 
2663 u_int8_t
mask2prefixlen6(struct sockaddr_in6 * sa_in6)2664 mask2prefixlen6(struct sockaddr_in6 *sa_in6)
2665 {
2666 	u_int8_t	*ap, *ep;
2667 	u_int		 l = 0;
2668 
2669 	/*
2670 	 * sin6_len is the size of the sockaddr so substract the offset of
2671 	 * the possibly truncated sin6_addr struct.
2672 	 */
2673 	ap = (u_int8_t *)&sa_in6->sin6_addr;
2674 	ep = (u_int8_t *)sa_in6 + sa_in6->sin6_len;
2675 	for (; ap < ep; ap++) {
2676 		/* this "beauty" is adopted from sbin/route/show.c ... */
2677 		switch (*ap) {
2678 		case 0xff:
2679 			l += 8;
2680 			break;
2681 		case 0xfe:
2682 			l += 7;
2683 			goto done;
2684 		case 0xfc:
2685 			l += 6;
2686 			goto done;
2687 		case 0xf8:
2688 			l += 5;
2689 			goto done;
2690 		case 0xf0:
2691 			l += 4;
2692 			goto done;
2693 		case 0xe0:
2694 			l += 3;
2695 			goto done;
2696 		case 0xc0:
2697 			l += 2;
2698 			goto done;
2699 		case 0x80:
2700 			l += 1;
2701 			goto done;
2702 		case 0x00:
2703 			goto done;
2704 		default:
2705 			fatalx("non contiguous inet6 netmask");
2706 		}
2707 	}
2708 
2709  done:
2710 	if (l > sizeof(struct in6_addr) * 8)
2711 		fatalx("%s: prefixlen %d out of bound", __func__, l);
2712 	return (l);
2713 }
2714 
2715 struct in6_addr *
prefixlen2mask6(u_int8_t prefixlen)2716 prefixlen2mask6(u_int8_t prefixlen)
2717 {
2718 	static struct in6_addr	mask;
2719 	int			i;
2720 
2721 	bzero(&mask, sizeof(mask));
2722 	for (i = 0; i < prefixlen / 8; i++)
2723 		mask.s6_addr[i] = 0xff;
2724 	i = prefixlen % 8;
2725 	if (i)
2726 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
2727 
2728 	return (&mask);
2729 }
2730 
2731 const struct if_status_description
2732 		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
2733 const struct ifmedia_description
2734 		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
2735 
2736 uint64_t
ift2ifm(uint8_t if_type)2737 ift2ifm(uint8_t if_type)
2738 {
2739 	switch (if_type) {
2740 	case IFT_ETHER:
2741 		return (IFM_ETHER);
2742 	case IFT_FDDI:
2743 		return (IFM_FDDI);
2744 	case IFT_CARP:
2745 		return (IFM_CARP);
2746 	case IFT_IEEE80211:
2747 		return (IFM_IEEE80211);
2748 	default:
2749 		return (0);
2750 	}
2751 }
2752 
2753 const char *
get_media_descr(uint64_t media_type)2754 get_media_descr(uint64_t media_type)
2755 {
2756 	const struct ifmedia_description	*p;
2757 
2758 	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
2759 		if (media_type == p->ifmt_word)
2760 			return (p->ifmt_string);
2761 
2762 	return ("unknown media");
2763 }
2764 
2765 const char *
get_linkstate(uint8_t if_type,int link_state)2766 get_linkstate(uint8_t if_type, int link_state)
2767 {
2768 	const struct if_status_description *p;
2769 	static char buf[8];
2770 
2771 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
2772 		if (LINK_STATE_DESC_MATCH(p, if_type, link_state))
2773 			return (p->ifs_string);
2774 	}
2775 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
2776 	return (buf);
2777 }
2778 
2779 #define ROUNDUP(a) \
2780 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
2781 
2782 void
get_rtaddrs(int addrs,struct sockaddr * sa,struct sockaddr ** rti_info)2783 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
2784 {
2785 	int	i;
2786 
2787 	for (i = 0; i < RTAX_MAX; i++) {
2788 		if (addrs & (1 << i)) {
2789 			rti_info[i] = sa;
2790 			sa = (struct sockaddr *)((char *)(sa) +
2791 			    ROUNDUP(sa->sa_len));
2792 		} else
2793 			rti_info[i] = NULL;
2794 	}
2795 }
2796 
2797 void
if_change(u_short ifindex,int flags,struct if_data * ifd,u_int rdomain)2798 if_change(u_short ifindex, int flags, struct if_data *ifd,
2799     u_int rdomain)
2800 {
2801 	struct ktable		*kt;
2802 	struct kif_node		*kif;
2803 	struct kif_kr		*kkr;
2804 	struct kif_kr6		*kkr6;
2805 	u_int8_t		 reachable;
2806 
2807 	if ((kif = kif_find(ifindex)) == NULL) {
2808 		log_warnx("%s: interface with index %u not found",
2809 		    __func__, ifindex);
2810 		return;
2811 	}
2812 
2813 	log_info("%s: %s: rdomain %u %s, %s, %s, %s",
2814 	    __func__, kif->k.ifname, ifd->ifi_rdomain,
2815 	    flags & IFF_UP ? "UP" : "DOWN",
2816 	    get_media_descr(ift2ifm(ifd->ifi_type)),
2817 	    get_linkstate(ifd->ifi_type, ifd->ifi_link_state),
2818 	    get_baudrate(ifd->ifi_baudrate, "bps"));
2819 
2820 	kif->k.flags = flags;
2821 	kif->k.link_state = ifd->ifi_link_state;
2822 	kif->k.if_type = ifd->ifi_type;
2823 	kif->k.rdomain = ifd->ifi_rdomain;
2824 	kif->k.baudrate = ifd->ifi_baudrate;
2825 	kif->k.depend_state = kif_depend_state(&kif->k);
2826 
2827 	send_imsg_session(IMSG_IFINFO, 0, &kif->k, sizeof(kif->k));
2828 
2829 	if ((reachable = kif_validate(&kif->k)) == kif->k.nh_reachable)
2830 		return;		/* nothing changed wrt nexthop validity */
2831 
2832 	kif->k.nh_reachable = reachable;
2833 
2834 	kt = ktable_get(rdomain);
2835 
2836 	LIST_FOREACH(kkr, &kif->kroute_l, entry) {
2837 		if (reachable)
2838 			kkr->kr->r.flags &= ~F_DOWN;
2839 		else
2840 			kkr->kr->r.flags |= F_DOWN;
2841 
2842 		if (kt == NULL)
2843 			continue;
2844 
2845 		knexthop_track(kt, kkr->kr);
2846 	}
2847 	LIST_FOREACH(kkr6, &kif->kroute6_l, entry) {
2848 		if (reachable)
2849 			kkr6->kr->r.flags &= ~F_DOWN;
2850 		else
2851 			kkr6->kr->r.flags |= F_DOWN;
2852 
2853 		if (kt == NULL)
2854 			continue;
2855 
2856 		knexthop_track(kt, kkr6->kr);
2857 	}
2858 }
2859 
2860 void
if_announce(void * msg,u_int rdomain)2861 if_announce(void *msg, u_int rdomain)
2862 {
2863 	struct if_announcemsghdr	*ifan;
2864 	struct kif_node			*kif;
2865 
2866 	ifan = msg;
2867 
2868 	switch (ifan->ifan_what) {
2869 	case IFAN_ARRIVAL:
2870 		if ((kif = calloc(1, sizeof(struct kif_node))) == NULL) {
2871 			log_warn("%s", __func__);
2872 			return;
2873 		}
2874 
2875 		kif->k.ifindex = ifan->ifan_index;
2876 		strlcpy(kif->k.ifname, ifan->ifan_name, sizeof(kif->k.ifname));
2877 		kif_insert(kif);
2878 		break;
2879 	case IFAN_DEPARTURE:
2880 		kif = kif_find(ifan->ifan_index);
2881 		kif_remove(kif, rdomain);
2882 		break;
2883 	}
2884 }
2885 
2886 int
get_mpe_config(const char * name,u_int * rdomain,u_int * label)2887 get_mpe_config(const char *name, u_int *rdomain, u_int *label)
2888 {
2889 	struct  ifreq	ifr;
2890 	struct shim_hdr	shim;
2891 	int		s;
2892 
2893 	*label = 0;
2894 	*rdomain = 0;
2895 
2896 	s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
2897 	if (s == -1)
2898 		return (-1);
2899 
2900 	bzero(&shim, sizeof(shim));
2901 	bzero(&ifr, sizeof(ifr));
2902 	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2903 	ifr.ifr_data = (caddr_t)&shim;
2904 
2905 	if (ioctl(s, SIOCGETLABEL, (caddr_t)&ifr) == -1) {
2906 		close(s);
2907 		return (-1);
2908 	}
2909 
2910 	ifr.ifr_data = NULL;
2911 	if (ioctl(s, SIOCGIFRDOMAIN, (caddr_t)&ifr) == -1) {
2912 		close(s);
2913 		return (-1);
2914 	}
2915 
2916 	close(s);
2917 
2918 	*rdomain = ifr.ifr_rdomainid;
2919 	*label = shim.shim_label;
2920 
2921 	return (0);
2922 }
2923 
2924 /*
2925  * rtsock related functions
2926  */
2927 
2928 int
send_rtmsg(int fd,int action,struct ktable * kt,struct kroute * kroute,u_int8_t fib_prio)2929 send_rtmsg(int fd, int action, struct ktable *kt, struct kroute *kroute,
2930     u_int8_t fib_prio)
2931 {
2932 	struct iovec		iov[7];
2933 	struct rt_msghdr	hdr;
2934 	struct sockaddr_in	prefix;
2935 	struct sockaddr_in	nexthop;
2936 	struct sockaddr_in	mask;
2937 	struct {
2938 		struct sockaddr_dl	dl;
2939 		char			pad[sizeof(long)];
2940 	}			ifp;
2941 	struct sockaddr_mpls	mpls;
2942 	struct sockaddr_rtlabel	label;
2943 	int			iovcnt = 0;
2944 
2945 	if (!kt->fib_sync)
2946 		return (0);
2947 
2948 	/* initialize header */
2949 	bzero(&hdr, sizeof(hdr));
2950 	hdr.rtm_version = RTM_VERSION;
2951 	hdr.rtm_type = action;
2952 	hdr.rtm_tableid = kt->rtableid;
2953 	hdr.rtm_priority = fib_prio;
2954 	if (kroute->flags & F_BLACKHOLE)
2955 		hdr.rtm_flags |= RTF_BLACKHOLE;
2956 	if (kroute->flags & F_REJECT)
2957 		hdr.rtm_flags |= RTF_REJECT;
2958 	if (action == RTM_CHANGE)	/* reset these flags on change */
2959 		hdr.rtm_fmask = RTF_REJECT|RTF_BLACKHOLE;
2960 	hdr.rtm_seq = kr_state.rtseq++;	/* overflow doesn't matter */
2961 	hdr.rtm_msglen = sizeof(hdr);
2962 	/* adjust iovec */
2963 	iov[iovcnt].iov_base = &hdr;
2964 	iov[iovcnt++].iov_len = sizeof(hdr);
2965 
2966 	bzero(&prefix, sizeof(prefix));
2967 	prefix.sin_len = sizeof(prefix);
2968 	prefix.sin_family = AF_INET;
2969 	prefix.sin_addr.s_addr = kroute->prefix.s_addr;
2970 	/* adjust header */
2971 	hdr.rtm_addrs |= RTA_DST;
2972 	hdr.rtm_msglen += sizeof(prefix);
2973 	/* adjust iovec */
2974 	iov[iovcnt].iov_base = &prefix;
2975 	iov[iovcnt++].iov_len = sizeof(prefix);
2976 
2977 	if (kroute->nexthop.s_addr != 0) {
2978 		bzero(&nexthop, sizeof(nexthop));
2979 		nexthop.sin_len = sizeof(nexthop);
2980 		nexthop.sin_family = AF_INET;
2981 		nexthop.sin_addr.s_addr = kroute->nexthop.s_addr;
2982 		/* adjust header */
2983 		hdr.rtm_flags |= RTF_GATEWAY;
2984 		hdr.rtm_addrs |= RTA_GATEWAY;
2985 		hdr.rtm_msglen += sizeof(nexthop);
2986 		/* adjust iovec */
2987 		iov[iovcnt].iov_base = &nexthop;
2988 		iov[iovcnt++].iov_len = sizeof(nexthop);
2989 	}
2990 
2991 	bzero(&mask, sizeof(mask));
2992 	mask.sin_len = sizeof(mask);
2993 	mask.sin_family = AF_INET;
2994 	mask.sin_addr.s_addr = htonl(prefixlen2mask(kroute->prefixlen));
2995 	/* adjust header */
2996 	hdr.rtm_addrs |= RTA_NETMASK;
2997 	hdr.rtm_msglen += sizeof(mask);
2998 	/* adjust iovec */
2999 	iov[iovcnt].iov_base = &mask;
3000 	iov[iovcnt++].iov_len = sizeof(mask);
3001 
3002 	if (kroute->flags & F_MPLS) {
3003 		/* need to force interface for mpe(4) routes */
3004 		bzero(&ifp, sizeof(ifp));
3005 		ifp.dl.sdl_len = sizeof(struct sockaddr_dl);
3006 		ifp.dl.sdl_family = AF_LINK;
3007 		ifp.dl.sdl_index = kroute->ifindex;
3008 		/* adjust header */
3009 		hdr.rtm_addrs |= RTA_IFP;
3010 		hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_dl));
3011 		/* adjust iovec */
3012 		iov[iovcnt].iov_base = &ifp;
3013 		iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_dl));
3014 
3015 		bzero(&mpls, sizeof(mpls));
3016 		mpls.smpls_len = sizeof(mpls);
3017 		mpls.smpls_family = AF_MPLS;
3018 		mpls.smpls_label = kroute->mplslabel;
3019 		/* adjust header */
3020 		hdr.rtm_flags |= RTF_MPLS;
3021 		hdr.rtm_mpls = MPLS_OP_PUSH;
3022 		hdr.rtm_addrs |= RTA_SRC;
3023 		hdr.rtm_msglen += sizeof(mpls);
3024 		/* clear gateway flag since this is for mpe(4) */
3025 		hdr.rtm_flags &= ~RTF_GATEWAY;
3026 		/* adjust iovec */
3027 		iov[iovcnt].iov_base = &mpls;
3028 		iov[iovcnt++].iov_len = sizeof(mpls);
3029 	}
3030 
3031 	if (kroute->labelid) {
3032 		bzero(&label, sizeof(label));
3033 		label.sr_len = sizeof(label);
3034 		strlcpy(label.sr_label, rtlabel_id2name(kroute->labelid),
3035 		    sizeof(label.sr_label));
3036 		/* adjust header */
3037 		hdr.rtm_addrs |= RTA_LABEL;
3038 		hdr.rtm_msglen += sizeof(label);
3039 		/* adjust iovec */
3040 		iov[iovcnt].iov_base = &label;
3041 		iov[iovcnt++].iov_len = sizeof(label);
3042 	}
3043 
3044 retry:
3045 	if (writev(fd, iov, iovcnt) == -1) {
3046 		if (errno == ESRCH) {
3047 			if (hdr.rtm_type == RTM_CHANGE) {
3048 				hdr.rtm_type = RTM_ADD;
3049 				goto retry;
3050 			} else if (hdr.rtm_type == RTM_DELETE) {
3051 				log_info("route %s/%u vanished before delete",
3052 				    inet_ntoa(kroute->prefix),
3053 				    kroute->prefixlen);
3054 				return (0);
3055 			}
3056 		}
3057 		log_warn("%s: action %u, prefix %s/%u", __func__, hdr.rtm_type,
3058 		    inet_ntoa(kroute->prefix), kroute->prefixlen);
3059 		return (0);
3060 	}
3061 
3062 	return (0);
3063 }
3064 
3065 int
send_rt6msg(int fd,int action,struct ktable * kt,struct kroute6 * kroute,u_int8_t fib_prio)3066 send_rt6msg(int fd, int action, struct ktable *kt, struct kroute6 *kroute,
3067     u_int8_t fib_prio)
3068 {
3069 	struct iovec		iov[7];
3070 	struct rt_msghdr	hdr;
3071 	struct pad {
3072 		struct sockaddr_in6	addr;
3073 		char			pad[sizeof(long)];
3074 	} prefix, nexthop, mask;
3075 	struct {
3076 		struct sockaddr_dl	dl;
3077 		char			pad[sizeof(long)];
3078 	}			ifp;
3079 	struct sockaddr_rtlabel	label;
3080 	struct sockaddr_mpls	mpls;
3081 	int			iovcnt = 0;
3082 
3083 	if (!kt->fib_sync)
3084 		return (0);
3085 
3086 	/* initialize header */
3087 	bzero(&hdr, sizeof(hdr));
3088 	hdr.rtm_version = RTM_VERSION;
3089 	hdr.rtm_type = action;
3090 	hdr.rtm_tableid = kt->rtableid;
3091 	hdr.rtm_priority = fib_prio;
3092 	if (kroute->flags & F_BLACKHOLE)
3093 		hdr.rtm_flags |= RTF_BLACKHOLE;
3094 	if (kroute->flags & F_REJECT)
3095 		hdr.rtm_flags |= RTF_REJECT;
3096 	if (action == RTM_CHANGE)	/* reset these flags on change */
3097 		hdr.rtm_fmask = RTF_REJECT|RTF_BLACKHOLE;
3098 	hdr.rtm_seq = kr_state.rtseq++;	/* overflow doesn't matter */
3099 	hdr.rtm_msglen = sizeof(hdr);
3100 	/* adjust iovec */
3101 	iov[iovcnt].iov_base = &hdr;
3102 	iov[iovcnt++].iov_len = sizeof(hdr);
3103 
3104 	bzero(&prefix, sizeof(prefix));
3105 	prefix.addr.sin6_len = sizeof(struct sockaddr_in6);
3106 	prefix.addr.sin6_family = AF_INET6;
3107 	memcpy(&prefix.addr.sin6_addr, &kroute->prefix,
3108 	    sizeof(struct in6_addr));
3109 	/* XXX scope does not matter or? */
3110 	/* adjust header */
3111 	hdr.rtm_addrs |= RTA_DST;
3112 	hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6));
3113 	/* adjust iovec */
3114 	iov[iovcnt].iov_base = &prefix;
3115 	iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
3116 
3117 	if (memcmp(&kroute->nexthop, &in6addr_any, sizeof(struct in6_addr))) {
3118 		bzero(&nexthop, sizeof(nexthop));
3119 		nexthop.addr.sin6_len = sizeof(struct sockaddr_in6);
3120 		nexthop.addr.sin6_family = AF_INET6;
3121 		memcpy(&nexthop.addr.sin6_addr, &kroute->nexthop,
3122 		    sizeof(struct in6_addr));
3123 		/* adjust header */
3124 		hdr.rtm_flags |= RTF_GATEWAY;
3125 		hdr.rtm_addrs |= RTA_GATEWAY;
3126 		hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6));
3127 		/* adjust iovec */
3128 		iov[iovcnt].iov_base = &nexthop;
3129 		iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
3130 	}
3131 
3132 	bzero(&mask, sizeof(mask));
3133 	mask.addr.sin6_len = sizeof(struct sockaddr_in6);
3134 	mask.addr.sin6_family = AF_INET6;
3135 	memcpy(&mask.addr.sin6_addr, prefixlen2mask6(kroute->prefixlen),
3136 	    sizeof(struct in6_addr));
3137 	/* adjust header */
3138 	hdr.rtm_addrs |= RTA_NETMASK;
3139 	hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6));
3140 	/* adjust iovec */
3141 	iov[iovcnt].iov_base = &mask;
3142 	iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
3143 
3144 	if (kroute->flags & F_MPLS) {
3145 		/* need to force interface for mpe(4) routes */
3146 		bzero(&ifp, sizeof(ifp));
3147 		ifp.dl.sdl_len = sizeof(struct sockaddr_dl);
3148 		ifp.dl.sdl_family = AF_LINK;
3149 		ifp.dl.sdl_index = kroute->ifindex;
3150 		/* adjust header */
3151 		hdr.rtm_addrs |= RTA_IFP;
3152 		hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_dl));
3153 		/* adjust iovec */
3154 		iov[iovcnt].iov_base = &ifp;
3155 		iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_dl));
3156 
3157 		bzero(&mpls, sizeof(mpls));
3158 		mpls.smpls_len = sizeof(mpls);
3159 		mpls.smpls_family = AF_MPLS;
3160 		mpls.smpls_label = kroute->mplslabel;
3161 		/* adjust header */
3162 		hdr.rtm_flags |= RTF_MPLS;
3163 		hdr.rtm_mpls = MPLS_OP_PUSH;
3164 		hdr.rtm_addrs |= RTA_SRC;
3165 		hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_mpls));
3166 		/* clear gateway flag since this is for mpe(4) */
3167 		hdr.rtm_flags &= ~RTF_GATEWAY;
3168 		/* adjust iovec */
3169 		iov[iovcnt].iov_base = &mpls;
3170 		iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_mpls));
3171 	}
3172 
3173 	if (kroute->labelid) {
3174 		bzero(&label, sizeof(label));
3175 		label.sr_len = sizeof(label);
3176 		strlcpy(label.sr_label, rtlabel_id2name(kroute->labelid),
3177 		    sizeof(label.sr_label));
3178 		/* adjust header */
3179 		hdr.rtm_addrs |= RTA_LABEL;
3180 		hdr.rtm_msglen += sizeof(label);
3181 		/* adjust iovec */
3182 		iov[iovcnt].iov_base = &label;
3183 		iov[iovcnt++].iov_len = sizeof(label);
3184 	}
3185 
3186 retry:
3187 	if (writev(fd, iov, iovcnt) == -1) {
3188 		if (errno == ESRCH) {
3189 			if (hdr.rtm_type == RTM_CHANGE) {
3190 				hdr.rtm_type = RTM_ADD;
3191 				goto retry;
3192 			} else if (hdr.rtm_type == RTM_DELETE) {
3193 				log_info("route %s/%u vanished before delete",
3194 				    log_in6addr(&kroute->prefix),
3195 				    kroute->prefixlen);
3196 				return (0);
3197 			}
3198 		}
3199 		log_warn("%s: action %u, prefix %s/%u", __func__, hdr.rtm_type,
3200 		    log_in6addr(&kroute->prefix), kroute->prefixlen);
3201 		return (0);
3202 	}
3203 
3204 	return (0);
3205 }
3206 
3207 int
fetchtable(struct ktable * kt,u_int8_t fib_prio)3208 fetchtable(struct ktable *kt, u_int8_t fib_prio)
3209 {
3210 	size_t			 len;
3211 	int			 mib[7];
3212 	char			*buf = NULL, *next, *lim;
3213 	struct rt_msghdr	*rtm;
3214 	struct sockaddr		*sa, *gw, *rti_info[RTAX_MAX];
3215 	struct sockaddr_in	*sa_in;
3216 	struct sockaddr_in6	*sa_in6;
3217 	struct sockaddr_rtlabel	*label;
3218 	struct kroute_node	*kr = NULL;
3219 	struct kroute6_node	*kr6 = NULL;
3220 
3221 	mib[0] = CTL_NET;
3222 	mib[1] = PF_ROUTE;
3223 	mib[2] = 0;
3224 	mib[3] = 0;
3225 	mib[4] = NET_RT_DUMP;
3226 	mib[5] = 0;
3227 	mib[6] = kt->rtableid;
3228 
3229 	if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
3230 		if (kt->rtableid != 0 && errno == EINVAL)
3231 			/* table nonexistent */
3232 			return (0);
3233 		log_warn("%s: sysctl", __func__);
3234 		return (-1);
3235 	}
3236 	if (len > 0) {
3237 		if ((buf = malloc(len)) == NULL) {
3238 			log_warn("%s: fetchtable", __func__);
3239 			return (-1);
3240 		}
3241 		if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
3242 			log_warn("%s: sysctl2", __func__);
3243 			free(buf);
3244 			return (-1);
3245 		}
3246 	}
3247 
3248 	lim = buf + len;
3249 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
3250 		rtm = (struct rt_msghdr *)next;
3251 		if (rtm->rtm_version != RTM_VERSION)
3252 			continue;
3253 		sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
3254 		get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
3255 
3256 		if ((sa = rti_info[RTAX_DST]) == NULL)
3257 			continue;
3258 
3259 		/* Skip ARP/ND cache and broadcast routes. */
3260 		if (rtm->rtm_flags & (RTF_LLINFO|RTF_BROADCAST))
3261 			continue;
3262 
3263 		switch (sa->sa_family) {
3264 		case AF_INET:
3265 			if ((kr = calloc(1, sizeof(struct kroute_node))) ==
3266 			    NULL) {
3267 				log_warn("%s", __func__);
3268 				free(buf);
3269 				return (-1);
3270 			}
3271 
3272 			kr->r.flags = F_KERNEL;
3273 			kr->r.priority = rtm->rtm_priority;
3274 			kr->r.ifindex = rtm->rtm_index;
3275 			kr->r.prefix.s_addr =
3276 			    ((struct sockaddr_in *)sa)->sin_addr.s_addr;
3277 			sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
3278 			if (rtm->rtm_flags & RTF_STATIC)
3279 				kr->r.flags |= F_STATIC;
3280 			if (rtm->rtm_flags & RTF_BLACKHOLE)
3281 				kr->r.flags |= F_BLACKHOLE;
3282 			if (rtm->rtm_flags & RTF_REJECT)
3283 				kr->r.flags |= F_REJECT;
3284 			if (rtm->rtm_flags & RTF_DYNAMIC)
3285 				kr->r.flags |= F_DYNAMIC;
3286 			if (sa_in != NULL) {
3287 				if (sa_in->sin_len == 0)
3288 					break;
3289 				kr->r.prefixlen =
3290 				    mask2prefixlen(sa_in->sin_addr.s_addr);
3291 			} else if (rtm->rtm_flags & RTF_HOST)
3292 				kr->r.prefixlen = 32;
3293 			else
3294 				kr->r.prefixlen =
3295 				    prefixlen_classful(kr->r.prefix.s_addr);
3296 			rtlabel_unref(kr->r.labelid);
3297 			kr->r.labelid = 0;
3298 			if ((label = (struct sockaddr_rtlabel *)
3299 			    rti_info[RTAX_LABEL]) != NULL) {
3300 				kr->r.flags |= F_RTLABEL;
3301 				kr->r.labelid =
3302 				    rtlabel_name2id(label->sr_label);
3303 			}
3304 			break;
3305 		case AF_INET6:
3306 			if ((kr6 = calloc(1, sizeof(struct kroute6_node))) ==
3307 			    NULL) {
3308 				log_warn("%s", __func__);
3309 				free(buf);
3310 				return (-1);
3311 			}
3312 
3313 			kr6->r.flags = F_KERNEL;
3314 			kr6->r.priority = rtm->rtm_priority;
3315 			kr6->r.ifindex = rtm->rtm_index;
3316 			memcpy(&kr6->r.prefix,
3317 			    &((struct sockaddr_in6 *)sa)->sin6_addr,
3318 			    sizeof(kr6->r.prefix));
3319 
3320 			sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
3321 			if (rtm->rtm_flags & RTF_STATIC)
3322 				kr6->r.flags |= F_STATIC;
3323 			if (rtm->rtm_flags & RTF_BLACKHOLE)
3324 				kr6->r.flags |= F_BLACKHOLE;
3325 			if (rtm->rtm_flags & RTF_REJECT)
3326 				kr6->r.flags |= F_REJECT;
3327 			if (rtm->rtm_flags & RTF_DYNAMIC)
3328 				kr6->r.flags |= F_DYNAMIC;
3329 			if (sa_in6 != NULL) {
3330 				if (sa_in6->sin6_len == 0)
3331 					break;
3332 				kr6->r.prefixlen = mask2prefixlen6(sa_in6);
3333 			} else if (rtm->rtm_flags & RTF_HOST)
3334 				kr6->r.prefixlen = 128;
3335 			else
3336 				fatalx("INET6 route without netmask");
3337 			rtlabel_unref(kr6->r.labelid);
3338 			kr6->r.labelid = 0;
3339 			if ((label = (struct sockaddr_rtlabel *)
3340 			    rti_info[RTAX_LABEL]) != NULL) {
3341 				kr6->r.flags |= F_RTLABEL;
3342 				kr6->r.labelid =
3343 				    rtlabel_name2id(label->sr_label);
3344 			}
3345 			break;
3346 		default:
3347 			continue;
3348 		}
3349 
3350 		if ((gw = rti_info[RTAX_GATEWAY]) != NULL)
3351 			switch (gw->sa_family) {
3352 			case AF_INET:
3353 				if (kr == NULL)
3354 					fatalx("v4 gateway for !v4 dst?!");
3355 
3356 				if (rtm->rtm_flags & RTF_CONNECTED) {
3357 					kr->r.flags |= F_CONNECTED;
3358 					break;
3359 				}
3360 
3361 				kr->r.nexthop.s_addr =
3362 				    ((struct sockaddr_in *)gw)->sin_addr.s_addr;
3363 				break;
3364 			case AF_INET6:
3365 				if (kr6 == NULL)
3366 					fatalx("v6 gateway for !v6 dst?!");
3367 
3368 				if (rtm->rtm_flags & RTF_CONNECTED) {
3369 					kr6->r.flags |= F_CONNECTED;
3370 					break;
3371 				}
3372 
3373 				memcpy(&kr6->r.nexthop,
3374 				    &((struct sockaddr_in6 *)gw)->sin6_addr,
3375 				    sizeof(kr6->r.nexthop));
3376 				break;
3377 			case AF_LINK:
3378 				/*
3379 				 * Traditional BSD connected routes have
3380 				 * a gateway of type AF_LINK.
3381 				 */
3382 				if (sa->sa_family == AF_INET)
3383 					kr->r.flags |= F_CONNECTED;
3384 				else if (sa->sa_family == AF_INET6)
3385 					kr6->r.flags |= F_CONNECTED;
3386 				break;
3387 			}
3388 
3389 		if (sa->sa_family == AF_INET) {
3390 			if (rtm->rtm_priority == fib_prio)  {
3391 				send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r,
3392 				    fib_prio);
3393 				free(kr);
3394 			} else
3395 				kroute_insert(kt, kr);
3396 		} else if (sa->sa_family == AF_INET6) {
3397 			if (rtm->rtm_priority == fib_prio)  {
3398 				send_rt6msg(kr_state.fd, RTM_DELETE, kt,
3399 				    &kr6->r, fib_prio);
3400 				free(kr6);
3401 			} else
3402 				kroute6_insert(kt, kr6);
3403 		}
3404 	}
3405 	free(buf);
3406 	return (0);
3407 }
3408 
3409 int
fetchifs(int ifindex)3410 fetchifs(int ifindex)
3411 {
3412 	size_t			 len;
3413 	int			 mib[6];
3414 	char			*buf, *next, *lim;
3415 	struct if_msghdr	 ifm;
3416 	struct kif_node		*kif;
3417 	struct sockaddr		*sa, *rti_info[RTAX_MAX];
3418 	struct sockaddr_dl	*sdl;
3419 
3420 	mib[0] = CTL_NET;
3421 	mib[1] = PF_ROUTE;
3422 	mib[2] = 0;
3423 	mib[3] = AF_INET;	/* AF does not matter but AF_INET is shorter */
3424 	mib[4] = NET_RT_IFLIST;
3425 	mib[5] = ifindex;
3426 
3427 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
3428 		log_warn("%s: sysctl", __func__);
3429 		return (-1);
3430 	}
3431 	if ((buf = malloc(len)) == NULL) {
3432 		log_warn("%s", __func__);
3433 		return (-1);
3434 	}
3435 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) {
3436 		log_warn("%s: sysctl2", __func__);
3437 		free(buf);
3438 		return (-1);
3439 	}
3440 
3441 	lim = buf + len;
3442 	for (next = buf; next < lim; next += ifm.ifm_msglen) {
3443 		memcpy(&ifm, next, sizeof(ifm));
3444 		if (ifm.ifm_version != RTM_VERSION)
3445 			continue;
3446 		if (ifm.ifm_type != RTM_IFINFO)
3447 			continue;
3448 
3449 		sa = (struct sockaddr *)(next + sizeof(ifm));
3450 		get_rtaddrs(ifm.ifm_addrs, sa, rti_info);
3451 
3452 		if ((kif = calloc(1, sizeof(struct kif_node))) == NULL) {
3453 			log_warn("%s", __func__);
3454 			free(buf);
3455 			return (-1);
3456 		}
3457 
3458 		kif->k.ifindex = ifm.ifm_index;
3459 		kif->k.flags = ifm.ifm_flags;
3460 		kif->k.link_state = ifm.ifm_data.ifi_link_state;
3461 		kif->k.if_type = ifm.ifm_data.ifi_type;
3462 		kif->k.rdomain = ifm.ifm_data.ifi_rdomain;
3463 		kif->k.baudrate = ifm.ifm_data.ifi_baudrate;
3464 		kif->k.nh_reachable = kif_validate(&kif->k);
3465 		kif->k.depend_state = kif_depend_state(&kif->k);
3466 
3467 		if ((sa = rti_info[RTAX_IFP]) != NULL)
3468 			if (sa->sa_family == AF_LINK) {
3469 				sdl = (struct sockaddr_dl *)sa;
3470 				if (sdl->sdl_nlen >= sizeof(kif->k.ifname))
3471 					memcpy(kif->k.ifname, sdl->sdl_data,
3472 					    sizeof(kif->k.ifname) - 1);
3473 				else if (sdl->sdl_nlen > 0)
3474 					memcpy(kif->k.ifname, sdl->sdl_data,
3475 					    sdl->sdl_nlen);
3476 				/* string already terminated via calloc() */
3477 			}
3478 
3479 		kif_insert(kif);
3480 	}
3481 	free(buf);
3482 	return (0);
3483 }
3484 
3485 int
dispatch_rtmsg(u_int rdomain)3486 dispatch_rtmsg(u_int rdomain)
3487 {
3488 	char			 buf[RT_BUF_SIZE];
3489 	ssize_t			 n;
3490 	char			*next, *lim;
3491 	struct rt_msghdr	*rtm;
3492 	struct if_msghdr	 ifm;
3493 	struct sockaddr		*sa, *rti_info[RTAX_MAX];
3494 	struct ktable		*kt;
3495 
3496 	if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) {
3497 		if (errno == EAGAIN || errno == EINTR)
3498 			return (0);
3499 		log_warn("%s: read error", __func__);
3500 		return (-1);
3501 	}
3502 
3503 	if (n == 0) {
3504 		log_warnx("routing socket closed");
3505 		return (-1);
3506 	}
3507 
3508 	lim = buf + n;
3509 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
3510 		rtm = (struct rt_msghdr *)next;
3511 		if (lim < next + sizeof(u_short) ||
3512 		    lim < next + rtm->rtm_msglen)
3513 			fatalx("%s: partial rtm in buffer", __func__);
3514 		if (rtm->rtm_version != RTM_VERSION)
3515 			continue;
3516 
3517 		switch (rtm->rtm_type) {
3518 		case RTM_ADD:
3519 		case RTM_CHANGE:
3520 		case RTM_DELETE:
3521 			sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
3522 			get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
3523 
3524 			if (rtm->rtm_pid == kr_state.pid) /* cause by us */
3525 				continue;
3526 
3527 			if (rtm->rtm_errno)		 /* failed attempts */
3528 				continue;
3529 
3530 			if (rtm->rtm_flags & RTF_LLINFO) /* arp cache */
3531 				continue;
3532 
3533 			if ((kt = ktable_get(rtm->rtm_tableid)) == NULL)
3534 				continue;
3535 
3536 			if (dispatch_rtmsg_addr(rtm, rti_info, kt) == -1)
3537 				return (-1);
3538 			break;
3539 		case RTM_IFINFO:
3540 			memcpy(&ifm, next, sizeof(ifm));
3541 			if_change(ifm.ifm_index, ifm.ifm_flags,
3542 			    &ifm.ifm_data, rdomain);
3543 			break;
3544 		case RTM_IFANNOUNCE:
3545 			if_announce(next, rdomain);
3546 			break;
3547 		default:
3548 			/* ignore for now */
3549 			break;
3550 		}
3551 	}
3552 	return (0);
3553 }
3554 
3555 int
dispatch_rtmsg_addr(struct rt_msghdr * rtm,struct sockaddr * rti_info[RTAX_MAX],struct ktable * kt)3556 dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX],
3557     struct ktable *kt)
3558 {
3559 	struct sockaddr		*sa;
3560 	struct sockaddr_in	*sa_in;
3561 	struct sockaddr_in6	*sa_in6;
3562 	struct sockaddr_rtlabel	*label;
3563 	struct kroute_node	*kr;
3564 	struct kroute6_node	*kr6;
3565 	struct bgpd_addr	 prefix;
3566 	int			 flags, oflags, mpath = 0, changed = 0;
3567 	int			 rtlabel_changed = 0;
3568 	u_int16_t		 ifindex, new_labelid;
3569 	u_int8_t		 prefixlen;
3570 	u_int8_t		 prio;
3571 
3572 	flags = F_KERNEL;
3573 	ifindex = 0;
3574 	prefixlen = 0;
3575 	bzero(&prefix, sizeof(prefix));
3576 
3577 	if ((sa = rti_info[RTAX_DST]) == NULL) {
3578 		log_warnx("empty route message");
3579 		return (0);
3580 	}
3581 
3582 	if (rtm->rtm_flags & RTF_STATIC)
3583 		flags |= F_STATIC;
3584 	if (rtm->rtm_flags & RTF_BLACKHOLE)
3585 		flags |= F_BLACKHOLE;
3586 	if (rtm->rtm_flags & RTF_REJECT)
3587 		flags |= F_REJECT;
3588 	if (rtm->rtm_flags & RTF_DYNAMIC)
3589 		flags |= F_DYNAMIC;
3590 #ifdef RTF_MPATH
3591 	if (rtm->rtm_flags & RTF_MPATH)
3592 		mpath = 1;
3593 #endif
3594 
3595 	prio = rtm->rtm_priority;
3596 	label = (struct sockaddr_rtlabel *)rti_info[RTAX_LABEL];
3597 
3598 	switch (sa->sa_family) {
3599 	case AF_INET:
3600 		prefix.aid = AID_INET;
3601 		prefix.v4.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
3602 		sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK];
3603 		if (sa_in != NULL) {
3604 			if (sa_in->sin_len != 0)
3605 				prefixlen = mask2prefixlen(
3606 				    sa_in->sin_addr.s_addr);
3607 		} else if (rtm->rtm_flags & RTF_HOST)
3608 			prefixlen = 32;
3609 		else
3610 			prefixlen =
3611 			    prefixlen_classful(prefix.v4.s_addr);
3612 		break;
3613 	case AF_INET6:
3614 		prefix.aid = AID_INET6;
3615 		memcpy(&prefix.v6, &((struct sockaddr_in6 *)sa)->sin6_addr,
3616 		    sizeof(struct in6_addr));
3617 		sa_in6 = (struct sockaddr_in6 *)rti_info[RTAX_NETMASK];
3618 		if (sa_in6 != NULL) {
3619 			if (sa_in6->sin6_len != 0)
3620 				prefixlen = mask2prefixlen6(sa_in6);
3621 		} else if (rtm->rtm_flags & RTF_HOST)
3622 			prefixlen = 128;
3623 		else
3624 			fatalx("in6 net addr without netmask");
3625 		break;
3626 	default:
3627 		return (0);
3628 	}
3629 
3630 	if ((sa = rti_info[RTAX_GATEWAY]) != NULL)
3631 		switch (sa->sa_family) {
3632 		case AF_LINK:
3633 			flags |= F_CONNECTED;
3634 			ifindex = rtm->rtm_index;
3635 			sa = NULL;
3636 			mpath = 0;	/* link local stuff can't be mpath */
3637 			break;
3638 		case AF_INET:
3639 		case AF_INET6:
3640 			if (rtm->rtm_flags & RTF_CONNECTED) {
3641 				flags |= F_CONNECTED;
3642 				ifindex = rtm->rtm_index;
3643 				sa = NULL;
3644 				mpath = 0; /* link local stuff can't be mpath */
3645 			}
3646 			break;
3647 		}
3648 
3649 	if (rtm->rtm_type == RTM_DELETE) {
3650 		switch (prefix.aid) {
3651 		case AID_INET:
3652 			sa_in = (struct sockaddr_in *)sa;
3653 			if ((kr = kroute_find(kt, prefix.v4.s_addr,
3654 			    prefixlen, prio)) == NULL)
3655 				return (0);
3656 			if (!(kr->r.flags & F_KERNEL))
3657 				return (0);
3658 
3659 			if (mpath)
3660 				/* get the correct route */
3661 				if ((kr = kroute_matchgw(kr, sa_in)) == NULL) {
3662 					log_warnx("%s[delete]: "
3663 					    "mpath route not found", __func__);
3664 					return (0);
3665 				}
3666 
3667 			if (kroute_remove(kt, kr) == -1)
3668 				return (-1);
3669 			break;
3670 		case AID_INET6:
3671 			sa_in6 = (struct sockaddr_in6 *)sa;
3672 			if ((kr6 = kroute6_find(kt, &prefix.v6, prefixlen,
3673 			    prio)) == NULL)
3674 				return (0);
3675 			if (!(kr6->r.flags & F_KERNEL))
3676 				return (0);
3677 
3678 			if (mpath)
3679 				/* get the correct route */
3680 				if ((kr6 = kroute6_matchgw(kr6, sa_in6)) ==
3681 				    NULL) {
3682 					log_warnx("%s[delete]: IPv6 mpath "
3683 					    "route not found", __func__);
3684 					return (0);
3685 				}
3686 
3687 			if (kroute6_remove(kt, kr6) == -1)
3688 				return (-1);
3689 			break;
3690 		}
3691 		return (0);
3692 	}
3693 
3694 	if (sa == NULL && !(flags & F_CONNECTED)) {
3695 		log_warnx("%s: no nexthop for %s/%u",
3696 		    __func__, log_addr(&prefix), prefixlen);
3697 		return (0);
3698 	}
3699 
3700 	switch (prefix.aid) {
3701 	case AID_INET:
3702 		sa_in = (struct sockaddr_in *)sa;
3703 		if ((kr = kroute_find(kt, prefix.v4.s_addr, prefixlen,
3704 		    prio)) != NULL) {
3705 			if (kr->r.flags & F_KERNEL) {
3706 				/* get the correct route */
3707 				if (mpath && rtm->rtm_type == RTM_CHANGE &&
3708 				    (kr = kroute_matchgw(kr, sa_in)) == NULL) {
3709 					log_warnx("%s[change]: "
3710 					    "mpath route not found", __func__);
3711 					goto add4;
3712 				} else if (mpath && rtm->rtm_type == RTM_ADD)
3713 					goto add4;
3714 
3715 				if (sa_in != NULL) {
3716 					if (kr->r.nexthop.s_addr !=
3717 					    sa_in->sin_addr.s_addr)
3718 						changed = 1;
3719 					kr->r.nexthop.s_addr =
3720 					    sa_in->sin_addr.s_addr;
3721 				} else {
3722 					if (kr->r.nexthop.s_addr != 0)
3723 						changed = 1;
3724 					kr->r.nexthop.s_addr = 0;
3725 				}
3726 
3727 				if (kr->r.flags & F_NEXTHOP)
3728 					flags |= F_NEXTHOP;
3729 
3730 				if (label != NULL) {
3731 					new_labelid =
3732 					    rtlabel_name2id(label->sr_label);
3733 					if (kr->r.labelid != new_labelid) {
3734 						rtlabel_unref(kr->r.labelid);
3735 						kr->r.labelid = 0;
3736 						flags |= F_RTLABEL;
3737 						kr->r.labelid = new_labelid;
3738 						rtlabel_changed = 1;
3739 					}
3740 				} else if (kr->r.labelid && label == NULL) {
3741 					rtlabel_unref(kr->r.labelid);
3742 					kr->r.labelid = 0;
3743 					flags &= ~F_RTLABEL;
3744 					rtlabel_changed = 1;
3745 				}
3746 
3747 				oflags = kr->r.flags;
3748 				if (flags != oflags)
3749 					changed = 1;
3750 				kr->r.flags = flags;
3751 
3752 				if (rtlabel_changed)
3753 					kr_redistribute(IMSG_NETWORK_ADD,
3754 					    kt, &kr->r);
3755 
3756 				if ((oflags & F_CONNECTED) &&
3757 				    !(flags & F_CONNECTED)) {
3758 					kif_kr_remove(kr);
3759 					kr_redistribute(IMSG_NETWORK_ADD,
3760 					    kt, &kr->r);
3761 				}
3762 				if ((flags & F_CONNECTED) &&
3763 				    !(oflags & F_CONNECTED)) {
3764 					kif_kr_insert(kr);
3765 					kr_redistribute(IMSG_NETWORK_ADD,
3766 					    kt, &kr->r);
3767 				}
3768 				if (kr->r.flags & F_NEXTHOP && changed)
3769 					knexthop_track(kt, kr);
3770 			}
3771 		} else if (rtm->rtm_type == RTM_CHANGE) {
3772 			log_warnx("%s: change req for %s/%u: not in table",
3773 			    __func__, log_addr(&prefix), prefixlen);
3774 			return (0);
3775 		} else {
3776 add4:
3777 			if ((kr = calloc(1,
3778 			    sizeof(struct kroute_node))) == NULL) {
3779 				log_warn("%s", __func__);
3780 				return (-1);
3781 			}
3782 			kr->r.prefix.s_addr = prefix.v4.s_addr;
3783 			kr->r.prefixlen = prefixlen;
3784 			if (sa_in != NULL)
3785 				kr->r.nexthop.s_addr = sa_in->sin_addr.s_addr;
3786 			else
3787 				kr->r.nexthop.s_addr = 0;
3788 			kr->r.flags = flags;
3789 			kr->r.ifindex = ifindex;
3790 			kr->r.priority = prio;
3791 
3792 			if (label) {
3793 				kr->r.flags |= F_RTLABEL;
3794 				kr->r.labelid =
3795 				    rtlabel_name2id(label->sr_label);
3796 			}
3797 			kroute_insert(kt, kr);
3798 		}
3799 		break;
3800 	case AID_INET6:
3801 		sa_in6 = (struct sockaddr_in6 *)sa;
3802 		if ((kr6 = kroute6_find(kt, &prefix.v6, prefixlen, prio)) !=
3803 		    NULL) {
3804 			if (kr6->r.flags & F_KERNEL) {
3805 				/* get the correct route */
3806 				if (mpath && rtm->rtm_type == RTM_CHANGE &&
3807 				    (kr6 = kroute6_matchgw(kr6, sa_in6)) ==
3808 				    NULL) {
3809 					log_warnx("%s[change]: IPv6 mpath "
3810 					    "route not found", __func__);
3811 					goto add6;
3812 				} else if (mpath && rtm->rtm_type == RTM_ADD)
3813 					goto add6;
3814 
3815 				if (sa_in6 != NULL) {
3816 					if (memcmp(&kr6->r.nexthop,
3817 					    &sa_in6->sin6_addr,
3818 					    sizeof(struct in6_addr)))
3819 						changed = 1;
3820 					memcpy(&kr6->r.nexthop,
3821 					    &sa_in6->sin6_addr,
3822 					    sizeof(struct in6_addr));
3823 				} else {
3824 					if (memcmp(&kr6->r.nexthop,
3825 					    &in6addr_any,
3826 					    sizeof(struct in6_addr)))
3827 						changed = 1;
3828 					memcpy(&kr6->r.nexthop,
3829 					    &in6addr_any,
3830 					    sizeof(struct in6_addr));
3831 				}
3832 
3833 				if (kr6->r.flags & F_NEXTHOP)
3834 					flags |= F_NEXTHOP;
3835 
3836 				if (label != NULL) {
3837 					new_labelid =
3838 					    rtlabel_name2id(label->sr_label);
3839 					if (kr6->r.labelid != new_labelid) {
3840 						rtlabel_unref(kr6->r.labelid);
3841 						kr6->r.labelid = 0;
3842 						flags |= F_RTLABEL;
3843 						kr6->r.labelid = new_labelid;
3844 						rtlabel_changed = 1;
3845 					}
3846 				} else if (kr6->r.labelid && label == NULL) {
3847 					rtlabel_unref(kr6->r.labelid);
3848 					kr6->r.labelid = 0;
3849 					flags &= ~F_RTLABEL;
3850 					rtlabel_changed = 1;
3851 				}
3852 
3853 				oflags = kr6->r.flags;
3854 				if (flags != oflags)
3855 					changed = 1;
3856 				kr6->r.flags = flags;
3857 
3858 				if (rtlabel_changed)
3859 					kr_redistribute6(IMSG_NETWORK_ADD,
3860 					    kt, &kr6->r);
3861 
3862 				if ((oflags & F_CONNECTED) &&
3863 				    !(flags & F_CONNECTED)) {
3864 					kif_kr6_remove(kr6);
3865 					kr_redistribute6(IMSG_NETWORK_ADD,
3866 					    kt, &kr6->r);
3867 				}
3868 				if ((flags & F_CONNECTED) &&
3869 				    !(oflags & F_CONNECTED)) {
3870 					kif_kr6_insert(kr6);
3871 					kr_redistribute6(IMSG_NETWORK_ADD,
3872 					    kt, &kr6->r);
3873 				}
3874 
3875 				if (kr6->r.flags & F_NEXTHOP && changed)
3876 					knexthop_track(kt, kr6);
3877 			}
3878 		} else if (rtm->rtm_type == RTM_CHANGE) {
3879 			log_warnx("%s: change req for %s/%u: not in table",
3880 			    __func__, log_addr(&prefix), prefixlen);
3881 			return (0);
3882 		} else {
3883 add6:
3884 			if ((kr6 = calloc(1,
3885 			    sizeof(struct kroute6_node))) == NULL) {
3886 				log_warn("%s", __func__);
3887 				return (-1);
3888 			}
3889 			memcpy(&kr6->r.prefix, &prefix.v6,
3890 			    sizeof(struct in6_addr));
3891 			kr6->r.prefixlen = prefixlen;
3892 			if (sa_in6 != NULL)
3893 				memcpy(&kr6->r.nexthop, &sa_in6->sin6_addr,
3894 				    sizeof(struct in6_addr));
3895 			else
3896 				memcpy(&kr6->r.nexthop, &in6addr_any,
3897 				    sizeof(struct in6_addr));
3898 			kr6->r.flags = flags;
3899 			kr6->r.ifindex = ifindex;
3900 			kr6->r.priority = prio;
3901 
3902 			if (label) {
3903 				kr6->r.flags |= F_RTLABEL;
3904 				kr6->r.labelid =
3905 				    rtlabel_name2id(label->sr_label);
3906 			}
3907 			kroute6_insert(kt, kr6);
3908 		}
3909 		break;
3910 	}
3911 
3912 	return (0);
3913 }
3914