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