diff options
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 4 | ||||
-rw-r--r-- | usr.sbin/bgpd/kroute.c | 373 |
2 files changed, 297 insertions, 80 deletions
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 39f4d781bbc..fe7b77287b4 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.222 2008/01/23 08:11:32 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.223 2008/12/12 23:15:12 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -424,6 +424,7 @@ struct kroute { u_int16_t labelid; u_short ifindex; u_int8_t prefixlen; + u_int8_t priority; }; struct kroute6 { @@ -433,6 +434,7 @@ struct kroute6 { u_int16_t labelid; u_short ifindex; u_int8_t prefixlen; + u_int8_t priority; }; struct kroute_nexthop { diff --git a/usr.sbin/bgpd/kroute.c b/usr.sbin/bgpd/kroute.c index 22f544f91dc..40b5d60ea44 100644 --- a/usr.sbin/bgpd/kroute.c +++ b/usr.sbin/bgpd/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.161 2008/11/21 17:41:22 claudio Exp $ */ +/* $OpenBSD: kroute.c,v 1.162 2008/12/12 23:15:12 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -48,11 +48,13 @@ struct { struct kroute_node { RB_ENTRY(kroute_node) entry; struct kroute r; + struct kroute_node *next; }; struct kroute6_node { RB_ENTRY(kroute6_node) entry; struct kroute6 r; + struct kroute6_node *next; }; struct knexthop_node { @@ -88,12 +90,17 @@ int kroute6_compare(struct kroute6_node *, struct kroute6_node *); int knexthop_compare(struct knexthop_node *, struct knexthop_node *); int kif_compare(struct kif_node *, struct kif_node *); -struct kroute_node *kroute_find(in_addr_t, u_int8_t); +struct kroute_node *kroute_find(in_addr_t, u_int8_t, u_int8_t); +struct kroute_node *kroute_matchgw(struct kroute_node *, + struct sockaddr_in *); int kroute_insert(struct kroute_node *); int kroute_remove(struct kroute_node *); void kroute_clear(void); -struct kroute6_node *kroute6_find(const struct in6_addr *, u_int8_t); +struct kroute6_node *kroute6_find(const struct in6_addr *, u_int8_t, + u_int8_t); +struct kroute6_node *kroute6_matchgw(struct kroute6_node *, + struct sockaddr_in6 *); int kroute6_insert(struct kroute6_node *); int kroute6_remove(struct kroute6_node *); void kroute6_clear(void); @@ -165,8 +172,8 @@ kr_init(int fs, u_int rtableid) int opt = 0, rcvbuf, default_rcvbuf; socklen_t optlen; - kr_state.fib_sync = fs; kr_state.rtableid = rtableid; + kr_state.fib_sync = fs; if ((kr_state.fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) { log_warn("kr_init: socket"); @@ -220,13 +227,9 @@ kr_change(struct kroute_label *kl) struct kroute_node *kr; int action = RTM_ADD; - if ((kr = kroute_find(kl->kr.prefix.s_addr, kl->kr.prefixlen)) != - NULL) { - if (kr->r.flags & F_BGPD_INSERTED) - action = RTM_CHANGE; - else /* a non-bgp route already exists. not a problem */ - return (0); - } + if ((kr = kroute_find(kl->kr.prefix.s_addr, kl->kr.prefixlen, RTP_BGP)) + != NULL) + action = RTM_CHANGE; /* nexthop within 127/8 -> ignore silently */ if ((kl->kr.nexthop.s_addr & htonl(IN_CLASSA_NET)) == @@ -253,6 +256,7 @@ kr_change(struct kroute_label *kl) kr->r.prefixlen = kl->kr.prefixlen; kr->r.nexthop.s_addr = kl->kr.nexthop.s_addr; kr->r.flags = kl->kr.flags | F_BGPD_INSERTED; + kr->r.priority = RTP_BGP; kr->r.labelid = kl->kr.labelid; if (kroute_insert(kr) == -1) @@ -278,8 +282,8 @@ kr_delete(struct kroute_label *kl) { struct kroute_node *kr; - if ((kr = kroute_find(kl->kr.prefix.s_addr, kl->kr.prefixlen)) == - NULL) + if ((kr = kroute_find(kl->kr.prefix.s_addr, kl->kr.prefixlen, RTP_BGP)) + == NULL) return (0); if (!(kr->r.flags & F_BGPD_INSERTED)) @@ -308,12 +312,9 @@ kr6_change(struct kroute6_label *kl) int action = RTM_ADD; struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT; - if ((kr6 = kroute6_find(&kl->kr.prefix, kl->kr.prefixlen)) != NULL) { - if (kr6->r.flags & F_BGPD_INSERTED) - action = RTM_CHANGE; - else /* a non-bgp route already exists. not a problem */ - return (0); - } + if ((kr6 = kroute6_find(&kl->kr.prefix, kl->kr.prefixlen, RTP_BGP)) + != NULL) + action = RTM_CHANGE; /* nexthop to loopback -> ignore silently */ if (IN6_IS_ADDR_LOOPBACK(&kl->kr.nexthop)) @@ -341,6 +342,7 @@ kr6_change(struct kroute6_label *kl) memcpy(&kr6->r.nexthop, &kl->kr.nexthop, sizeof(struct in6_addr)); kr6->r.flags = kl->kr.flags | F_BGPD_INSERTED; + kr6->r.priority = RTP_BGP; kr6->r.labelid = kl->kr.labelid; if (kroute6_insert(kr6) == -1) @@ -367,7 +369,8 @@ kr6_delete(struct kroute6_label *kl) { struct kroute6_node *kr6; - if ((kr6 = kroute6_find(&kl->kr.prefix, kl->kr.prefixlen)) == NULL) + if ((kr6 = kroute6_find(&kl->kr.prefix, kl->kr.prefixlen, RTP_BGP)) + == NULL) return (0); if (!(kr6->r.flags & F_BGPD_INSERTED)) @@ -510,8 +513,8 @@ kr_nexthop_delete(struct bgpd_addr *addr) void kr_show_route(struct imsg *imsg) { - struct kroute_node *kr; - struct kroute6_node *kr6; + struct kroute_node *kr, *kn; + struct kroute6_node *kr6, *kn6; struct bgpd_addr *addr; int flags; sa_family_t af; @@ -531,16 +534,26 @@ kr_show_route(struct imsg *imsg) memcpy(&af, (char *)imsg->data + sizeof(flags), sizeof(af)); if (!af || af == AF_INET) RB_FOREACH(kr, kroute_tree, &krt) - if (!flags || kr->r.flags & flags) - send_imsg_session(IMSG_CTL_KROUTE, - imsg->hdr.pid, &kr->r, - sizeof(kr->r)); + if (!flags || kr->r.flags & flags) { + kn = kr; + do { + send_imsg_session( + IMSG_CTL_KROUTE, + imsg->hdr.pid, &kn->r, + sizeof(kn->r)); + } while ((kn = kn->next) != NULL); + } if (!af || af == AF_INET6) RB_FOREACH(kr6, kroute6_tree, &krt6) - if (!flags || kr6->r.flags & flags) - send_imsg_session(IMSG_CTL_KROUTE6, - imsg->hdr.pid, &kr6->r, - sizeof(kr6->r)); + if (!flags || kr6->r.flags & flags) { + kn6 = kr6; + do { + send_imsg_session( + IMSG_CTL_KROUTE6, + imsg->hdr.pid, &kn6->r, + sizeof(kn6->r)); + } while ((kn6 = kn6->next) != NULL); + } break; case IMSG_CTL_KROUTE_ADDR: if (imsg->hdr.len != IMSG_HEADER_SIZE + @@ -792,6 +805,14 @@ kroute_compare(struct kroute_node *a, struct kroute_node *b) return (-1); if (a->r.prefixlen > b->r.prefixlen) return (1); + + /* if the priority is RTP_ANY finish on the first address hit */ + if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY) + return (0); + if (a->r.priority < b->r.priority) + return (-1); + if (a->r.priority > b->r.priority) + return (1); return (0); } @@ -811,6 +832,14 @@ kroute6_compare(struct kroute6_node *a, struct kroute6_node *b) return (-1); if (a->r.prefixlen > b->r.prefixlen) return (1); + + /* if the priority is RTP_ANY finish on the first address hit */ + if (a->r.priority == RTP_ANY || b->r.priority == RTP_ANY) + return (0); + if (a->r.priority < b->r.priority) + return (-1); + if (a->r.priority > b->r.priority) + return (1); return (0); } @@ -854,27 +883,65 @@ kif_compare(struct kif_node *a, struct kif_node *b) */ struct kroute_node * -kroute_find(in_addr_t prefix, u_int8_t prefixlen) +kroute_find(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio) { struct kroute_node s; + struct kroute_node *kn, *tmp; s.r.prefix.s_addr = prefix; s.r.prefixlen = prefixlen; + s.r.priority = prio; + + kn = RB_FIND(kroute_tree, &krt, &s); + if (kn && prio == RTP_ANY) { + tmp = RB_PREV(kroute_tree, &krt, kn); + while (tmp) { + if (kroute_compare(&s, tmp) == 0) + kn = tmp; + else + break; + tmp = RB_PREV(kroute_tree, &krt, kn); + } + } + return (kn); +} + +struct kroute_node * +kroute_matchgw(struct kroute_node *kr, struct sockaddr_in *sa_in) +{ + in_addr_t nexthop; - return (RB_FIND(kroute_tree, &krt, &s)); + if (sa_in == NULL) { + log_warnx("kroute_matchgw: no nexthop defined"); + return (NULL); + } + nexthop = sa_in->sin_addr.s_addr; +log_debug("kroute_matchgw: prefix %s/%u", inet_ntoa(kr->r.prefix), kr->r.prefixlen); +log_debug("kroute_matchgw: nexthop = %s", inet_ntoa(sa_in->sin_addr)); + + while (kr) { +log_debug("kroute_matchgw: kr->r.nexthop = %s", inet_ntoa(kr->r.nexthop)); + if (kr->r.nexthop.s_addr == nexthop) + return (kr); + kr = kr->next; + } + + return (NULL); } int kroute_insert(struct kroute_node *kr) { + struct kroute_node *krm; struct knexthop_node *h; in_addr_t mask, ina; - if (RB_INSERT(kroute_tree, &krt, kr) != NULL) { - log_warnx("kroute_tree insert failed for %s/%u", - inet_ntoa(kr->r.prefix), kr->r.prefixlen); - free(kr); - return (-1); + if ((krm = RB_INSERT(kroute_tree, &krt, kr)) != NULL) { + /* multipath route, add at end of list */ + while (krm->next != NULL) + krm = krm->next; + krm->next = kr; + kr->next = NULL; /* to be sure */ } if (kr->r.flags & F_KERNEL) { @@ -889,29 +956,61 @@ kroute_insert(struct kroute_node *kr) if (kif_kr_insert(kr) == -1) return (-1); - kr_redistribute(IMSG_NETWORK_ADD, &kr->r); + if (krm == NULL) + /* redistribute multipath routes only once */ + kr_redistribute(IMSG_NETWORK_ADD, &kr->r); } return (0); } + int kroute_remove(struct kroute_node *kr) { + struct kroute_node *krm; struct knexthop_node *s; - if (RB_REMOVE(kroute_tree, &krt, kr) == NULL) { - log_warnx("kroute_remove failed for %s/%u", + if ((krm = RB_FIND(kroute_tree, &krt, kr)) == NULL) { + log_warnx("kroute_remove failed to find %s/%u", inet_ntoa(kr->r.prefix), kr->r.prefixlen); return (-1); } + if (krm == kr) { + /* head element */ + if (RB_REMOVE(kroute_tree, &krt, kr) == NULL) { + log_warnx("kroute_remove failed for %s/%u", + inet_ntoa(kr->r.prefix), kr->r.prefixlen); + return (-1); + } + if (kr->next != NULL) { + if (RB_INSERT(kroute_tree, &krt, kr->next) != NULL) { + log_warnx("kroute_remove failed to add %s/%u", + inet_ntoa(kr->r.prefix), kr->r.prefixlen); + return (-1); + } + } + } else { + /* somewhere in the list */ + while (krm->next != kr && krm->next != NULL) + krm = krm->next; + if (krm->next == NULL) { + log_warnx("kroute_remove multipath list corrupted " + "for %s/%u", inet_ntoa(kr->r.prefix), + kr->r.prefixlen); + return (-1); + } + krm->next = kr->next; + } + /* check whether a nexthop depends on this kroute */ if ((kr->r.flags & F_KERNEL) && (kr->r.flags & F_NEXTHOP)) RB_FOREACH(s, knexthop_tree, &knt) if (s->kroute == kr) knexthop_validate(s); - if (kr->r.flags & F_KERNEL) + if (kr->r.flags & F_KERNEL && kr == krm && kr->next == NULL) + /* again remove only once */ kr_redistribute(IMSG_NETWORK_REMOVE, &kr->r); if (kr->r.flags & F_CONNECTED) @@ -934,27 +1033,62 @@ kroute_clear(void) } struct kroute6_node * -kroute6_find(const struct in6_addr *prefix, u_int8_t prefixlen) +kroute6_find(const struct in6_addr *prefix, u_int8_t prefixlen, u_int8_t prio) { struct kroute6_node s; + struct kroute6_node *kn6, *tmp; memcpy(&s.r.prefix, prefix, sizeof(struct in6_addr)); s.r.prefixlen = prefixlen; + s.r.priority = prio; + + kn6 = RB_FIND(kroute6_tree, &krt6, &s); + if (kn6 && prio == RTP_ANY) { + tmp = RB_PREV(kroute6_tree, &krt6, kn6); + while (tmp) { + if (kroute6_compare(&s, tmp) == 0) + kn6 = tmp; + else + break; + tmp = RB_PREV(kroute6_tree, &krt6, kn6); + } + } + return (kn6); +} + +struct kroute6_node * +kroute6_matchgw(struct kroute6_node *kr, struct sockaddr_in6 *sa_in6) +{ + struct in6_addr nexthop; + + if (sa_in6 == NULL) { + log_warnx("kroute6_matchgw: no nexthop defined"); + return (NULL); + } + memcpy(&nexthop, &sa_in6->sin6_addr, sizeof(nexthop)); - return (RB_FIND(kroute6_tree, &krt6, &s)); + while (kr) { + if (memcmp(&kr->r.nexthop, &nexthop, sizeof(nexthop)) == NULL) + return (kr); + kr = kr->next; + } + + return (NULL); } int kroute6_insert(struct kroute6_node *kr) { + struct kroute6_node *krm; struct knexthop_node *h; struct in6_addr ina, inb; - if (RB_INSERT(kroute6_tree, &krt6, kr) != NULL) { - log_warnx("kroute_tree insert failed for %s/%u", - log_in6addr(&kr->r.prefix), kr->r.prefixlen); - free(kr); - return (-1); + if ((krm = RB_INSERT(kroute6_tree, &krt6, kr)) != NULL) { + /* multipath route, add at end of list */ + while (krm->next != NULL) + krm = krm->next; + krm->next = kr; + kr->next = NULL; /* to be sure */ } if (kr->r.flags & F_KERNEL) { @@ -971,7 +1105,9 @@ kroute6_insert(struct kroute6_node *kr) if (kif_kr6_insert(kr) == -1) return (-1); - kr_redistribute6(IMSG_NETWORK_ADD, &kr->r); + if (krm == NULL) + /* redistribute multipath routes only once */ + kr_redistribute6(IMSG_NETWORK_ADD, &kr->r); } return (0); @@ -980,21 +1116,51 @@ kroute6_insert(struct kroute6_node *kr) int kroute6_remove(struct kroute6_node *kr) { + struct kroute6_node *krm; struct knexthop_node *s; - if (RB_REMOVE(kroute6_tree, &krt6, kr) == NULL) { - log_warnx("kroute_remove failed for %s/%u", + if ((krm = RB_FIND(kroute6_tree, &krt6, kr)) == NULL) { + log_warnx("kroute6_remove failed for %s/%u", log_in6addr(&kr->r.prefix), kr->r.prefixlen); return (-1); } + if (krm == kr) { + /* head element */ + if (RB_REMOVE(kroute6_tree, &krt6, kr) == NULL) { + log_warnx("kroute6_remove failed for %s/%u", + log_in6addr(&kr->r.prefix), kr->r.prefixlen); + return (-1); + } + if (kr->next != NULL) { + if (RB_INSERT(kroute6_tree, &krt6, kr->next) != NULL) { + log_warnx("kroute6_remove failed to add %s/%u", + log_in6addr(&kr->r.prefix), + kr->r.prefixlen); + return (-1); + } + } + } else { + /* somewhere in the list */ + while (krm->next != kr && krm->next != NULL) + krm = krm->next; + if (krm->next == NULL) { + log_warnx("kroute6_remove multipath list corrupted " + "for %s/%u", log_in6addr(&kr->r.prefix), + kr->r.prefixlen); + return (-1); + } + krm->next = kr->next; + } + /* check whether a nexthop depends on this kroute */ if ((kr->r.flags & F_KERNEL) && (kr->r.flags & F_NEXTHOP)) RB_FOREACH(s, knexthop_tree, &knt) if (s->kroute == kr) knexthop_validate(s); - if (kr->r.flags & F_KERNEL) + if (kr->r.flags & F_KERNEL && kr == krm && kr->next == NULL) + /* again remove only once */ kr_redistribute6(IMSG_NETWORK_REMOVE, &kr->r); if (kr->r.flags & F_CONNECTED) @@ -1426,13 +1592,13 @@ kroute_match(in_addr_t key, int matchall) /* we will never match the default route */ for (i = 32; i > 0; i--) - if ((kr = - kroute_find(htonl(ina & prefixlen2mask(i)), i)) != NULL) + if ((kr = kroute_find(htonl(ina & prefixlen2mask(i)), i, + RTP_ANY)) != NULL) if (matchall || bgpd_filternexthop(&kr->r, NULL) == 0) return (kr); /* if we don't have a match yet, try to find a default route */ - if ((kr = kroute_find(0, 0)) != NULL) + if ((kr = kroute_find(0, 0, RTP_ANY)) != NULL) if (matchall || bgpd_filternexthop(&kr->r, NULL) == 0) return (kr); @@ -1449,13 +1615,13 @@ kroute6_match(struct in6_addr *key, int matchall) /* we will never match the default route */ for (i = 128; i > 0; i--) { inet6applymask(&ina, key, i); - if ((kr6 = kroute6_find(&ina, i)) != NULL) + if ((kr6 = kroute6_find(&ina, i, RTP_ANY)) != NULL) if (matchall || bgpd_filternexthop(NULL, &kr6->r) == 0) return (kr6); } /* if we don't have a match yet, try to find a default route */ - if ((kr6 = kroute6_find(&in6addr_any, 0)) != NULL) + if ((kr6 = kroute6_find(&in6addr_any, 0, RTP_ANY)) != NULL) if (matchall || bgpd_filternexthop(NULL, &kr6->r) == 0) return (kr6); @@ -1798,7 +1964,6 @@ send_rtmsg(int fd, int action, struct kroute *kroute) hdr.rtm_version = RTM_VERSION; hdr.rtm_type = action; hdr.rtm_tableid = kr_state.rtableid; - hdr.rtm_flags = RTF_PROTO1; hdr.rtm_priority = RTP_BGP; if (kroute->flags & F_BLACKHOLE) hdr.rtm_flags |= RTF_BLACKHOLE; @@ -1911,7 +2076,6 @@ send_rt6msg(int fd, int action, struct kroute6 *kroute) hdr.rtm_version = RTM_VERSION; hdr.rtm_type = action; hdr.rtm_tableid = kr_state.rtableid; - hdr.rtm_flags = RTF_PROTO1; if (kroute->flags & F_BLACKHOLE) hdr.rtm_flags |= RTF_BLACKHOLE; if (kroute->flags & F_REJECT) @@ -2056,10 +2220,6 @@ fetchtable(u_int rtableid, int connected_only) if (rtm->rtm_flags & RTF_LLINFO) /* arp cache */ continue; -#ifdef RTF_MPATH - if (rtm->rtm_flags & RTF_MPATH) /* multipath */ - continue; -#endif switch (sa->sa_family) { case AF_INET: if ((kr = calloc(1, sizeof(struct kroute_node))) == @@ -2070,6 +2230,7 @@ fetchtable(u_int rtableid, int connected_only) } kr->r.flags = F_KERNEL; + kr->r.priority = rtm->rtm_priority; kr->r.ifindex = rtm->rtm_index; kr->r.prefix.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; @@ -2102,6 +2263,7 @@ fetchtable(u_int rtableid, int connected_only) } kr6->r.flags = F_KERNEL; + kr6->r.priority = rtm->rtm_priority; kr6->r.ifindex = rtm->rtm_index; memcpy(&kr6->r.prefix, &((struct sockaddr_in6 *)sa)->sin6_addr, @@ -2153,7 +2315,7 @@ fetchtable(u_int rtableid, int connected_only) } if (sa->sa_family == AF_INET) { - if (rtm->rtm_flags & RTF_PROTO1) { + if (rtm->rtm_priority == RTP_BGP) { send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r); free(kr); } else if (connected_only && @@ -2162,7 +2324,7 @@ fetchtable(u_int rtableid, int connected_only) else kroute_insert(kr); } else if (sa->sa_family == AF_INET6) { - if (rtm->rtm_flags & RTF_PROTO1) { + if (rtm->rtm_priority == RTP_BGP) { send_rt6msg(kr_state.fd, RTM_DELETE, &kr6->r); free(kr6); } else if (connected_only && @@ -2329,9 +2491,10 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], struct kroute_node *kr; struct kroute6_node *kr6; struct bgpd_addr prefix; - int flags, oflags; + int flags, oflags, mpath = 0; u_int16_t ifindex; u_int8_t prefixlen; + u_int8_t prio; flags = F_KERNEL; ifindex = 0; @@ -2349,7 +2512,12 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], flags |= F_REJECT; if (rtm->rtm_flags & RTF_DYNAMIC) flags |= F_DYNAMIC; +#ifdef RTF_MPATH + if (rtm->rtm_flags & RTF_MPATH) + mpath = 1; +#endif + prio = rtm->rtm_priority; prefix.af = sa->sa_family; switch (prefix.af) { case AF_INET: @@ -2381,22 +2549,54 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], return (0); } + if ((sa = rti_info[RTAX_GATEWAY]) != NULL) + switch (sa->sa_family) { + case AF_LINK: + flags |= F_CONNECTED; + ifindex = rtm->rtm_index; + sa = NULL; + mpath = 0; /* link local stuff can't be mpath */ + break; + } + if (rtm->rtm_type == RTM_DELETE) { switch (prefix.af) { case AF_INET: + sa_in = (struct sockaddr_in *)sa; if ((kr = kroute_find(prefix.v4.s_addr, - prefixlen)) == NULL) + prefixlen, prio)) == NULL) return (0); if (!(kr->r.flags & F_KERNEL)) return (0); + + if (mpath) + /* get the correct route */ + if ((kr = kroute_matchgw(kr, sa_in)) == NULL) { + log_warnx("dispatch_rtmsg[delete] " + "mpath route not found"); + return (-1); + } + if (kroute_remove(kr) == -1) return (-1); break; case AF_INET6: - if ((kr6 = kroute6_find(&prefix.v6, prefixlen)) == NULL) + sa_in6 = (struct sockaddr_in6 *)sa; + if ((kr6 = kroute6_find(&prefix.v6, prefixlen, + prio)) == NULL) return (0); if (!(kr6->r.flags & F_KERNEL)) return (0); + + if (mpath) + /* get the correct route */ + if ((kr6 = kroute6_matchgw(kr6, sa_in6)) == + NULL) { + log_warnx("dispatch_rtmsg[delete] " + "mpath route not found"); + return (-1); + } + if (kroute6_remove(kr6) == -1) return (-1); break; @@ -2404,15 +2604,6 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], return (0); } - if ((sa = rti_info[RTAX_GATEWAY]) != NULL) - switch (sa->sa_family) { - case AF_LINK: - flags |= F_CONNECTED; - ifindex = rtm->rtm_index; - sa = NULL; - break; - } - if (connected_only && !(flags & F_CONNECTED)) return (0); @@ -2425,8 +2616,18 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], switch (prefix.af) { case AF_INET: sa_in = (struct sockaddr_in *)sa; - if ((kr = kroute_find(prefix.v4.s_addr, prefixlen)) != NULL) { + if ((kr = kroute_find(prefix.v4.s_addr, prefixlen, + prio)) != NULL) { if (kr->r.flags & F_KERNEL) { + /* get the correct route */ + if (mpath && rtm->rtm_type == RTM_CHANGE && + (kr = kroute_matchgw(kr, sa_in)) == NULL) { + log_warnx("dispatch_rtmsg[change] " + "mpath route not found"); + return (-1); + } else if (mpath && rtm->rtm_type == RTM_ADD) + goto add4; + if (sa_in != NULL) kr->r.nexthop.s_addr = sa_in->sin_addr.s_addr; @@ -2457,6 +2658,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], log_addr(&prefix), prefixlen); return (0); } else { +add4: if ((kr = calloc(1, sizeof(struct kroute_node))) == NULL) { log_warn("dispatch_rtmsg"); @@ -2470,14 +2672,25 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], kr->r.nexthop.s_addr = 0; kr->r.flags = flags; kr->r.ifindex = ifindex; + kr->r.priority = prio; kroute_insert(kr); } break; case AF_INET6: sa_in6 = (struct sockaddr_in6 *)sa; - if ((kr6 = kroute6_find(&prefix.v6, prefixlen)) != NULL) { + if ((kr6 = kroute6_find(&prefix.v6, prefixlen, prio)) != NULL) { if (kr6->r.flags & F_KERNEL) { + /* get the correct route */ + if (mpath && rtm->rtm_type == RTM_CHANGE && + (kr6 = kroute6_matchgw(kr6, sa_in6)) == + NULL) { + log_warnx("dispatch_rtmsg[change] " + "mpath route not found"); + return (-1); + } else if (mpath && rtm->rtm_type == RTM_ADD) + goto add6; + if (sa_in6 != NULL) memcpy(&kr6->r.nexthop, &sa_in6->sin6_addr, @@ -2511,6 +2724,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], log_addr(&prefix), prefixlen); return (0); } else { +add6: if ((kr6 = calloc(1, sizeof(struct kroute6_node))) == NULL) { log_warn("dispatch_rtmsg"); @@ -2527,6 +2741,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], sizeof(struct in6_addr)); kr6->r.flags = flags; kr6->r.ifindex = ifindex; + kr6->r.priority = prio; kroute6_insert(kr6); } |