Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/in_fib.c
Show First 20 Lines • Show All 43 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/in_fib.h> | #include <netinet/in_fib.h> | ||||
#ifdef INET | #ifdef INET | ||||
static void fib4_rte_to_nh_basic(struct rtentry *rte, struct in_addr dst, | static void fib4_rte_to_nh_basic(struct nhop_object *nh, struct in_addr dst, | ||||
uint32_t flags, struct nhop4_basic *pnh4); | uint32_t flags, struct nhop4_basic *pnh4); | ||||
static void fib4_rte_to_nh_extended(struct rtentry *rte, struct in_addr dst, | static void fib4_rte_to_nh_extended(struct nhop_object *nh, struct in_addr dst, | ||||
uint32_t flags, struct nhop4_extended *pnh4); | uint32_t flags, struct nhop4_extended *pnh4); | ||||
#define RNTORT(p) ((struct rtentry *)(p)) | #define RNTORT(p) ((struct rtentry *)(p)) | ||||
static void | static void | ||||
fib4_rte_to_nh_basic(struct rtentry *rte, struct in_addr dst, | fib4_rte_to_nh_basic(struct nhop_object *nh, struct in_addr dst, | ||||
uint32_t flags, struct nhop4_basic *pnh4) | uint32_t flags, struct nhop4_basic *pnh4) | ||||
{ | { | ||||
struct sockaddr_in *gw; | |||||
if ((flags & NHR_IFAIF) != 0) | if ((flags & NHR_IFAIF) != 0) | ||||
pnh4->nh_ifp = rte->rt_ifa->ifa_ifp; | pnh4->nh_ifp = nh->nh_ifa->ifa_ifp; | ||||
else | else | ||||
pnh4->nh_ifp = rte->rt_ifp; | pnh4->nh_ifp = nh->nh_ifp; | ||||
pnh4->nh_mtu = min(rte->rt_mtu, rte->rt_ifp->if_mtu); | pnh4->nh_mtu = nh->nh_mtu; | ||||
if (rte->rt_flags & RTF_GATEWAY) { | if (nh->nh_flags & NHF_GATEWAY) | ||||
gw = (struct sockaddr_in *)rte->rt_gateway; | pnh4->nh_addr = nh->gw4_sa.sin_addr; | ||||
pnh4->nh_addr = gw->sin_addr; | else | ||||
} else | |||||
pnh4->nh_addr = dst; | pnh4->nh_addr = dst; | ||||
/* Set flags */ | /* Set flags */ | ||||
pnh4->nh_flags = fib_rte_to_nh_flags(rte->rt_flags); | pnh4->nh_flags = nh->nh_flags; | ||||
gw = (struct sockaddr_in *)rt_key(rte); | |||||
if (gw->sin_addr.s_addr == 0) | |||||
pnh4->nh_flags |= NHF_DEFAULT; | |||||
/* TODO: Handle RTF_BROADCAST here */ | /* TODO: Handle RTF_BROADCAST here */ | ||||
} | } | ||||
static void | static void | ||||
fib4_rte_to_nh_extended(struct rtentry *rte, struct in_addr dst, | fib4_rte_to_nh_extended(struct nhop_object *nh, struct in_addr dst, | ||||
uint32_t flags, struct nhop4_extended *pnh4) | uint32_t flags, struct nhop4_extended *pnh4) | ||||
{ | { | ||||
struct sockaddr_in *gw; | |||||
if ((flags & NHR_IFAIF) != 0) | if ((flags & NHR_IFAIF) != 0) | ||||
pnh4->nh_ifp = rte->rt_ifa->ifa_ifp; | pnh4->nh_ifp = nh->nh_ifa->ifa_ifp; | ||||
else | else | ||||
pnh4->nh_ifp = rte->rt_ifp; | pnh4->nh_ifp = nh->nh_ifp; | ||||
pnh4->nh_mtu = min(rte->rt_mtu, rte->rt_ifp->if_mtu); | pnh4->nh_mtu = nh->nh_mtu; | ||||
if (rte->rt_flags & RTF_GATEWAY) { | if (nh->nh_flags & NHF_GATEWAY) | ||||
gw = (struct sockaddr_in *)rte->rt_gateway; | pnh4->nh_addr = nh->gw4_sa.sin_addr; | ||||
pnh4->nh_addr = gw->sin_addr; | else | ||||
} else | |||||
pnh4->nh_addr = dst; | pnh4->nh_addr = dst; | ||||
/* Set flags */ | /* Set flags */ | ||||
pnh4->nh_flags = fib_rte_to_nh_flags(rte->rt_flags); | pnh4->nh_flags = nh->nh_flags; | ||||
gw = (struct sockaddr_in *)rt_key(rte); | pnh4->nh_ia = ifatoia(nh->nh_ifa); | ||||
if (gw->sin_addr.s_addr == 0) | |||||
pnh4->nh_flags |= NHF_DEFAULT; | |||||
pnh4->nh_ia = ifatoia(rte->rt_ifa); | |||||
pnh4->nh_src = IA_SIN(pnh4->nh_ia)->sin_addr; | pnh4->nh_src = IA_SIN(pnh4->nh_ia)->sin_addr; | ||||
} | } | ||||
/* | /* | ||||
* Performs IPv4 route table lookup on @dst. Returns 0 on success. | * Performs IPv4 route table lookup on @dst. Returns 0 on success. | ||||
* Stores nexthop info provided @pnh4 structure. | * Stores nexthop info provided @pnh4 structure. | ||||
* Note that | * Note that | ||||
* - nh_ifp cannot be safely dereferenced | * - nh_ifp cannot be safely dereferenced | ||||
* - nh_ifp represents logical transmit interface (rt_ifp) (e.g. if | * - nh_ifp represents logical transmit interface (rt_ifp) (e.g. if | ||||
* looking up address on interface "ix0" pointer to "lo0" interface | * looking up address on interface "ix0" pointer to "lo0" interface | ||||
* will be returned instead of "ix0") | * will be returned instead of "ix0") | ||||
* - nh_ifp represents "address" interface if NHR_IFAIF flag is passed | * - nh_ifp represents "address" interface if NHR_IFAIF flag is passed | ||||
* - howewer mtu from "transmit" interface will be returned. | * - howewer mtu from "transmit" interface will be returned. | ||||
*/ | */ | ||||
int | int | ||||
fib4_lookup_nh_basic(uint32_t fibnum, struct in_addr dst, uint32_t flags, | fib4_lookup_nh_basic(uint32_t fibnum, struct in_addr dst, uint32_t flags, | ||||
uint32_t flowid, struct nhop4_basic *pnh4) | uint32_t flowid, struct nhop4_basic *pnh4) | ||||
{ | { | ||||
RIB_RLOCK_TRACKER; | RIB_RLOCK_TRACKER; | ||||
struct rib_head *rh; | struct rib_head *rh; | ||||
struct radix_node *rn; | struct radix_node *rn; | ||||
struct sockaddr_in sin; | struct sockaddr_in sin; | ||||
struct rtentry *rte; | struct nhop_object *nh; | ||||
KASSERT((fibnum < rt_numfibs), ("fib4_lookup_nh_basic: bad fibnum")); | KASSERT((fibnum < rt_numfibs), ("fib4_lookup_nh_basic: bad fibnum")); | ||||
rh = rt_tables_get_rnh(fibnum, AF_INET); | rh = rt_tables_get_rnh(fibnum, AF_INET); | ||||
if (rh == NULL) | if (rh == NULL) | ||||
return (ENOENT); | return (ENOENT); | ||||
/* Prepare lookup key */ | /* Prepare lookup key */ | ||||
memset(&sin, 0, sizeof(sin)); | memset(&sin, 0, sizeof(sin)); | ||||
sin.sin_len = sizeof(struct sockaddr_in); | sin.sin_len = sizeof(struct sockaddr_in); | ||||
sin.sin_addr = dst; | sin.sin_addr = dst; | ||||
RIB_RLOCK(rh); | RIB_RLOCK(rh); | ||||
rn = rh->rnh_matchaddr((void *)&sin, &rh->head); | rn = rh->rnh_matchaddr((void *)&sin, &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)) { | ||||
fib4_rte_to_nh_basic(rte, dst, flags, pnh4); | fib4_rte_to_nh_basic(nh, dst, flags, pnh4); | ||||
RIB_RUNLOCK(rh); | RIB_RUNLOCK(rh); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
RIB_RUNLOCK(rh); | RIB_RUNLOCK(rh); | ||||
return (ENOENT); | return (ENOENT); | ||||
Show All 13 Lines | |||||
*/ | */ | ||||
int | int | ||||
fib4_lookup_nh_ext(uint32_t fibnum, struct in_addr dst, uint32_t flags, | fib4_lookup_nh_ext(uint32_t fibnum, struct in_addr dst, uint32_t flags, | ||||
uint32_t flowid, struct nhop4_extended *pnh4) | uint32_t flowid, struct nhop4_extended *pnh4) | ||||
{ | { | ||||
RIB_RLOCK_TRACKER; | RIB_RLOCK_TRACKER; | ||||
struct rib_head *rh; | struct rib_head *rh; | ||||
struct radix_node *rn; | struct radix_node *rn; | ||||
struct nhop_object *nh; | |||||
struct sockaddr_in sin; | struct sockaddr_in sin; | ||||
struct rtentry *rte; | |||||
KASSERT((fibnum < rt_numfibs), ("fib4_lookup_nh_ext: bad fibnum")); | KASSERT((fibnum < rt_numfibs), ("fib4_lookup_nh_ext: bad fibnum")); | ||||
rh = rt_tables_get_rnh(fibnum, AF_INET); | rh = rt_tables_get_rnh(fibnum, AF_INET); | ||||
if (rh == NULL) | if (rh == NULL) | ||||
return (ENOENT); | return (ENOENT); | ||||
/* Prepare lookup key */ | /* Prepare lookup key */ | ||||
memset(&sin, 0, sizeof(sin)); | memset(&sin, 0, sizeof(sin)); | ||||
sin.sin_family = AF_INET; | |||||
sin.sin_len = sizeof(struct sockaddr_in); | sin.sin_len = sizeof(struct sockaddr_in); | ||||
sin.sin_addr = dst; | sin.sin_addr = dst; | ||||
nh = NULL; | |||||
RIB_RLOCK(rh); | RIB_RLOCK(rh); | ||||
rn = rh->rnh_matchaddr((void *)&sin, &rh->head); | rn = rh->rnh_matchaddr((void *)&sin, &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)) { | ||||
fib4_rte_to_nh_extended(rte, dst, flags, pnh4); | fib4_rte_to_nh_extended(nh, dst, flags, pnh4); | ||||
if ((flags & NHR_REF) != 0) { | if ((flags & NHR_REF) != 0) { | ||||
/* TODO: lwref on egress ifp's ? */ | /* TODO: 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 | ||||
fib4_free_nh_ext(uint32_t fibnum, struct nhop4_extended *pnh4) | fib4_free_nh_ext(uint32_t fibnum, struct nhop4_extended *pnh4) | ||||
{ | { | ||||
} | |||||
struct nhop_object * | |||||
fib4_lookup_nh_ptr(uint32_t fibnum, struct in_addr dst, uint32_t scopeid, | |||||
uint32_t flags, uint32_t flowid) | |||||
{ | |||||
RIB_RLOCK_TRACKER; | |||||
struct rib_head *rh; | |||||
struct radix_node *rn; | |||||
struct nhop_object *nh; | |||||
KASSERT((fibnum < rt_numfibs), ("fib4_lookup_nh_route: 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; | |||||
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; | |||||
/* 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 | |||||
fib4_lookup_urpf(uint32_t fibnum, struct in_addr dst, 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; | |||||
int ret; | |||||
KASSERT((fibnum < rt_numfibs), ("fib4_lookup_nh_route: bad fibnum")); | |||||
rh = rt_tables_get_rnh(fibnum, AF_INET); | |||||
if (rh == NULL) | |||||
return (0); | |||||
/* Prepare lookup key */ | |||||
struct sockaddr_in sin4; | |||||
memset(&sin4, 0, sizeof(sin4)); | |||||
sin4.sin_len = sizeof(struct sockaddr_in); | |||||
ae: sin4.sin_family = AF_INET? | |||||
Done Inline ActionsNo, radix doesn't care of anything that is below sockaddr adress offset. I agree that generally this should be filled in properly to ease code understanding, but I really hope to commit the sockaddr change soon. melifaro: No, radix doesn't care of anything that is below sockaddr adress offset.
Additionally, there… | |||||
sin4.sin_addr = dst; | |||||
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; | |||||
ret = check_urpf(nh, flags, src_if); | |||||
RIB_RUNLOCK(rh); | |||||
return (ret); | |||||
} | |||||
RIB_RUNLOCK(rh); | |||||
return (0); | |||||
} | } | ||||
#endif | #endif |
sin4.sin_family = AF_INET?