Refactor fib4/fib6 functions.

No functional changes.

* Make lookup path of fib<4|6>_lookup_debugnet() separate functions
 (fib<46>_lookup_rt()). These will be used in the control plane code
 requiring unlocked radix operations and actual prefix pointer.
* Make lookup part of fib<4|6>_check_urpf() separate functions.
 This change simplifies the switch to alternative lookup implementations,
 which helps algorithmic lookups introduction.
* While here, use static initializers for IPv4/IPv6 keys

Differential Revision:	https://reviews.freebsd.org/D27405
This commit is contained in:
Alexander V. Chernikov 2020-11-29 13:41:49 +00:00
parent 98d5c4e5c8
commit b712e3e343
5 changed files with 174 additions and 95 deletions

View File

@ -230,6 +230,7 @@ VNET_DECLARE(u_int, fib_hash_outbound);
/* Control plane route request flags */
#define NHR_COPY 0x100 /* Copy rte data */
#define NHR_UNLOCKED 0x200 /* Do not lock table */
/*
* Routing statistics.

View File

@ -75,7 +75,6 @@ struct _hash_5tuple_ipv4 {
_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 @@ fib4_lookup(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
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,6 +180,35 @@ check_urpf(struct nhop_object *nh, uint32_t flags,
return (check_urpf_nhop(nh, flags, 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;
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 (NULL);
/* Prepare lookup key */
struct sockaddr_in sin4;
memset(&sin4, 0, sizeof(sin4));
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))
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
@ -193,66 +221,74 @@ check_urpf(struct nhop_object *nh, uint32_t flags,
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);
}
/*
* 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;
int ret;
struct rtentry *rt;
KASSERT((fibnum < rt_numfibs), ("fib4_check_urpf: bad fibnum"));
KASSERT((fibnum < rt_numfibs), ("fib4_lookup_rt: bad fibnum"));
rh = rt_tables_get_rnh(fibnum, AF_INET);
if (rh == NULL)
return (0);
return (NULL);
/* Prepare lookup key */
struct sockaddr_in sin4;
memset(&sin4, 0, sizeof(sin4));
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,
};
RIB_RLOCK(rh);
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)) {
ret = check_urpf(RNTORT(rn)->rt_nhop, flags, src_if);
RIB_RUNLOCK(rh);
return (ret);
rt = (struct rtentry *)rn;
rnd->rnd_nhop = rt->rt_nhop;
rnd->rnd_weight = rt->rt_weight;
}
RIB_RUNLOCK(rh);
if (!(flags & NHR_UNLOCKED))
RIB_RUNLOCK(rh);
return (0);
return (rt);
}
struct nhop_object *
fib4_lookup_debugnet(uint32_t fibnum, struct in_addr dst, uint32_t scopeid,
uint32_t flags)
{
struct rib_head *rh;
struct radix_node *rn;
struct nhop_object *nh;
struct rtentry *rt;
struct route_nhop_data rnd;
KASSERT((fibnum < rt_numfibs), ("fib4_lookup_debugnet: 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;
nh = NULL;
/* unlocked lookup */
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 = 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);

View File

@ -45,10 +45,15 @@ struct route_in {
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,

View File

@ -119,19 +119,16 @@ fib6_lookup(uint32_t fibnum, const struct in6_addr *dst6,
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,6 +189,40 @@ check_urpf(struct nhop_object *nh, uint32_t flags,
return (check_urpf_nhop(nh, flags, 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 nhop_object *nh;
KASSERT((fibnum < rt_numfibs), ("fib6_check_urpf: bad fibnum"));
rh = rt_tables_get_rnh(fibnum, AF_INET6);
if (rh == NULL)
return (NULL);
/* Prepare lookup key */
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))
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
@ -205,73 +236,74 @@ int
fib6_check_urpf(uint32_t fibnum, const struct in6_addr *dst6,
uint32_t scopeid, uint32_t flags, const struct ifnet *src_if)
{
RIB_RLOCK_TRACKER;
struct rib_head *rh;
struct radix_node *rn;
struct sockaddr_in6 sin6;
int ret;
KASSERT((fibnum < rt_numfibs), ("fib6_check_urpf: bad fibnum"));
rh = rt_tables_get_rnh(fibnum, AF_INET6);
if (rh == NULL)
return (0);
/* TODO: radix changes */
/* Prepare lookup key */
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.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);
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);
}
RIB_RUNLOCK(rh);
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);

View File

@ -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,