--- ../../src.orig/bgpd/kroute-freebsd.c 2026-05-03 15:02:40.891682000 -0500 +++ kroute-freebsd.c 2026-08-04 19:00:21.900976000 -0500 @@ -62,36 +62,31 @@ struct kroute { RB_ENTRY(kroute) entry; struct kroute *next; - struct in_addr prefix; - struct in_addr nexthop; + union { + struct in_addr v4; + struct in6_addr v6; + } prefix; + union { + struct in_addr v4; + struct in6_addr v6; + } nexthop; uint32_t mplslabel; - uint16_t flags; - uint16_t labelid; - u_short ifindex; - uint8_t prefixlen; - uint8_t priority; -}; - -struct kroute6 { - RB_ENTRY(kroute6) entry; - struct kroute6 *next; - struct in6_addr prefix; - struct in6_addr nexthop; uint32_t prefix_scope_id; /* because ... */ uint32_t nexthop_scope_id; - uint32_t mplslabel; uint16_t flags; uint16_t labelid; u_short ifindex; uint8_t prefixlen; uint8_t priority; + uint8_t prefix_aid; + uint8_t nexthop_aid; }; struct knexthop { - RB_ENTRY(knexthop) entry; - struct bgpd_addr nexthop; - void *kroute; - u_short ifindex; + RB_ENTRY(knexthop) entry; + struct bgpd_addr nexthop; + struct kroute *kroute; + u_short ifindex; }; struct kredist_node { @@ -120,17 +115,14 @@ void ktable_destroy(struct ktable *); struct ktable *ktable_get(u_int); -int kr4_change(struct ktable *, struct kroute_full *); -int kr6_change(struct ktable *, struct kroute_full *); +int kr_change(u_int, struct kroute_full *); int kr_net_match(struct ktable *, struct network_config *, uint16_t, int); struct network *kr_net_find(struct ktable *, struct network *); void kr_net_clear(struct ktable *); void kr_redistribute(int, struct ktable *, struct kroute_full *); uint8_t kr_priority(struct kroute_full *); struct kroute_full *kr_tofull(struct kroute *); -struct kroute_full *kr6_tofull(struct kroute6 *); int kroute_compare(struct kroute *, struct kroute *); -int kroute6_compare(struct kroute6 *, struct kroute6 *); int knexthop_compare(struct knexthop *, struct knexthop *); int kredist_compare(struct kredist_node *, struct kredist_node *); int kif_compare(struct kif *, struct kif *); @@ -142,11 +134,6 @@ int kroute_remove(struct ktable *, struct kroute_full *, int); void kroute_clear(struct ktable *); -struct kroute6 *kroute6_find(struct ktable *, const struct bgpd_addr *, - uint8_t, uint8_t); -struct kroute6 *kroute6_matchgw(struct kroute6 *, struct kroute_full *); -void kroute6_clear(struct ktable *); - struct knexthop *knexthop_find(struct ktable *, struct bgpd_addr *); int knexthop_insert(struct ktable *, struct knexthop *); void knexthop_remove(struct ktable *, struct knexthop *); @@ -158,14 +145,12 @@ void kif_clear(void); int kroute_validate(struct kroute *); -int kroute6_validate(struct kroute6 *); int knexthop_true_nexthop(struct ktable *, struct kroute_full *); void knexthop_validate(struct ktable *, struct knexthop *); void knexthop_track(struct ktable *, u_short); void knexthop_update(struct ktable *, struct kroute_full *); void knexthop_send_update(struct knexthop *); struct kroute *kroute_match(struct ktable *, struct bgpd_addr *, int); -struct kroute6 *kroute6_match(struct ktable *, struct bgpd_addr *, int); void kroute_detach_nexthop(struct ktable *, struct knexthop *); uint8_t prefixlen_classful(in_addr_t); @@ -185,13 +170,12 @@ int dispatch_rtmsg_addr(struct rt_msghdr *, struct kroute_full *); int kr_fib_delete(struct ktable *, struct kroute_full *, int); int kr_fib_change(struct ktable *, struct kroute_full *, int, int); +int kr_rfc5549_support(void); + RB_PROTOTYPE(kroute_tree, kroute, entry, kroute_compare) RB_GENERATE(kroute_tree, kroute, entry, kroute_compare) -RB_PROTOTYPE(kroute6_tree, kroute6, entry, kroute6_compare) -RB_GENERATE(kroute6_tree, kroute6, entry, kroute6_compare) - RB_PROTOTYPE(knexthop_tree, knexthop, entry, knexthop_compare) RB_GENERATE(knexthop_tree, knexthop, entry, knexthop_compare) @@ -302,7 +286,6 @@ /* initialize structure ... */ strlcpy(kt->descr, name, sizeof(kt->descr)); RB_INIT(&kt->krt); - RB_INIT(&kt->krt6); RB_INIT(&kt->knt); TAILQ_INIT(&kt->krn); kt->fib_conf = kt->fib_sync = fs; @@ -362,7 +345,6 @@ if (kt->rtableid == kt->nhtableid) knexthop_clear(kt); kroute_clear(kt); - kroute6_clear(kt); kr_net_clear(kt); krt[kt->rtableid] = NULL; @@ -448,7 +430,9 @@ int kr_change(u_int rtableid, struct kroute_full *kf) { - struct ktable *kt; + struct ktable *kt; + struct kroute *kr; + struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT; if ((kt = ktable_get(rtableid)) == NULL) /* too noisy during reloads, just ignore */ @@ -457,36 +441,45 @@ kf->priority = RTP_MINE; if (!knexthop_true_nexthop(kt, kf)) return kroute_remove(kt, kf, 1); - switch (kf->prefix.aid) { - case AID_INET: - return (kr4_change(kt, kf)); - case AID_INET6: - return (kr6_change(kt, kf)); - default: + if (kf->prefix.aid != AID_INET && kf->prefix.aid != AID_INET6) { log_warnx("%s: not handled AID", __func__); return (-1); } -} -int -kr4_change(struct ktable *kt, struct kroute_full *kf) -{ - struct kroute *kr; - - /* for blackhole and reject routes nexthop needs to be 127.0.0.1 */ - if (kf->flags & (F_BLACKHOLE|F_REJECT)) - kf->nexthop.v4.s_addr = htonl(INADDR_LOOPBACK); - /* nexthop within 127/8 -> ignore silently */ - else if ((kf->nexthop.v4.s_addr & htonl(IN_CLASSA_NET)) == - htonl(INADDR_LOOPBACK & IN_CLASSA_NET)) - return (0); + if (kf->flags & (F_BLACKHOLE|F_REJECT)) { + if (kf->prefix.aid == AID_INET) { + /* for IPv4 blackhole and reject routes nexthop needs to be 127.0.0.1 */ + kf->nexthop.aid = AID_INET; + kf->nexthop.v4.s_addr = htonl(INADDR_LOOPBACK); + } else { + /* for IPv6 blackhole and reject routes nexthop needs to be ::1 */ + kf->nexthop.aid = AID_INET6; + memcpy(&kf->nexthop.v6, &lo6, sizeof(kf->nexthop.v6)); + } + } else { + /* nexthop to loopback -> ignore silently */ + if (kf->nexthop.aid == AID_INET) { + if ((kf->nexthop.v4.s_addr & htonl(IN_CLASSA_NET)) == + htonl(INADDR_LOOPBACK & IN_CLASSA_NET)) + return (0); + } else { + if (IN6_IS_ADDR_LOOPBACK(&kf->nexthop.v6)) + return (0); + } + } if ((kr = kroute_find(kt, &kf->prefix, kf->prefixlen, - kf->priority)) == NULL) { + kf->priority)) == NULL) { if (kroute_insert(kt, kf) == -1) return (-1); } else { - kr->nexthop.s_addr = kf->nexthop.v4.s_addr; + + if (kf->nexthop.aid == AID_INET) + kr->nexthop.v4.s_addr = kf->nexthop.v4.s_addr; + else { + kr->nexthop.v6 = kf->nexthop.v6; + kr->nexthop_scope_id = kf->nexthop.scope_id; + } rtlabel_unref(kr->labelid); kr->labelid = rtlabel_name2id(kf->label); if (kf->flags & F_BLACKHOLE) @@ -503,7 +496,7 @@ /* check if there is already a kernel, higher prio route */ if (kroute_find(kt, &kf->prefix, kf->prefixlen, RTP_KERN) == - NULL) + NULL) if (send_rtmsg(RTM_CHANGE, kt, kf)) kr->flags |= F_BGPD_INSERTED; } @@ -512,50 +505,6 @@ } int -kr6_change(struct ktable *kt, struct kroute_full *kf) -{ - struct kroute6 *kr6; - struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT; - - /* for blackhole and reject routes nexthop needs to be ::1 */ - if (kf->flags & (F_BLACKHOLE|F_REJECT)) - memcpy(&kf->nexthop.v6, &lo6, sizeof(kf->nexthop.v6)); - /* nexthop to loopback -> ignore silently */ - else if (IN6_IS_ADDR_LOOPBACK(&kf->nexthop.v6)) - return (0); - - if ((kr6 = kroute6_find(kt, &kf->prefix, kf->prefixlen, - kf->priority)) == NULL) { - if (kroute_insert(kt, kf) == -1) - return (-1); - } else { - memcpy(&kr6->nexthop, &kf->nexthop.v6, sizeof(struct in6_addr)); - kr6->nexthop_scope_id = kf->nexthop.scope_id; - rtlabel_unref(kr6->labelid); - kr6->labelid = rtlabel_name2id(kf->label); - if (kf->flags & F_BLACKHOLE) - kr6->flags |= F_BLACKHOLE; - else - kr6->flags &= ~F_BLACKHOLE; - if (kf->flags & F_REJECT) - kr6->flags |= F_REJECT; - else - kr6->flags &= ~F_REJECT; - - if (kr6->flags & F_NEXTHOP) - knexthop_update(kt, kf); - - /* check if there is already a kernel, higher prio route */ - if (kroute6_find(kt, &kf->prefix, kf->prefixlen, RTP_KERN) == - NULL) - if (send_rtmsg(RTM_CHANGE, kt, kf)) - kr6->flags |= F_BGPD_INSERTED; - } - - return (0); -} - -int kr_delete(u_int rtableid, struct kroute_full *kf) { struct ktable *kt; @@ -573,7 +522,6 @@ { struct ktable *kt; struct kroute *kr, *next; - struct kroute6 *kr6, *next6; if ((kt = ktable_get(rtableid)) == NULL) /* too noisy during reloads, just ignore */ @@ -584,12 +532,6 @@ if (kroute_remove(kt, kr_tofull(kr), 1) == -1) return (-1); } - RB_FOREACH_SAFE(kr6, kroute6_tree, &kt->krt6, next6) - if ((kr6->flags & F_BGPD_INSERTED)) { - if (kroute_remove(kt, kr6_tofull(kr6), 1) == -1) - return (-1); - } - kt->fib_sync = 0; return (0); } @@ -610,7 +552,6 @@ { struct ktable *kt; struct kroute *kr; - struct kroute6 *kr6; if ((kt = ktable_get(rtableid)) == NULL) /* table does not exist */ return; @@ -625,13 +566,8 @@ if (send_rtmsg(RTM_ADD, kt, kr_tofull(kr))) kr->flags |= F_BGPD_INSERTED; } - RB_FOREACH(kr6, kroute6_tree, &kt->krt6) - if (kr6->flags & F_BGPD) { - if (send_rtmsg(RTM_ADD, kt, kr6_tofull(kr6))) - kr6->flags |= F_BGPD_INSERTED; - } - log_info("kernel routing table %u (%s) coupled", kt->rtableid, - kt->descr); + log_info("kernel routing table %u (%s) coupled", kt->rtableid, + kt->descr); } void @@ -648,7 +584,6 @@ { struct ktable *kt; struct kroute *kr; - struct kroute6 *kr6; if ((kt = ktable_get(rtableid)) == NULL) /* table does not exist */ return; @@ -661,16 +596,10 @@ if (send_rtmsg(RTM_DELETE, kt, kr_tofull(kr))) kr->flags &= ~F_BGPD_INSERTED; } - RB_FOREACH(kr6, kroute6_tree, &kt->krt6) - if ((kr6->flags & F_BGPD_INSERTED)) { - if (send_rtmsg(RTM_DELETE, kt, kr6_tofull(kr6))) - kr6->flags &= ~F_BGPD_INSERTED; - } - kt->fib_sync = 0; log_info("kernel routing table %u (%s) decoupled", kt->rtableid, - kt->descr); + kt->descr); } void @@ -767,7 +696,6 @@ { struct ktable *kt; struct kroute *kr, *kn; - struct kroute6 *kr6, *kn6; struct kroute_full *kf; struct bgpd_addr addr; struct ctl_kroute_req req; @@ -805,18 +733,6 @@ pid, kf, sizeof(*kf)); } while ((kn = kn->next) != NULL); } - if (!req.af || req.af == AF_INET6) - RB_FOREACH(kr6, kroute6_tree, &kt->krt6) { - if (req.flags && (kr6->flags & req.flags) == 0) - continue; - kn6 = kr6; - do { - kf = kr6_tofull(kn6); - kf->priority = kr_priority(kf); - send_imsg_session(IMSG_CTL_KROUTE, - pid, kf, sizeof(*kf)); - } while ((kn6 = kn6->next) != NULL); - } break; case IMSG_CTL_KROUTE_ADDR: if (imsg_get_data(imsg, &addr, sizeof(addr)) == -1) { @@ -830,25 +746,12 @@ break; } kr = NULL; - switch (addr.aid) { - case AID_INET: - kr = kroute_match(kt, &addr, 1); - if (kr != NULL) { - kf = kr_tofull(kr); - kf->priority = kr_priority(kf); - send_imsg_session(IMSG_CTL_KROUTE, - pid, kf, sizeof(*kf)); - } - break; - case AID_INET6: - kr6 = kroute6_match(kt, &addr, 1); - if (kr6 != NULL) { - kf = kr6_tofull(kr6); - kf->priority = kr_priority(kf); - send_imsg_session(IMSG_CTL_KROUTE, - pid, kf, sizeof(*kf)); - } - break; + kr = kroute_match(kt, &addr, 1); + if (kr != NULL) { + kf = kr_tofull(kr); + kf->priority = kr_priority(kf); + send_imsg_session(IMSG_CTL_KROUTE, + pid, kf, sizeof(*kf)); } break; case IMSG_CTL_SHOW_NEXTHOP: @@ -862,22 +765,12 @@ memset(&snh, 0, sizeof(snh)); memcpy(&snh.addr, &h->nexthop, sizeof(snh.addr)); if (h->kroute != NULL) { - switch (h->nexthop.aid) { - case AID_INET: - kr = h->kroute; - snh.valid = kroute_validate(kr); - snh.krvalid = 1; - snh.kr = *kr_tofull(kr); - ifindex = kr->ifindex; - break; - case AID_INET6: - kr6 = h->kroute; - snh.valid = kroute6_validate(kr6); - snh.krvalid = 1; - snh.kr = *kr6_tofull(kr6); - ifindex = kr6->ifindex; - break; - } + kr = h->kroute; + snh.valid = kroute_validate(kr); + snh.krvalid = 1; + snh.kr = *kr_tofull(kr); + ifindex = kr->ifindex; + snh.kr.priority = kr_priority(&snh.kr); if ((kif = kif_find(ifindex)) != NULL) memcpy(&snh.iface, @@ -904,7 +797,6 @@ ktab = *kt; /* do not leak internal information */ RB_INIT(&ktab.krt); - RB_INIT(&ktab.krt6); RB_INIT(&ktab.knt); TAILQ_INIT(&ktab.krn); @@ -1144,8 +1036,14 @@ return; /* Check if the nexthop is the loopback addr. */ - if (kf->nexthop.v4.s_addr == htonl(INADDR_LOOPBACK)) - loflag = 1; + if (kf->nexthop.aid == AID_INET) { + if (kf->nexthop.v4.s_addr == htonl(INADDR_LOOPBACK)) + loflag = 1; + } + else { + if (IN6_IS_ADDR_LOOPBACK(&kf->nexthop.v6)) + loflag = 1; + } break; case AID_INET6: @@ -1163,9 +1061,15 @@ IN6_IS_ADDR_V4COMPAT(&kf->prefix.v6)) return; - /* Check if the nexthop is the loopback addr. */ - if (IN6_IS_ADDR_LOOPBACK(&kf->nexthop.v6)) - loflag = 1; + /* Check if the nexthop is the loopback addr. */ + if (kf->nexthop.aid == AID_INET) { + if (kf->nexthop.v4.s_addr == htonl(INADDR_LOOPBACK)) + loflag = 1; + } + else { + if (IN6_IS_ADDR_LOOPBACK(&kf->nexthop.v6)) + loflag = 1; + } break; default: /* unhandled AID cannot be redistributed */ @@ -1235,7 +1139,6 @@ { struct ktable *kt; struct kroute *kr; - struct kroute6 *kr6; struct knexthop *nh; struct network *n; u_int rid; @@ -1262,9 +1165,6 @@ RB_FOREACH(kr, kroute_tree, &kt->krt) kr_redistribute(IMSG_NETWORK_ADD, kt, kr_tofull(kr)); - RB_FOREACH(kr6, kroute6_tree, &kt->krt6) - kr_redistribute(IMSG_NETWORK_ADD, kt, - kr6_tofull(kr6)); } } @@ -1286,40 +1186,29 @@ memset(&kf, 0, sizeof(kf)); - kf.prefix.aid = AID_INET; - kf.prefix.v4.s_addr = kr->prefix.s_addr; - kf.nexthop.aid = AID_INET; - kf.nexthop.v4.s_addr = kr->nexthop.s_addr; + kf.prefix.aid = kr->prefix_aid; + if (kr->prefix_aid == AID_INET) + kf.prefix.v4 = kr->prefix.v4; + else { + kf.prefix.v6 = kr->prefix.v6; + kf.prefix.scope_id = kr->prefix_scope_id; + } + + kf.nexthop.aid = kr->nexthop_aid; + if (kr->nexthop_aid == AID_INET) + kf.nexthop.v4 = kr->nexthop.v4; + else { + kf.nexthop.v6 = kr->nexthop.v6; + kf.nexthop.scope_id = kr->nexthop_scope_id; + } + strlcpy(kf.label, rtlabel_id2name(kr->labelid), sizeof(kf.label)); kf.flags = kr->flags; kf.ifindex = kr->ifindex; kf.prefixlen = kr->prefixlen; kf.priority = kr->priority; kf.mplslabel = kr->mplslabel; - - return (&kf); -} - -struct kroute_full * -kr6_tofull(struct kroute6 *kr6) -{ - static struct kroute_full kf; - memset(&kf, 0, sizeof(kf)); - - kf.prefix.aid = AID_INET6; - kf.prefix.v6 = kr6->prefix; - kf.prefix.scope_id = kr6->prefix_scope_id; - kf.nexthop.aid = AID_INET6; - kf.nexthop.v6 = kr6->nexthop; - kf.nexthop.scope_id = kr6->nexthop_scope_id; - strlcpy(kf.label, rtlabel_id2name(kr6->labelid), sizeof(kf.label)); - kf.flags = kr6->flags; - kf.ifindex = kr6->ifindex; - kf.prefixlen = kr6->prefixlen; - kf.priority = kr6->priority; - kf.mplslabel = kr6->mplslabel; - return (&kf); } @@ -1330,40 +1219,24 @@ int kroute_compare(struct kroute *a, struct kroute *b) { - if (ntohl(a->prefix.s_addr) < ntohl(b->prefix.s_addr)) - return (-1); - if (ntohl(a->prefix.s_addr) > ntohl(b->prefix.s_addr)) - return (1); - if (a->prefixlen < b->prefixlen) - return (-1); - if (a->prefixlen > b->prefixlen) - return (1); - - /* if the priority is RTP_ANY finish on the first address hit */ - if (a->priority == RTP_ANY || b->priority == RTP_ANY) - return (0); - if (a->priority < b->priority) - return (-1); - if (a->priority > b->priority) - return (1); - return (0); -} - -int -kroute6_compare(struct kroute6 *a, struct kroute6 *b) -{ int i; - for (i = 0; i < 16; i++) { - if (a->prefix.s6_addr[i] < b->prefix.s6_addr[i]) + if (a->prefix_aid != b->prefix_aid) + return ((a->prefix_aid < b->prefix_aid) ? (-1) : (1)); + + if (a->prefix_aid == AID_INET) { + if (ntohl(a->prefix.v4.s_addr) < ntohl(b->prefix.v4.s_addr)) return (-1); - if (a->prefix.s6_addr[i] > b->prefix.s6_addr[i]) + if (ntohl(a->prefix.v4.s_addr) > ntohl(b->prefix.v4.s_addr)) return (1); + } else { + for (i = 0; i < 16; i++) { + if (a->prefix.v6.s6_addr[i] < b->prefix.v6.s6_addr[i]) + return (-1); + if (a->prefix.v6.s6_addr[i] > b->prefix.v6.s6_addr[i]) + return (1); + } } - if (a->prefix_scope_id < b->prefix_scope_id) - return (-1); - if (a->prefix_scope_id > b->prefix_scope_id) - return (1); if (a->prefixlen < b->prefixlen) return (-1); @@ -1386,7 +1259,7 @@ int i; if (a->nexthop.aid != b->nexthop.aid) - return (b->nexthop.aid - a->nexthop.aid); + return ((a->nexthop.aid < b->nexthop.aid) ? (-1) : (1)); switch (a->nexthop.aid) { case AID_INET: @@ -1416,7 +1289,7 @@ int i; if (a->prefix.aid != b->prefix.aid) - return (b->prefix.aid - a->prefix.aid); + return ((a->prefix.aid < b->prefix.aid) ? (-1) : (1)); if (a->prefixlen < b->prefixlen) return (-1); @@ -1468,7 +1341,15 @@ struct kroute s; struct kroute *kn, *tmp; - s.prefix = prefix->v4; + s.prefix_aid = prefix->aid; + + if (prefix->aid == AID_INET) + s.prefix.v4 = prefix->v4; + else { + s.prefix.v6 = prefix->v6; + s.prefix_scope_id = prefix->scope_id; + } + s.prefixlen = prefixlen; s.priority = prio; @@ -1489,7 +1370,9 @@ struct kroute * kroute_matchgw(struct kroute *kr, struct kroute_full *kf) { - in_addr_t nexthop; + in_addr_t nexthop4; + struct in6_addr nexthop6; + uint32_t scope_id; if (kf->flags & F_CONNECTED) { do { @@ -1501,12 +1384,31 @@ return (NULL); } - nexthop = kf->nexthop.v4.s_addr; - do { - if (kr->nexthop.s_addr == nexthop) - return (kr); - kr = kr->next; - } while (kr); + switch (kf->nexthop.aid) { + case AID_INET: + nexthop4 = kf->nexthop.v4.s_addr; + do { + if (kr->nexthop_aid == AID_INET) { + if (kr->nexthop.v4.s_addr == nexthop4) + return (kr); + } + kr = kr->next; + } while (kr); + break; + case AID_INET6: + nexthop6 = kf->nexthop.v6; + scope_id = kf->nexthop.scope_id; + do { + if (kr->nexthop_aid == AID_INET6) { + if (memcmp(&kr->nexthop.v6, &nexthop6, + sizeof(nexthop6)) == 0 && + kr->nexthop_scope_id == scope_id) + return (kr); + } + kr = kr->next; + } while (kr); + break; + } return (NULL); } @@ -1515,7 +1417,6 @@ kroute_insert(struct ktable *kt, struct kroute_full *kf) { struct kroute *kr, *krm; - struct kroute6 *kr6, *kr6m; struct knexthop *n; uint32_t mplslabel = 0; int multipath = 0; @@ -1533,85 +1434,70 @@ (kf->prefix.labelstack[2] << 8); } + if ((kr = calloc(1, sizeof(*kr))) == NULL) { + log_warn("%s", __func__); + return (-1); + } + + kr->prefix_aid = kf->prefix.aid; + kr->flags = kf->flags; + kr->prefixlen = kf->prefixlen; + + kr->ifindex = kf->ifindex; + kr->priority = kf->priority; + kr->labelid = rtlabel_name2id(kf->label); + kr->nexthop_aid = AID_UNSPEC; + switch (kf->prefix.aid) { case AID_INET: case AID_VPN_IPv4: - if ((kr = calloc(1, sizeof(*kr))) == NULL) { - log_warn("%s", __func__); - return (-1); + kr->prefix.v4 = kf->prefix.v4; + if (kf->nexthop.aid == AID_INET) { + kr->nexthop.v4 = kf->nexthop.v4; + kr->nexthop_aid = AID_INET; } - kr->flags = kf->flags; - kr->prefix = kf->prefix.v4; - kr->prefixlen = kf->prefixlen; - if (kf->nexthop.aid == AID_INET) - kr->nexthop = kf->nexthop.v4; + else if (kf->nexthop.aid == AID_INET6) { + kr->nexthop.v6 = kf->nexthop.v6; + kr->nexthop_aid = AID_INET6; + } if (kf->prefix.aid == AID_VPN_IPv4) { kr->flags |= F_MPLS; kr->mplslabel = htonl(mplslabel); } - - kr->ifindex = kf->ifindex; - kr->priority = kf->priority; - kr->labelid = rtlabel_name2id(kf->label); - - if ((krm = RB_INSERT(kroute_tree, &kt->krt, kr)) != NULL) { - /* multipath route, add at end of list */ - while (krm->next != NULL) - krm = krm->next; - krm->next = kr; - multipath = 1; - } + break; - /* check if a kernel route exists */ - if ((kf->flags & F_BGPD) && - kroute_find(kt, &kf->prefix, kf->prefixlen, RTP_KERN) == - NULL) - if (send_rtmsg(RTM_ADD, kt, kf)) - kr->flags |= F_BGPD_INSERTED; - break; case AID_INET6: case AID_VPN_IPv6: - if ((kr6 = calloc(1, sizeof(*kr6))) == NULL) { - log_warn("%s", __func__); - return (-1); - } - kr6->flags = kf->flags; - kr6->prefix = kf->prefix.v6; - kr6->prefix_scope_id = kf->prefix.scope_id; - kr6->prefixlen = kf->prefixlen; + kr->prefix.v6 = kf->prefix.v6; + kr->prefix_scope_id = kf->prefix.scope_id; + kr->nexthop_aid = AID_INET6; if (kf->nexthop.aid == AID_INET6) { - kr6->nexthop = kf->nexthop.v6; - kr6->nexthop_scope_id = kf->nexthop.scope_id; + kr->nexthop.v6 = kf->nexthop.v6; + kr->nexthop_scope_id = kf->nexthop.scope_id; } else - kr6->nexthop = in6addr_any; + kr->nexthop.v6 = in6addr_any; if (kf->prefix.aid == AID_VPN_IPv6) { - kr6->flags |= F_MPLS; - kr6->mplslabel = htonl(mplslabel); + kr->flags |= F_MPLS; + kr->mplslabel = htonl(mplslabel); } + } - kr6->ifindex = kf->ifindex; - kr6->priority = kf->priority; - kr6->labelid = rtlabel_name2id(kf->label); - - if ((kr6m = RB_INSERT(kroute6_tree, &kt->krt6, kr6)) != NULL) { - /* multipath route, add at end of list */ - while (kr6m->next != NULL) - kr6m = kr6m->next; - kr6m->next = kr6; - multipath = 1; - } - - /* check if a kernel route exists */ - if ((kf->flags & F_BGPD) && - kroute6_find(kt, &kf->prefix, kf->prefixlen, RTP_KERN) == - NULL) - if (send_rtmsg(RTM_ADD, kt, kf)) - kr6->flags |= F_BGPD_INSERTED; - break; + if ((krm = RB_INSERT(kroute_tree, &kt->krt, kr)) != NULL) { + /* multipath route, add at end of list */ + while (krm->next != NULL) + krm = krm->next; + krm->next = kr; + multipath = 1; } + /* check if a kernel route exists */ + if ((kf->flags & F_BGPD) && + kroute_find(kt, &kf->prefix, kf->prefixlen, RTP_KERN) == NULL) + if (send_rtmsg(RTM_ADD, kt, kf)) + kr->flags |= F_BGPD_INSERTED; + if (bgpd_has_bgpnh() || !(kf->flags & F_BGPD)) { RB_FOREACH(n, knexthop_tree, KT2KNT(kt)) if (prefix_compare(&kf->prefix, &n->nexthop, @@ -1628,24 +1514,28 @@ return (0); } - -static int -kroute4_remove(struct ktable *kt, struct kroute_full *kf, int any) +int +kroute_remove(struct ktable *kt, struct kroute_full *kf, int any) { + int multipath = 1; struct kroute *kr, *krm; struct knexthop *n; - int multipath = 1; - if ((kr = kroute_find(kt, &kf->prefix, kf->prefixlen, - kf->priority)) == NULL) + if (kf->prefix.aid != AID_INET && kf->prefix.aid != AID_INET6) { + log_warnx("%s: not handled AID", __func__); return (-1); + } + if ((kr = kroute_find(kt, &kf->prefix, kf->prefixlen, kf->priority)) + == NULL) + return (0); + if ((kr->flags & F_BGPD) != (kf->flags & F_BGPD)) { log_warnx("%s: wrong type for %s/%u", __func__, - log_addr(&kf->prefix), kf->prefixlen); + log_addr(&kf->prefix), kf->prefixlen); if (!(kf->flags & F_BGPD)) kr->flags &= ~F_BGPD_INSERTED; - return (-1); + return (0); } /* get the correct route to remove */ @@ -1653,8 +1543,8 @@ if (!any) { if ((krm = kroute_matchgw(kr, kf)) == NULL) { log_warnx("delete %s/%u: route not found", - log_addr(&kf->prefix), kf->prefixlen); - return (-2); + log_addr(&kf->prefix), kf->prefixlen); + return (-1); } } @@ -1664,10 +1554,11 @@ if (krm->next != NULL) { kr = krm->next; if (RB_INSERT(kroute_tree, &kt->krt, kr) != NULL) { - log_warnx("%s: failed to add %s/%u", - __func__, inet_ntoa(kr->prefix), - kr->prefixlen); - return (-2); + log_warnx("%s: failed to add %s/%u", __func__, + (kr->prefix_aid == AID_INET)? + (inet_ntoa(kr->prefix.v4)): + (log_in6addr(&kr->prefix.v6)), kr->prefixlen); + return (-1); } } else { multipath = 0; @@ -1678,8 +1569,11 @@ kr = kr->next; if (kr->next == NULL) { log_warnx("%s: multipath list corrupted for %s/%u", - __func__, inet_ntoa(kr->prefix), kr->prefixlen); - return (-2); + __func__, (kr->prefix_aid == AID_INET)? + (inet_ntoa(kr->prefix.v4)): + (log_in6addr(&kr->prefix.v6)), + kr->prefixlen); + return (-1); } kr->next = krm->next; } @@ -1693,102 +1587,10 @@ } *kf = *kr_tofull(krm); - - rtlabel_unref(krm->labelid); - free(krm); - return (multipath); -} - -static int -kroute6_remove(struct ktable *kt, struct kroute_full *kf, int any) -{ - struct kroute6 *kr, *krm; - struct knexthop *n; - int multipath = 1; - - if ((kr = kroute6_find(kt, &kf->prefix, kf->prefixlen, - kf->priority)) == NULL) - return (-1); - - if ((kr->flags & F_BGPD) != (kf->flags & F_BGPD)) { - log_warnx("%s: wrong type for %s/%u", __func__, - log_addr(&kf->prefix), kf->prefixlen); - if (!(kf->flags & F_BGPD)) - kr->flags &= ~F_BGPD_INSERTED; - return (-1); - } - - /* get the correct route to remove */ - krm = kr; - if (!any) { - if ((krm = kroute6_matchgw(kr, kf)) == NULL) { - log_warnx("delete %s/%u: route not found", - log_addr(&kf->prefix), kf->prefixlen); - return (-2); - } - } - if (krm == kr) { - /* head element */ - RB_REMOVE(kroute6_tree, &kt->krt6, krm); - if (krm->next != NULL) { - kr = krm->next; - if (RB_INSERT(kroute6_tree, &kt->krt6, kr) != NULL) { - log_warnx("%s: failed to add %s/%u", __func__, - log_in6addr(&kr->prefix), kr->prefixlen); - return (-2); - } - } else { - multipath = 0; - } - } else { - /* somewhere in the list */ - while (kr->next != krm && kr->next != NULL) - kr = kr->next; - if (kr->next == NULL) { - log_warnx("%s: multipath list corrupted for %s/%u", - __func__, log_in6addr(&kr->prefix), kr->prefixlen); - return (-2); - } - kr->next = krm->next; - } - - /* check whether a nexthop depends on this kroute */ - if (krm->flags & F_NEXTHOP) { - RB_FOREACH(n, knexthop_tree, KT2KNT(kt)) { - if (n->kroute == krm) - knexthop_validate(kt, n); - } - } - - *kf = *kr6_tofull(krm); - rtlabel_unref(krm->labelid); free(krm); - return (multipath); -} - -int -kroute_remove(struct ktable *kt, struct kroute_full *kf, int any) -{ - int multipath; - - switch (kf->prefix.aid) { - case AID_INET: - multipath = kroute4_remove(kt, kf, any); - break; - case AID_INET6: - multipath = kroute6_remove(kt, kf, any); - break; - default: - log_warnx("%s: not handled AID", __func__); - return (-1); - } - - if (multipath < 0) - return (multipath + 1); - if (kf->flags & F_BGPD_INSERTED) send_rtmsg(RTM_DELETE, kt, kf); @@ -1808,67 +1610,6 @@ kroute_remove(kt, kr_tofull(kr), 1); } -struct kroute6 * -kroute6_find(struct ktable *kt, const struct bgpd_addr *prefix, - uint8_t prefixlen, uint8_t prio) -{ - struct kroute6 s; - struct kroute6 *kn6, *tmp; - - s.prefix = prefix->v6; - s.prefix_scope_id = prefix->scope_id; - s.prefixlen = prefixlen; - s.priority = prio; - - kn6 = RB_FIND(kroute6_tree, &kt->krt6, &s); - if (kn6 && prio == RTP_ANY) { - tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6); - while (tmp) { - if (kroute6_compare(&s, tmp) == 0) - kn6 = tmp; - else - break; - tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6); - } - } - return (kn6); -} - -struct kroute6 * -kroute6_matchgw(struct kroute6 *kr, struct kroute_full *kf) -{ - struct in6_addr nexthop; - - if (kf->flags & F_CONNECTED) { - do { - if (kr->ifindex == kf->ifindex || - kf->ifindex == 0) - return (kr); - kr = kr->next; - } while (kr); - return (NULL); - } - - nexthop = kf->nexthop.v6; - do { - if (memcmp(&kr->nexthop, &nexthop, sizeof(nexthop)) == 0 && - kr->nexthop_scope_id == kf->nexthop.scope_id) - return (kr); - kr = kr->next; - } while (kr); - - return (NULL); -} - -void -kroute6_clear(struct ktable *kt) -{ - struct kroute6 *kr; - - while ((kr = RB_MIN(kroute6_tree, &kt->krt6)) != NULL) - kroute_remove(kt, kr6_tofull(kr), 1); -} - struct knexthop * knexthop_find(struct ktable *kt, struct bgpd_addr *addr) { @@ -2003,26 +1744,6 @@ int kroute_validate(struct kroute *kr) -{ - struct kif *kif; - - if (kr->flags & (F_REJECT | F_BLACKHOLE)) - return (0); - - if ((kif = kif_find(kr->ifindex)) == NULL) { - if (kr->ifindex) - log_warnx("%s: interface with index %d not found, " - "referenced from route for %s/%u", __func__, - kr->ifindex, inet_ntoa(kr->prefix), - kr->prefixlen); - return (1); - } - - return (kif->nh_reachable); -} - -int -kroute6_validate(struct kroute6 *kr) { struct kif *kif; @@ -2033,7 +1754,9 @@ if (kr->ifindex) log_warnx("%s: interface with index %d not found, " "referenced from route for %s/%u", __func__, - kr->ifindex, log_in6addr(&kr->prefix), + kr->ifindex, (kr->prefix_aid == AID_INET)? + inet_ntoa(kr->prefix.v4): + log_in6addr(&kr->prefix.v6), kr->prefixlen); return (1); } @@ -2047,7 +1770,6 @@ struct bgpd_addr gateway = { 0 }; struct knexthop *kn; struct kroute *kr; - struct kroute6 *kr6; /* * Ignore the nexthop for VPN routes. The gateway is forced @@ -2068,21 +1790,19 @@ if (kn->kroute == NULL) return 0; + kr = kn->kroute; + if (kr->flags & F_CONNECTED) + return 1; + switch (kn->nexthop.aid) { case AID_INET: - kr = kn->kroute; - if (kr->flags & F_CONNECTED) - return 1; gateway.aid = AID_INET; - gateway.v4.s_addr = kr->nexthop.s_addr; + gateway.v4 = kr->nexthop.v4; break; case AID_INET6: - kr6 = kn->kroute; - if (kr6->flags & F_CONNECTED) - return 1; gateway.aid = AID_INET6; - gateway.v6 = kr6->nexthop; - gateway.scope_id = kr6->nexthop_scope_id; + gateway.v6 = kr->nexthop.v6; + gateway.scope_id = kr->nexthop_scope_id; break; } @@ -2090,12 +1810,11 @@ return 1; } + void knexthop_validate(struct ktable *kt, struct knexthop *kn) { - void *oldk; - struct kroute *kr; - struct kroute6 *kr6; + struct kroute *kr, *oldk; oldk = kn->kroute; kroute_detach_nexthop(kt, kn); @@ -2103,37 +1822,21 @@ if ((kt = ktable_get(kt->nhtableid)) == NULL) fatalx("%s: lost nexthop routing table", __func__); - switch (kn->nexthop.aid) { - case AID_INET: - kr = kroute_match(kt, &kn->nexthop, 0); + kr = kroute_match(kt, &kn->nexthop, 0); - if (kr != NULL) { - kn->kroute = kr; - kn->ifindex = kr->ifindex; - kr->flags |= F_NEXTHOP; - } - - /* - * Send update if nexthop route changed under us if - * the route remains the same then the NH state has not - * changed. - */ - if (kr != oldk) - knexthop_send_update(kn); - break; - case AID_INET6: - kr6 = kroute6_match(kt, &kn->nexthop, 0); - - if (kr6 != NULL) { - kn->kroute = kr6; - kn->ifindex = kr6->ifindex; - kr6->flags |= F_NEXTHOP; - } - - if (kr6 != oldk) - knexthop_send_update(kn); - break; + if (kr != NULL) { + kn->kroute = kr; + kn->ifindex = kr->ifindex; + kr->flags |= F_NEXTHOP; } + + /* + * Send update if nexthop route changed under us if + * the route remains the same then the NH state has not + * changed. + */ + if (kr != oldk) + knexthop_send_update(kn); } /* @@ -2168,46 +1871,59 @@ { struct kroute_nexthop n; struct kroute *kr; - struct kroute6 *kr6; + uint8_t nh_aid; memset(&n, 0, sizeof(n)); - n.nexthop = kn->nexthop; + nh_aid = kn->nexthop.aid; + n.nexthop.aid = nh_aid; + if (nh_aid == AID_INET) + n.nexthop.v4 = kn->nexthop.v4; + else + n.nexthop.v6 = kn->nexthop.v6; + if (kn->kroute == NULL) { n.valid = 0; /* NH is not valid */ send_nexthop_update(&n); return; } - switch (kn->nexthop.aid) { + kr = kn->kroute; + n.valid = kroute_validate(kr); + n.connected = kr->flags & F_CONNECTED; + + switch (nh_aid) { case AID_INET: - kr = kn->kroute; - n.valid = kroute_validate(kr); - n.connected = kr->flags & F_CONNECTED; if (!n.connected) { n.gateway.aid = AID_INET; - n.gateway.v4.s_addr = kr->nexthop.s_addr; + n.gateway.v4 = kr->nexthop.v4; } else { n.gateway = n.nexthop; - n.net.aid = AID_INET; - n.net.v4.s_addr = kr->prefix.s_addr; + n.net.aid = kr->prefix_aid; + if (kr->prefix_aid == AID_INET) + n.net.v4 = kr->prefix.v4; + else { + n.net.v6 = kr->prefix.v6; + n.net.scope_id = kr->prefix_scope_id; + } n.netlen = kr->prefixlen; } break; case AID_INET6: - kr6 = kn->kroute; - n.valid = kroute6_validate(kr6); - n.connected = kr6->flags & F_CONNECTED; if (!n.connected) { n.gateway.aid = AID_INET6; - n.gateway.v6 = kr6->nexthop; - n.gateway.scope_id = kr6->nexthop_scope_id; + n.gateway.v6 = kr->nexthop.v6; + n.gateway.scope_id = kr->nexthop_scope_id; } else { n.gateway = n.nexthop; - n.net.aid = AID_INET6; - n.net.v6 = kr6->prefix; - n.net.scope_id = kr6->prefix_scope_id; - n.netlen = kr6->prefixlen; + n.net.aid = kr->prefix_aid; + if (kr->prefix_aid == AID_INET6) { + n.net.v6 = kr->prefix.v6; + n.net.scope_id = kr->prefix_scope_id; + } + else + n.net.v4 = kr->prefix.v4; + n.netlen = kr->prefixlen; } break; } @@ -2221,28 +1937,17 @@ struct kroute *kr; struct bgpd_addr masked; - for (i = 32; i >= 0; i--) { + if (key->aid == AID_INET6) + i = 128; + else + i = 32; + + while (i >= 0) { applymask(&masked, key, i); if ((kr = kroute_find(kt, &masked, i, RTP_ANY)) != NULL) if (matchany || bgpd_oknexthop(kr_tofull(kr))) return (kr); - } - - return (NULL); -} - -struct kroute6 * -kroute6_match(struct ktable *kt, struct bgpd_addr *key, int matchany) -{ - int i; - struct kroute6 *kr6; - struct bgpd_addr masked; - - for (i = 128; i >= 0; i--) { - applymask(&masked, key, i); - if ((kr6 = kroute6_find(kt, &masked, i, RTP_ANY)) != NULL) - if (matchany || bgpd_oknexthop(kr6_tofull(kr6))) - return (kr6); + i--; } return (NULL); @@ -2253,7 +1958,6 @@ { struct knexthop *s; struct kroute *k; - struct kroute6 *k6; if (kn->kroute == NULL) return; @@ -2267,16 +1971,8 @@ break; if (s == NULL) { - switch (kn->nexthop.aid) { - case AID_INET: - k = kn->kroute; - k->flags &= ~F_NEXTHOP; - break; - case AID_INET6: - k6 = kn->kroute; - k6->flags &= ~F_NEXTHOP; - break; - } + k = kn->kroute; + k->flags &= ~F_NEXTHOP; } kn->kroute = NULL; @@ -2587,6 +2283,11 @@ if (!kt->fib_sync) return (0); + if (kf->flags & F_MPLS) { + /* no MPLS support */ + return (0); + } + /* initialize header */ memset(&hdr, 0, sizeof(hdr)); hdr.rtm_version = RTM_VERSION; @@ -2645,11 +2346,6 @@ iov[iovcnt].iov_base = &mask; iov[iovcnt++].iov_len = ROUNDUP(salen); - if (kf->flags & F_MPLS) { - /* no MPLS support */ - return (0); - } - /* Silently ignore set routing labels */ retry: @@ -2964,27 +2660,15 @@ kr_fib_delete(struct ktable *kt, struct kroute_full *kf, int mpath) { struct kroute *kr; - struct kroute6 *kr6; int rv; rv = kroute_remove(kt, kf, !mpath); /* check if lower pref bgp route exists */ - switch (kf->prefix.aid) { - case AID_INET: - if ((kr = kroute_find(kt, &kf->prefix, kf->prefixlen, - RTP_MINE)) != NULL) { - if (send_rtmsg(RTM_ADD, kt, kf)) - kr->flags |= F_BGPD_INSERTED; - } - break; - case AID_INET6: - if ((kr6 = kroute6_find(kt, &kf->prefix, kf->prefixlen, - RTP_MINE)) != NULL) { - if (send_rtmsg(RTM_ADD, kt, kf)) - kr6->flags |= F_BGPD_INSERTED; - } - break; + if ((kr = kroute_find(kt, &kf->prefix, kf->prefixlen, + RTP_MINE)) != NULL) { + if (send_rtmsg(RTM_ADD, kt, kf)) + kr->flags |= F_BGPD_INSERTED; } return rv; @@ -2994,151 +2678,109 @@ kr_fib_change(struct ktable *kt, struct kroute_full *kf, int type, int mpath) { struct kroute *kr; - struct kroute6 *kr6; int flags, oflags; int changed = 0, rtlabel_changed = 0; uint16_t new_labelid; flags = kf->flags; - switch (kf->prefix.aid) { - case AID_INET: - if ((kr = kroute_find(kt, &kf->prefix, kf->prefixlen, - kf->priority)) != NULL) { - if (!(kf->flags & F_BGPD)) { - /* get the correct route */ - if (mpath && type == RTM_CHANGE && - (kr = kroute_matchgw(kr, kf)) == NULL) { - log_warnx("%s[change]: " + + if ((kr = kroute_find(kt, &kf->prefix, kf->prefixlen, + kf->priority)) != NULL) { + if (!(kf->flags & F_BGPD)) { + /* get the correct route */ + if (mpath) { + if (type == RTM_CHANGE && + kroute_matchgw(kr, kf) == NULL) { + log_warnx("%s[change]: " "mpath route not found", __func__); - goto add4; - } else if (mpath && type == RTM_ADD) - goto add4; + kroute_insert(kt, kf); + return 0; + } else if (mpath && type == RTM_ADD) { + kroute_insert(kt, kf); + return 0; + } + } + if (kf->prefix.aid == AID_INET) { if (kf->nexthop.aid == AID_INET) { - if (kr->nexthop.s_addr != - kf->nexthop.v4.s_addr) + if (kr->nexthop.v4.s_addr != + kf->nexthop.v4.s_addr) changed = 1; - kr->nexthop.s_addr = - kf->nexthop.v4.s_addr; - kr->ifindex = kf->ifindex; + kr->nexthop.v4 = kf->nexthop.v4; } else { - if (kr->nexthop.s_addr != 0) + if (kr->nexthop.v4.s_addr != 0) changed = 1; - kr->nexthop.s_addr = 0; - kr->ifindex = kf->ifindex; + kr->nexthop.v4.s_addr = 0; } - - if (kr->flags & F_NEXTHOP) - flags |= F_NEXTHOP; - - new_labelid = rtlabel_name2id(kf->label); - if (kr->labelid != new_labelid) { - rtlabel_unref(kr->labelid); - kr->labelid = new_labelid; - rtlabel_changed = 1; - } - - oflags = kr->flags; - if (flags != oflags) - changed = 1; - kr->flags = flags; - - if (rtlabel_changed) - kr_redistribute(IMSG_NETWORK_ADD, - kt, kr_tofull(kr)); - - if ((oflags & F_CONNECTED) && - !(flags & F_CONNECTED)) - kr_redistribute(IMSG_NETWORK_ADD, - kt, kr_tofull(kr)); - if ((flags & F_CONNECTED) && - !(oflags & F_CONNECTED)) - kr_redistribute(IMSG_NETWORK_ADD, - kt, kr_tofull(kr)); - - if (kr->flags & F_NEXTHOP && changed) - knexthop_update(kt, kf); } else { - kr->flags &= ~F_BGPD_INSERTED; - } - } else { -add4: - kroute_insert(kt, kf); - } - break; - case AID_INET6: - if ((kr6 = kroute6_find(kt, &kf->prefix, kf->prefixlen, - kf->priority)) != NULL) { - if (!(kf->flags & F_BGPD)) { - /* get the correct route */ - if (mpath && type == RTM_CHANGE && - (kr6 = kroute6_matchgw(kr6, kf)) == NULL) { - log_warnx("%s[change]: IPv6 mpath " - "route not found", __func__); - goto add6; - } else if (mpath && type == RTM_ADD) - goto add6; - - if (kf->nexthop.aid == AID_INET6) { - if (memcmp(&kr6->nexthop, + if (kf->nexthop.aid == AID_INET6) { + if (memcmp(&kr->nexthop.v6, &kf->nexthop.v6, sizeof(struct in6_addr)) || - kr6->nexthop_scope_id != + kr->nexthop_scope_id != kf->nexthop.scope_id) changed = 1; - kr6->nexthop = kf->nexthop.v6; - kr6->nexthop_scope_id = + kr->nexthop.v6 = kf->nexthop.v6; + kr->nexthop_scope_id = kf->nexthop.scope_id; - kr6->ifindex = kf->ifindex; } else { - if (memcmp(&kr6->nexthop, - &in6addr_any, - sizeof(struct in6_addr))) + if (kr->nexthop.v4.s_addr != + kf->nexthop.v4.s_addr) changed = 1; - kr6->nexthop = in6addr_any; - kr6->nexthop_scope_id = 0; - kr6->ifindex = kf->ifindex; - } + kr->nexthop.v4 = kf->nexthop.v4; + kr->nexthop_scope_id = 0; + } + } - if (kr6->flags & F_NEXTHOP) - flags |= F_NEXTHOP; + kr->ifindex = kf->ifindex; - new_labelid = rtlabel_name2id(kf->label); - if (kr6->labelid != new_labelid) { - rtlabel_unref(kr6->labelid); - kr6->labelid = new_labelid; - rtlabel_changed = 1; - } + if (kr->flags & F_NEXTHOP) + flags |= F_NEXTHOP; - oflags = kr6->flags; - if (flags != oflags) - changed = 1; - kr6->flags = flags; + new_labelid = rtlabel_name2id(kf->label); + if (kr->labelid != new_labelid) { + rtlabel_unref(kr->labelid); + kr->labelid = new_labelid; + rtlabel_changed = 1; + } - if (rtlabel_changed) - kr_redistribute(IMSG_NETWORK_ADD, - kt, kr6_tofull(kr6)); + oflags = kr->flags; + if (flags != oflags) + changed = 1; + kr->flags = flags; - if ((oflags & F_CONNECTED) && - !(flags & F_CONNECTED)) - kr_redistribute(IMSG_NETWORK_ADD, - kt, kr6_tofull(kr6)); - if ((flags & F_CONNECTED) && - !(oflags & F_CONNECTED)) - kr_redistribute(IMSG_NETWORK_ADD, - kt, kr6_tofull(kr6)); + if (rtlabel_changed) + kr_redistribute(IMSG_NETWORK_ADD, + kt, kr_tofull(kr)); - if (kr6->flags & F_NEXTHOP && changed) - knexthop_update(kt, kf); - } else { - kr6->flags &= ~F_BGPD_INSERTED; - } - } else { -add6: - kroute_insert(kt, kf); - } - break; - } + if ((oflags & F_CONNECTED) && + !(flags & F_CONNECTED)) + kr_redistribute(IMSG_NETWORK_ADD, + kt, kr_tofull(kr)); + if ((flags & F_CONNECTED) && + !(oflags & F_CONNECTED)) + kr_redistribute(IMSG_NETWORK_ADD, + kt, kr_tofull(kr)); + if (kr->flags & F_NEXTHOP && changed) + knexthop_update(kt, kf); + } else + kr->flags &= ~F_BGPD_INSERTED; + } else + kroute_insert(kt, kf); + return (0); } + +int kr_rfc5549_support(void) +{ + int rfc5549_val; + size_t rfc5549_len = sizeof(rfc5549_val); + + if (sysctlbyname("kern.features.ipv4_rfc5549_support", + &rfc5549_val, &rfc5549_len, NULL, 0) != -1) + return rfc5549_val; + + return 0; +} +