Index: sys/net/route.h =================================================================== --- sys/net/route.h +++ sys/net/route.h @@ -230,6 +230,7 @@ /* Control plane route request flags */ #define NHR_COPY 0x100 /* Copy rte data */ +#define NHR_UNLOCKED 0x200 /* Do not lock table */ /* * Routing statistics. Index: sys/netinet/in_fib.h =================================================================== --- sys/netinet/in_fib.h +++ sys/netinet/in_fib.h @@ -45,10 +45,15 @@ struct sockaddr_in ro_dst4; }; +struct rtentry; +struct route_nhop_data; + struct nhop_object *fib4_lookup(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, uint32_t flags, uint32_t flowid); int fib4_check_urpf(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, uint32_t flags, const struct ifnet *src_if); +struct rtentry *fib4_lookup_rt(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, + uint32_t flags, struct route_nhop_data *nrd); struct nhop_object *fib4_lookup_debugnet(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, uint32_t flags); uint32_t fib4_calc_software_hash(struct in_addr src, struct in_addr dst, Index: sys/netinet/in_fib.c =================================================================== --- sys/netinet/in_fib.c +++ sys/netinet/in_fib.c @@ -75,7 +75,6 @@ _Static_assert(sizeof(struct _hash_5tuple_ipv4) == 16, "_hash_5tuple_ipv4 size is wrong"); - uint32_t fib4_calc_software_hash(struct in_addr src, struct in_addr dst, unsigned short src_port, unsigned short dst_port, char proto, @@ -119,11 +118,11 @@ return (NULL); /* Prepare lookup key */ - struct sockaddr_in sin4; - memset(&sin4, 0, sizeof(sin4)); - sin4.sin_family = AF_INET; - sin4.sin_len = sizeof(struct sockaddr_in); - sin4.sin_addr = dst; + struct sockaddr_in sin4 = { + .sin_family = AF_INET, + .sin_len = sizeof(struct sockaddr_in), + .sin_addr = dst, + }; nh = NULL; RIB_RLOCK(rh); @@ -181,28 +180,18 @@ return (check_urpf_nhop(nh, flags, src_if)); } -/* - * Performs reverse path forwarding lookup. - * If @src_if is non-zero, verifies that at least 1 path goes via - * this interface. - * If @src_if is zero, verifies that route exist. - * if @flags contains NHR_NOTDEFAULT, do not consider default route. - * - * Returns 1 if route matching conditions is found, 0 otherwise. - */ -int -fib4_check_urpf(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, - uint32_t flags, const struct ifnet *src_if) +static struct nhop_object * +lookup_nhop(uint32_t fibnum, struct in_addr dst, uint32_t scopeid) { RIB_RLOCK_TRACKER; struct rib_head *rh; struct radix_node *rn; - int ret; + struct nhop_object *nh; KASSERT((fibnum < rt_numfibs), ("fib4_check_urpf: bad fibnum")); rh = rt_tables_get_rnh(fibnum, AF_INET); if (rh == NULL) - return (0); + return (NULL); /* Prepare lookup key */ struct sockaddr_in sin4; @@ -210,49 +199,96 @@ sin4.sin_len = sizeof(struct sockaddr_in); sin4.sin_addr = dst; + nh = NULL; RIB_RLOCK(rh); rn = rh->rnh_matchaddr((void *)&sin4, &rh->head); - if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { - ret = check_urpf(RNTORT(rn)->rt_nhop, flags, src_if); - RIB_RUNLOCK(rh); - return (ret); - } + if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) + nh = RNTORT(rn)->rt_nhop; RIB_RUNLOCK(rh); + return (nh); +} + +/* + * Performs reverse path forwarding lookup. + * If @src_if is non-zero, verifies that at least 1 path goes via + * this interface. + * If @src_if is zero, verifies that route exist. + * if @flags contains NHR_NOTDEFAULT, do not consider default route. + * + * Returns 1 if route matching conditions is found, 0 otherwise. + */ +int +fib4_check_urpf(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, + uint32_t flags, const struct ifnet *src_if) +{ + struct nhop_object *nh; + + nh = lookup_nhop(fibnum, dst, scopeid); + if (nh != NULL) + return (check_urpf(nh, flags, src_if)); + return (0); } -struct nhop_object * -fib4_lookup_debugnet(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, - uint32_t flags) +/* + * Function returning prefix match data along with the nexthop data. + * Intended to be used by the control plane code. + * Supported flags: + * NHR_UNLOCKED: do not lock radix during lookup. + * Returns pointer to rtentry and raw nexthop in @rnd. Both rtentry + * and nexthop are safe to use within current epoch. Note: + * Note: rnd_nhop can actually be the nexthop group. + */ +struct rtentry * +fib4_lookup_rt(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, + uint32_t flags, struct route_nhop_data *rnd) { + RIB_RLOCK_TRACKER; struct rib_head *rh; struct radix_node *rn; - struct nhop_object *nh; + struct rtentry *rt; - KASSERT((fibnum < rt_numfibs), ("fib4_lookup_debugnet: bad fibnum")); + KASSERT((fibnum < rt_numfibs), ("fib4_lookup_rt: bad fibnum")); rh = rt_tables_get_rnh(fibnum, AF_INET); if (rh == NULL) return (NULL); /* Prepare lookup key */ - struct sockaddr_in sin4; - memset(&sin4, 0, sizeof(sin4)); - sin4.sin_family = AF_INET; - sin4.sin_len = sizeof(struct sockaddr_in); - sin4.sin_addr = dst; + struct sockaddr_in sin4 = { + .sin_family = AF_INET, + .sin_len = sizeof(struct sockaddr_in), + .sin_addr = dst, + }; - nh = NULL; - /* unlocked lookup */ + rt = NULL; + if (!(flags & NHR_UNLOCKED)) + RIB_RLOCK(rh); rn = rh->rnh_matchaddr((void *)&sin4, &rh->head); if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { - nh = nhop_select((RNTORT(rn))->rt_nhop, 0); + rt = (struct rtentry *)rn; + rnd->rnd_nhop = rt->rt_nhop; + rnd->rnd_weight = rt->rt_weight; + } + if (!(flags & NHR_UNLOCKED)) + RIB_RUNLOCK(rh); + + return (rt); +} + +struct nhop_object * +fib4_lookup_debugnet(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, + uint32_t flags) +{ + struct rtentry *rt; + struct route_nhop_data rnd; + + rt = fib4_lookup_rt(fibnum, dst, scopeid, NHR_UNLOCKED, &rnd); + if (rt != NULL) { + struct nhop_object *nh = nhop_select(rnd.rnd_nhop, 0); /* Ensure route & ifp is UP */ - if (RT_LINK_IS_UP(nh->nh_ifp)) { - if (flags & NHR_REF) - nhop_ref_object(nh); + if (RT_LINK_IS_UP(nh->nh_ifp)) return (nh); - } } return (NULL); Index: sys/netinet6/in6_fib.h =================================================================== --- sys/netinet6/in6_fib.h +++ sys/netinet6/in6_fib.h @@ -32,11 +32,16 @@ #ifndef _NETINET6_IN6_FIB_H_ #define _NETINET6_IN6_FIB_H_ +struct rtentry; +struct route_nhop_data; + struct nhop_object *fib6_lookup(uint32_t fibnum, const struct in6_addr *dst6, uint32_t scopeid, uint32_t flags, uint32_t flowid); int fib6_check_urpf(uint32_t fibnum, const struct in6_addr *dst6, uint32_t scopeid, uint32_t flags, const struct ifnet *src_if); +struct rtentry *fib6_lookup_rt(uint32_t fibnum, const struct in6_addr *dst6, + uint32_t scopeid, uint32_t flags, struct route_nhop_data *rnd); struct nhop_object *fib6_lookup_debugnet(uint32_t fibnum, const struct in6_addr *dst6, uint32_t scopeid, uint32_t flags); uint32_t fib6_calc_software_hash(const struct in6_addr *src, Index: sys/netinet6/in6_fib.c =================================================================== --- sys/netinet6/in6_fib.c +++ sys/netinet6/in6_fib.c @@ -119,19 +119,16 @@ struct rib_head *rh; struct radix_node *rn; struct nhop_object *nh; - struct sockaddr_in6 sin6; KASSERT((fibnum < rt_numfibs), ("fib6_lookup: bad fibnum")); rh = rt_tables_get_rnh(fibnum, AF_INET6); if (rh == NULL) return (NULL); - /* TODO: radix changes */ - //addr = *dst6; - /* Prepare lookup key */ - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_addr = *dst6; + struct sockaddr_in6 sin6 = { + .sin6_len = sizeof(struct sockaddr_in6), + .sin6_addr = *dst6, + }; /* Assume scopeid is valid and embed it directly */ if (IN6_IS_SCOPE_LINKLOCAL(dst6)) @@ -192,86 +189,121 @@ return (check_urpf_nhop(nh, flags, src_if)); } -/* - * Performs reverse path forwarding lookup. - * If @src_if is non-zero, verifies that at least 1 path goes via - * this interface. - * If @src_if is zero, verifies that route exist. - * if @flags contains NHR_NOTDEFAULT, do not consider default route. - * - * Returns 1 if route matching conditions is found, 0 otherwise. - */ -int -fib6_check_urpf(uint32_t fibnum, const struct in6_addr *dst6, - uint32_t scopeid, uint32_t flags, const struct ifnet *src_if) +static struct nhop_object * +lookup_nhop(uint32_t fibnum, const struct in6_addr *dst6, + uint32_t scopeid) { RIB_RLOCK_TRACKER; struct rib_head *rh; struct radix_node *rn; - struct sockaddr_in6 sin6; - int ret; + struct nhop_object *nh; KASSERT((fibnum < rt_numfibs), ("fib6_check_urpf: bad fibnum")); rh = rt_tables_get_rnh(fibnum, AF_INET6); if (rh == NULL) - return (0); + return (NULL); - /* TODO: radix changes */ /* Prepare lookup key */ - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_addr = *dst6; + struct sockaddr_in6 sin6 = { + .sin6_len = sizeof(struct sockaddr_in6), + .sin6_addr = *dst6, + }; /* Assume scopeid is valid and embed it directly */ if (IN6_IS_SCOPE_LINKLOCAL(dst6)) sin6.sin6_addr.s6_addr16[1] = htons(scopeid & 0xffff); + nh = NULL; RIB_RLOCK(rh); rn = rh->rnh_matchaddr((void *)&sin6, &rh->head); - if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { - ret = check_urpf(RNTORT(rn)->rt_nhop, flags, src_if); - RIB_RUNLOCK(rh); - return (ret); - } + if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) + nh = RNTORT(rn)->rt_nhop; RIB_RUNLOCK(rh); + return (nh); +} + +/* + * Performs reverse path forwarding lookup. + * If @src_if is non-zero, verifies that at least 1 path goes via + * this interface. + * If @src_if is zero, verifies that route exist. + * if @flags contains NHR_NOTDEFAULT, do not consider default route. + * + * Returns 1 if route matching conditions is found, 0 otherwise. + */ +int +fib6_check_urpf(uint32_t fibnum, const struct in6_addr *dst6, + uint32_t scopeid, uint32_t flags, const struct ifnet *src_if) +{ + struct nhop_object *nh; + + nh = lookup_nhop(fibnum, dst6, scopeid); + if (nh != NULL) + return (check_urpf(nh, flags, src_if)); return (0); } -struct nhop_object * -fib6_lookup_debugnet(uint32_t fibnum, const struct in6_addr *dst6, - uint32_t scopeid, uint32_t flags) +/* + * Function returning prefix match data along with the nexthop data. + * Intended to be used by the control plane code. + * Supported flags: + * NHR_UNLOCKED: do not lock radix during lookup. + * Returns pointer to rtentry and raw nexthop in @rnd. Both rtentry + * and nexthop are safe to use within current epoch. Note: + * Note: rnd_nhop can actually be the nexthop group. + */ +struct rtentry * +fib6_lookup_rt(uint32_t fibnum, const struct in6_addr *dst6, + uint32_t scopeid, uint32_t flags, struct route_nhop_data *rnd) { + RIB_RLOCK_TRACKER; struct rib_head *rh; struct radix_node *rn; - struct nhop_object *nh; - struct sockaddr_in6 sin6; + struct rtentry *rt; KASSERT((fibnum < rt_numfibs), ("fib6_lookup: bad fibnum")); rh = rt_tables_get_rnh(fibnum, AF_INET6); if (rh == NULL) return (NULL); - /* TODO: radix changes */ - //addr = *dst6; - /* Prepare lookup key */ - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_addr = *dst6; + struct sockaddr_in6 sin6 = { + .sin6_len = sizeof(struct sockaddr_in6), + .sin6_addr = *dst6, + }; /* Assume scopeid is valid and embed it directly */ if (IN6_IS_SCOPE_LINKLOCAL(dst6)) sin6.sin6_addr.s6_addr16[1] = htons(scopeid & 0xffff); + rt = NULL; + if (!(flags & NHR_UNLOCKED)) + RIB_RLOCK(rh); rn = rh->rnh_matchaddr((void *)&sin6, &rh->head); if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { - nh = nhop_select((RNTORT(rn))->rt_nhop, 0); + rt = (struct rtentry *)rn; + rnd->rnd_nhop = rt->rt_nhop; + rnd->rnd_weight = rt->rt_weight; + } + if (!(flags & NHR_UNLOCKED)) + RIB_RUNLOCK(rh); + + return (rt); +} + +struct nhop_object * +fib6_lookup_debugnet(uint32_t fibnum, const struct in6_addr *dst6, + uint32_t scopeid, uint32_t flags) +{ + struct rtentry *rt; + struct route_nhop_data rnd; + + rt = fib6_lookup_rt(fibnum, dst6, scopeid, NHR_UNLOCKED, &rnd); + if (rt != NULL) { + struct nhop_object *nh = nhop_select(rnd.rnd_nhop, 0); /* Ensure route & ifp is UP */ - if (RT_LINK_IS_UP(nh->nh_ifp)) { - if (flags & NHR_REF) - nhop_ref_object(nh); + if (RT_LINK_IS_UP(nh->nh_ifp)) return (nh); - } } return (NULL);