Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/in6_fib.c
Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/if_dl.h> | #include <net/if_dl.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
#include <net/route_var.h> | #include <net/route_var.h> | ||||
#include <net/route/nhop.h> | |||||
#include <net/route/shared.h> | |||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#ifdef RADIX_MPATH | #ifdef RADIX_MPATH | ||||
#include <net/radix_mpath.h> | #include <net/radix_mpath.h> | ||||
#endif | #endif | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/in_var.h> | #include <netinet/in_var.h> | ||||
#include <netinet/ip_mroute.h> | #include <netinet/ip_mroute.h> | ||||
#include <netinet/ip6.h> | #include <netinet/ip6.h> | ||||
#include <netinet6/in6_fib.h> | #include <netinet6/in6_fib.h> | ||||
#include <netinet6/in6_var.h> | #include <netinet6/in6_var.h> | ||||
#include <netinet6/nd6.h> | #include <netinet6/nd6.h> | ||||
#include <netinet6/scope6_var.h> | #include <netinet6/scope6_var.h> | ||||
#include <net/if_types.h> | #include <net/if_types.h> | ||||
#ifdef INET6 | #ifdef INET6 | ||||
static void fib6_rte_to_nh_extended(struct rtentry *rte, | static void fib6_rte_to_nh_extended(const struct nhop_object *nh, | ||||
const struct in6_addr *dst, uint32_t flags, struct nhop6_extended *pnh6); | const struct in6_addr *dst, uint32_t flags, struct nhop6_extended *pnh6); | ||||
static void fib6_rte_to_nh_basic(struct rtentry *rte, const struct in6_addr *dst, | static void fib6_rte_to_nh_basic(const struct nhop_object *nh, const struct in6_addr *dst, | ||||
uint32_t flags, struct nhop6_basic *pnh6); | uint32_t flags, struct nhop6_basic *pnh6); | ||||
static struct ifnet *fib6_get_ifaifp(struct rtentry *rte); | |||||
#define RNTORT(p) ((struct rtentry *)(p)) | #define RNTORT(p) ((struct rtentry *)(p)) | ||||
#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) | #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) | ||||
CHK_STRUCT_ROUTE_COMPAT(struct route_in6, ro_dst); | CHK_STRUCT_ROUTE_COMPAT(struct route_in6, ro_dst); | ||||
/* | |||||
* Gets real interface for the @rte. | |||||
* Returns rt_ifp for !IFF_LOOPBACK routers. | |||||
* Extracts "real" address interface from interface address | |||||
* loopback routes. | |||||
*/ | |||||
static struct ifnet * | |||||
fib6_get_ifaifp(struct rtentry *rte) | |||||
{ | |||||
struct ifnet *ifp; | |||||
struct sockaddr_dl *sdl; | |||||
ifp = rte->rt_ifp; | |||||
if ((ifp->if_flags & IFF_LOOPBACK) && | |||||
rte->rt_gateway->sa_family == AF_LINK) { | |||||
sdl = (struct sockaddr_dl *)rte->rt_gateway; | |||||
return (ifnet_byindex(sdl->sdl_index)); | |||||
} | |||||
return (ifp); | |||||
} | |||||
static void | static void | ||||
fib6_rte_to_nh_basic(struct rtentry *rte, const struct in6_addr *dst, | fib6_rte_to_nh_basic(const struct nhop_object *nh, const struct in6_addr *dst, | ||||
uint32_t flags, struct nhop6_basic *pnh6) | uint32_t flags, struct nhop6_basic *pnh6) | ||||
{ | { | ||||
struct sockaddr_in6 *gw; | |||||
/* Do explicit nexthop zero unless we're copying it */ | /* Do explicit nexthop zero unless we're copying it */ | ||||
memset(pnh6, 0, sizeof(*pnh6)); | memset(pnh6, 0, sizeof(*pnh6)); | ||||
if ((flags & NHR_IFAIF) != 0) | if ((flags & NHR_IFAIF) != 0) | ||||
pnh6->nh_ifp = fib6_get_ifaifp(rte); | pnh6->nh_ifp = nh->nh_aifp; | ||||
else | else | ||||
pnh6->nh_ifp = rte->rt_ifp; | pnh6->nh_ifp = nh->nh_ifp; | ||||
pnh6->nh_mtu = min(rte->rt_mtu, IN6_LINKMTU(rte->rt_ifp)); | pnh6->nh_mtu = nh->nh_mtu; | ||||
if (rte->rt_flags & RTF_GATEWAY) { | if (nh->nh_flags & NHF_GATEWAY) { | ||||
/* Return address with embedded scope. */ | /* Return address with embedded scope. */ | ||||
gw = (struct sockaddr_in6 *)rte->rt_gateway; | pnh6->nh_addr = nh->gw6_sa.sin6_addr; | ||||
pnh6->nh_addr = gw->sin6_addr; | |||||
} else | } else | ||||
pnh6->nh_addr = *dst; | pnh6->nh_addr = *dst; | ||||
/* Set flags */ | /* Set flags */ | ||||
pnh6->nh_flags = fib_rte_to_nh_flags(rte->rt_flags); | pnh6->nh_flags = nh->nh_flags; | ||||
gw = (struct sockaddr_in6 *)rt_key(rte); | |||||
if (IN6_IS_ADDR_UNSPECIFIED(&gw->sin6_addr)) | |||||
pnh6->nh_flags |= NHF_DEFAULT; | |||||
} | } | ||||
static void | static void | ||||
fib6_rte_to_nh_extended(struct rtentry *rte, const struct in6_addr *dst, | fib6_rte_to_nh_extended(const struct nhop_object *nh, const struct in6_addr *dst, | ||||
uint32_t flags, struct nhop6_extended *pnh6) | uint32_t flags, struct nhop6_extended *pnh6) | ||||
{ | { | ||||
struct sockaddr_in6 *gw; | |||||
/* Do explicit nexthop zero unless we're copying it */ | /* Do explicit nexthop zero unless we're copying it */ | ||||
memset(pnh6, 0, sizeof(*pnh6)); | memset(pnh6, 0, sizeof(*pnh6)); | ||||
if ((flags & NHR_IFAIF) != 0) | if ((flags & NHR_IFAIF) != 0) | ||||
pnh6->nh_ifp = fib6_get_ifaifp(rte); | pnh6->nh_ifp = nh->nh_aifp; | ||||
else | else | ||||
pnh6->nh_ifp = rte->rt_ifp; | pnh6->nh_ifp = nh->nh_ifp; | ||||
pnh6->nh_mtu = min(rte->rt_mtu, IN6_LINKMTU(rte->rt_ifp)); | pnh6->nh_mtu = nh->nh_mtu; | ||||
if (rte->rt_flags & RTF_GATEWAY) { | if (nh->nh_flags & NHF_GATEWAY) { | ||||
/* Return address with embedded scope. */ | /* Return address with embedded scope. */ | ||||
gw = (struct sockaddr_in6 *)rte->rt_gateway; | pnh6->nh_addr = nh->gw6_sa.sin6_addr; | ||||
pnh6->nh_addr = gw->sin6_addr; | |||||
} else | } else | ||||
pnh6->nh_addr = *dst; | pnh6->nh_addr = *dst; | ||||
/* Set flags */ | /* Set flags */ | ||||
pnh6->nh_flags = fib_rte_to_nh_flags(rte->rt_flags); | pnh6->nh_flags = nh->nh_flags; | ||||
gw = (struct sockaddr_in6 *)rt_key(rte); | pnh6->nh_ia = ifatoia6(nh->nh_ifa); | ||||
if (IN6_IS_ADDR_UNSPECIFIED(&gw->sin6_addr)) | |||||
pnh6->nh_flags |= NHF_DEFAULT; | |||||
pnh6->nh_ia = ifatoia6(rte->rt_ifa); | |||||
} | } | ||||
/* | /* | ||||
* Performs IPv6 route table lookup on @dst. Returns 0 on success. | * Performs IPv6 route table lookup on @dst. Returns 0 on success. | ||||
* Stores basic nexthop info into provided @pnh6 structure. | * Stores basic nexthop info into provided @pnh6 structure. | ||||
* Note that | * Note that | ||||
* - nh_ifp represents logical transmit interface (rt_ifp) by default | * - nh_ifp represents logical transmit interface (rt_ifp) by default | ||||
* - nh_ifp represents "address" interface if NHR_IFAIF flag is passed | * - nh_ifp represents "address" interface if NHR_IFAIF flag is passed | ||||
* - mtu from logical transmit interface will be returned. | * - mtu from logical transmit interface will be returned. | ||||
* - nh_ifp cannot be safely dereferenced | * - nh_ifp cannot be safely dereferenced | ||||
* - nh_ifp represents rt_ifp (e.g. if looking up address on | * - nh_ifp represents rt_ifp (e.g. if looking up address on | ||||
* interface "ix0" pointer to "ix0" interface will be returned instead | * interface "ix0" pointer to "ix0" interface will be returned instead | ||||
* of "lo0") | * of "lo0") | ||||
* - howewer mtu from "transmit" interface will be returned. | * - howewer mtu from "transmit" interface will be returned. | ||||
* - scope will be embedded in nh_addr | * - scope will be embedded in nh_addr | ||||
*/ | */ | ||||
int | int | ||||
fib6_lookup_nh_basic(uint32_t fibnum, const struct in6_addr *dst, uint32_t scopeid, | fib6_lookup_nh_basic(uint32_t fibnum, const struct in6_addr *dst, uint32_t scopeid, | ||||
uint32_t flags, uint32_t flowid, struct nhop6_basic *pnh6) | uint32_t flags, uint32_t flowid, struct nhop6_basic *pnh6) | ||||
{ | { | ||||
RIB_RLOCK_TRACKER; | RIB_RLOCK_TRACKER; | ||||
struct rib_head *rh; | struct rib_head *rh; | ||||
struct radix_node *rn; | struct radix_node *rn; | ||||
struct sockaddr_in6 sin6; | struct sockaddr_in6 sin6; | ||||
struct rtentry *rte; | struct nhop_object *nh; | ||||
KASSERT((fibnum < rt_numfibs), ("fib6_lookup_nh_basic: bad fibnum")); | KASSERT((fibnum < rt_numfibs), ("fib6_lookup_nh_basic: bad fibnum")); | ||||
rh = rt_tables_get_rnh(fibnum, AF_INET6); | rh = rt_tables_get_rnh(fibnum, AF_INET6); | ||||
if (rh == NULL) | if (rh == NULL) | ||||
return (ENOENT); | return (ENOENT); | ||||
/* Prepare lookup key */ | /* Prepare lookup key */ | ||||
memset(&sin6, 0, sizeof(sin6)); | memset(&sin6, 0, sizeof(sin6)); | ||||
sin6.sin6_addr = *dst; | sin6.sin6_addr = *dst; | ||||
ae: Do we need to initialize sin6_family here? | |||||
Done Inline ActionsSame as in IPv4 case: radix does not care of anything that is below the address offset in the struct sockaddr_in6. melifaro: Same as in IPv4 case: radix does not care of anything that is below the address offset in the… | |||||
sin6.sin6_len = sizeof(struct sockaddr_in6); | sin6.sin6_len = sizeof(struct sockaddr_in6); | ||||
/* Assume scopeid is valid and embed it directly */ | /* Assume scopeid is valid and embed it directly */ | ||||
if (IN6_IS_SCOPE_LINKLOCAL(dst)) | if (IN6_IS_SCOPE_LINKLOCAL(dst)) | ||||
sin6.sin6_addr.s6_addr16[1] = htons(scopeid & 0xffff); | sin6.sin6_addr.s6_addr16[1] = htons(scopeid & 0xffff); | ||||
RIB_RLOCK(rh); | RIB_RLOCK(rh); | ||||
rn = rh->rnh_matchaddr((void *)&sin6, &rh->head); | rn = rh->rnh_matchaddr((void *)&sin6, &rh->head); | ||||
if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { | if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { | ||||
rte = RNTORT(rn); | nh = RNTORT(rn)->rt_nhop; | ||||
/* Ensure route & ifp is UP */ | /* Ensure route & ifp is UP */ | ||||
if (RT_LINK_IS_UP(rte->rt_ifp)) { | if (RT_LINK_IS_UP(nh->nh_ifp)) { | ||||
fib6_rte_to_nh_basic(rte, &sin6.sin6_addr, flags, pnh6); | fib6_rte_to_nh_basic(nh, &sin6.sin6_addr, flags, pnh6); | ||||
RIB_RUNLOCK(rh); | RIB_RUNLOCK(rh); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
RIB_RUNLOCK(rh); | RIB_RUNLOCK(rh); | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
Show All 12 Lines | |||||
int | int | ||||
fib6_lookup_nh_ext(uint32_t fibnum, const struct in6_addr *dst,uint32_t scopeid, | fib6_lookup_nh_ext(uint32_t fibnum, const struct in6_addr *dst,uint32_t scopeid, | ||||
uint32_t flags, uint32_t flowid, struct nhop6_extended *pnh6) | uint32_t flags, uint32_t flowid, struct nhop6_extended *pnh6) | ||||
{ | { | ||||
RIB_RLOCK_TRACKER; | RIB_RLOCK_TRACKER; | ||||
struct rib_head *rh; | struct rib_head *rh; | ||||
struct radix_node *rn; | struct radix_node *rn; | ||||
struct sockaddr_in6 sin6; | struct sockaddr_in6 sin6; | ||||
struct rtentry *rte; | struct nhop_object *nh; | ||||
KASSERT((fibnum < rt_numfibs), ("fib6_lookup_nh_ext: bad fibnum")); | KASSERT((fibnum < rt_numfibs), ("fib6_lookup_nh_ext: bad fibnum")); | ||||
rh = rt_tables_get_rnh(fibnum, AF_INET6); | rh = rt_tables_get_rnh(fibnum, AF_INET6); | ||||
if (rh == NULL) | if (rh == NULL) | ||||
return (ENOENT); | return (ENOENT); | ||||
/* Prepare lookup key */ | /* Prepare lookup key */ | ||||
memset(&sin6, 0, sizeof(sin6)); | memset(&sin6, 0, sizeof(sin6)); | ||||
sin6.sin6_len = sizeof(struct sockaddr_in6); | sin6.sin6_len = sizeof(struct sockaddr_in6); | ||||
Not Done Inline Actionssin6_family ae: sin6_family | |||||
sin6.sin6_addr = *dst; | sin6.sin6_addr = *dst; | ||||
/* Assume scopeid is valid and embed it directly */ | /* Assume scopeid is valid and embed it directly */ | ||||
if (IN6_IS_SCOPE_LINKLOCAL(dst)) | if (IN6_IS_SCOPE_LINKLOCAL(dst)) | ||||
sin6.sin6_addr.s6_addr16[1] = htons(scopeid & 0xffff); | sin6.sin6_addr.s6_addr16[1] = htons(scopeid & 0xffff); | ||||
RIB_RLOCK(rh); | RIB_RLOCK(rh); | ||||
rn = rh->rnh_matchaddr((void *)&sin6, &rh->head); | rn = rh->rnh_matchaddr((void *)&sin6, &rh->head); | ||||
if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { | if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { | ||||
rte = RNTORT(rn); | nh = RNTORT(rn)->rt_nhop; | ||||
#ifdef RADIX_MPATH | |||||
rte = rt_mpath_select(rte, flowid); | |||||
if (rte == NULL) { | |||||
RIB_RUNLOCK(rh); | |||||
return (ENOENT); | |||||
} | |||||
#endif | |||||
/* Ensure route & ifp is UP */ | /* Ensure route & ifp is UP */ | ||||
if (RT_LINK_IS_UP(rte->rt_ifp)) { | if (RT_LINK_IS_UP(nh->nh_ifp)) { | ||||
fib6_rte_to_nh_extended(rte, &sin6.sin6_addr, flags, | fib6_rte_to_nh_extended(nh, &sin6.sin6_addr, flags, | ||||
pnh6); | pnh6); | ||||
if ((flags & NHR_REF) != 0) { | if ((flags & NHR_REF) != 0) { | ||||
/* TODO: Do lwref on egress ifp's */ | /* TODO: Do lwref on egress ifp's */ | ||||
} | } | ||||
RIB_RUNLOCK(rh); | RIB_RUNLOCK(rh); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
RIB_RUNLOCK(rh); | RIB_RUNLOCK(rh); | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
void | void | ||||
fib6_free_nh_ext(uint32_t fibnum, struct nhop6_extended *pnh6) | fib6_free_nh_ext(uint32_t fibnum, struct nhop6_extended *pnh6) | ||||
{ | { | ||||
} | |||||
/* | |||||
* | |||||
* Assumes scope is deembedded and provided in @scopeid | |||||
*/ | |||||
struct nhop_object * | |||||
fib6_lookup_nh_ptr(uint32_t fibnum, const struct in6_addr *dst6, | |||||
uint32_t scopeid, uint32_t flags, uint32_t flowid) | |||||
{ | |||||
RIB_RLOCK_TRACKER; | |||||
struct rib_head *rh; | |||||
struct radix_node *rn; | |||||
struct nhop_object *nh; | |||||
struct sockaddr_in6 sin6; | |||||
KASSERT((fibnum < rt_numfibs), ("fib6_lookup_nh_ext: 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); | |||||
Not Done Inline Actionssin6_family? ae: sin6_family? | |||||
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)) { | |||||
nh = (RNTORT(rn))->rt_nhop; | |||||
/* Ensure route & ifp is UP */ | |||||
if (RT_LINK_IS_UP(nh->nh_ifp)) { | |||||
if (flags & NHR_REF) | |||||
nhop_ref_object(nh); | |||||
RIB_RUNLOCK(rh); | |||||
return (nh); | |||||
} | |||||
} | |||||
RIB_RUNLOCK(rh); | |||||
RTSTAT_INC(rts_unreach); | |||||
return (NULL); | |||||
} | |||||
inline static int | |||||
check_urpf(const struct nhop_object *nh, uint32_t flags, | |||||
const struct ifnet *src_if) | |||||
{ | |||||
if (src_if != NULL && nh->nh_aifp == src_if) { | |||||
return (1); | |||||
} | |||||
if (src_if == NULL) { | |||||
if ((flags & NHR_NODEFAULT) == 0) | |||||
return (1); | |||||
else if ((nh->nh_flags & NHF_DEFAULT) == 0) | |||||
return (1); | |||||
} | |||||
return (0); | |||||
} | |||||
/* | |||||
* 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_lookup_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 nhop_object *nh; | |||||
struct in6_addr addr; | |||||
int ret; | |||||
KASSERT((fibnum < rt_numfibs), ("fib6_lookup_nh_ext: bad fibnum")); | |||||
rh = rt_tables_get_rnh(fibnum, AF_INET6); | |||||
if (rh == NULL) | |||||
return (0); | |||||
addr = *dst6; | |||||
/* Assume scopeid is valid and embed it directly */ | |||||
if (IN6_IS_SCOPE_LINKLOCAL(dst6)) | |||||
addr.s6_addr16[1] = htons(scopeid & 0xffff); | |||||
RIB_RLOCK(rh); | |||||
rn = rh->rnh_matchaddr((void *)&addr, &rh->head); | |||||
if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) { | |||||
nh = (RNTORT(rn))->rt_nhop; | |||||
ret = check_urpf(nh, flags, src_if); | |||||
RIB_RUNLOCK(rh); | |||||
return (ret); | |||||
} | |||||
RIB_RUNLOCK(rh); | |||||
return (0); | |||||
} | } | ||||
#endif | #endif | ||||
Do we need to initialize sin6_family here?