Changeset View
Changeset View
Standalone View
Standalone View
sys/ofed/drivers/infiniband/core/ib_cma.c
Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
#include <linux/in6.h> | #include <linux/in6.h> | ||||
#include <linux/mutex.h> | #include <linux/mutex.h> | ||||
#include <linux/random.h> | #include <linux/random.h> | ||||
#include <linux/idr.h> | #include <linux/idr.h> | ||||
#include <linux/inetdevice.h> | #include <linux/inetdevice.h> | ||||
#include <linux/slab.h> | #include <linux/slab.h> | ||||
#include <linux/module.h> | #include <linux/module.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
#include <net/route/nhop.h> | |||||
#include <net/tcp.h> | #include <net/tcp.h> | ||||
#include <net/ipv6.h> | #include <net/ipv6.h> | ||||
#include <netinet/in_fib.h> | |||||
#include <netinet6/in6_fib.h> | |||||
#include <netinet6/scope6_var.h> | #include <netinet6/scope6_var.h> | ||||
#include <netinet6/ip6_var.h> | #include <netinet6/ip6_var.h> | ||||
#include <rdma/rdma_cm.h> | #include <rdma/rdma_cm.h> | ||||
#include <rdma/rdma_cm_ib.h> | #include <rdma/rdma_cm_ib.h> | ||||
#include <rdma/rdma_sdp.h> | #include <rdma/rdma_sdp.h> | ||||
#include <rdma/ib.h> | #include <rdma/ib.h> | ||||
#include <rdma/ib_addr.h> | #include <rdma/ib_addr.h> | ||||
▲ Show 20 Lines • Show All 1,281 Lines • ▼ Show 20 Lines | static int cma_save_req_info(const struct ib_cm_event *ib_event, | ||||
return 0; | return 0; | ||||
} | } | ||||
static bool validate_ipv4_net_dev(struct net_device *net_dev, | static bool validate_ipv4_net_dev(struct net_device *net_dev, | ||||
const struct sockaddr_in *dst_addr, | const struct sockaddr_in *dst_addr, | ||||
const struct sockaddr_in *src_addr) | const struct sockaddr_in *src_addr) | ||||
{ | { | ||||
#ifdef INET | #ifdef INET | ||||
struct sockaddr_in src_tmp = *src_addr; | |||||
__be32 daddr = dst_addr->sin_addr.s_addr, | __be32 daddr = dst_addr->sin_addr.s_addr, | ||||
saddr = src_addr->sin_addr.s_addr; | saddr = src_addr->sin_addr.s_addr; | ||||
struct net_device *dst_dev; | struct net_device *dst_dev; | ||||
struct rtentry *rte; | struct nhop_object *nh; | ||||
bool ret; | bool ret; | ||||
if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) || | if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) || | ||||
ipv4_is_lbcast(daddr) || ipv4_is_zeronet(saddr) || | ipv4_is_lbcast(daddr) || ipv4_is_zeronet(saddr) || | ||||
ipv4_is_zeronet(daddr) || ipv4_is_loopback(daddr) || | ipv4_is_zeronet(daddr) || ipv4_is_loopback(daddr) || | ||||
ipv4_is_loopback(saddr)) | ipv4_is_loopback(saddr)) | ||||
return false; | return false; | ||||
dst_dev = ip_dev_find(net_dev->if_vnet, daddr); | dst_dev = ip_dev_find(net_dev->if_vnet, daddr); | ||||
if (dst_dev != net_dev) { | if (dst_dev != net_dev) { | ||||
if (dst_dev != NULL) | if (dst_dev != NULL) | ||||
dev_put(dst_dev); | dev_put(dst_dev); | ||||
return false; | return false; | ||||
} | } | ||||
dev_put(dst_dev); | dev_put(dst_dev); | ||||
/* | /* | ||||
* Check for loopback. | * Check for loopback. | ||||
*/ | */ | ||||
if (saddr == daddr) | if (saddr == daddr) | ||||
return true; | return true; | ||||
/* | |||||
* Make sure the socket address length field | |||||
* is set, else rtalloc1() will fail. | |||||
*/ | |||||
src_tmp.sin_len = sizeof(src_tmp); | |||||
CURVNET_SET(net_dev->if_vnet); | CURVNET_SET(net_dev->if_vnet); | ||||
rte = rtalloc1((struct sockaddr *)&src_tmp, 1, 0); | nh = fib4_lookup(RT_DEFAULT_FIB, src_addr->sin_addr, 0, NHR_NONE, 0); | ||||
if (rte != NULL) { | if (nh != NULL) | ||||
ret = (rte->rt_ifp == net_dev); | ret = (nh->nh_ifp == net_dev); | ||||
RTFREE_LOCKED(rte); | else | ||||
} else { | |||||
ret = false; | ret = false; | ||||
} | |||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return ret; | return ret; | ||||
#else | #else | ||||
return false; | return false; | ||||
#endif | #endif | ||||
} | } | ||||
static bool validate_ipv6_net_dev(struct net_device *net_dev, | static bool validate_ipv6_net_dev(struct net_device *net_dev, | ||||
const struct sockaddr_in6 *dst_addr, | const struct sockaddr_in6 *dst_addr, | ||||
const struct sockaddr_in6 *src_addr) | const struct sockaddr_in6 *src_addr) | ||||
{ | { | ||||
#ifdef INET6 | #ifdef INET6 | ||||
struct sockaddr_in6 src_tmp = *src_addr; | struct sockaddr_in6 src_tmp = *src_addr; | ||||
struct sockaddr_in6 dst_tmp = *dst_addr; | struct sockaddr_in6 dst_tmp = *dst_addr; | ||||
struct net_device *dst_dev; | struct net_device *dst_dev; | ||||
struct rtentry *rte; | struct nhop_object *nh; | ||||
bool ret; | bool ret; | ||||
dst_dev = ip6_dev_find(net_dev->if_vnet, dst_tmp.sin6_addr, | dst_dev = ip6_dev_find(net_dev->if_vnet, dst_tmp.sin6_addr, | ||||
net_dev->if_index); | net_dev->if_index); | ||||
if (dst_dev != net_dev) { | if (dst_dev != net_dev) { | ||||
if (dst_dev != NULL) | if (dst_dev != NULL) | ||||
dev_put(dst_dev); | dev_put(dst_dev); | ||||
return false; | return false; | ||||
} | } | ||||
dev_put(dst_dev); | dev_put(dst_dev); | ||||
CURVNET_SET(net_dev->if_vnet); | CURVNET_SET(net_dev->if_vnet); | ||||
/* | /* | ||||
* Make sure the socket address length field | * Make sure the scope ID gets embedded. | ||||
* is set, else rtalloc1() will fail. | |||||
*/ | */ | ||||
src_tmp.sin6_len = sizeof(src_tmp); | |||||
/* | |||||
* Make sure the scope ID gets embedded, else rtalloc1() will | |||||
* resolve to the loopback interface. | |||||
*/ | |||||
src_tmp.sin6_scope_id = net_dev->if_index; | src_tmp.sin6_scope_id = net_dev->if_index; | ||||
sa6_embedscope(&src_tmp, 0); | sa6_embedscope(&src_tmp, 0); | ||||
dst_tmp.sin6_scope_id = net_dev->if_index; | dst_tmp.sin6_scope_id = net_dev->if_index; | ||||
sa6_embedscope(&dst_tmp, 0); | sa6_embedscope(&dst_tmp, 0); | ||||
/* | /* | ||||
* Check for loopback after scope ID | * Check for loopback after scope ID | ||||
* has been embedded: | * has been embedded: | ||||
*/ | */ | ||||
if (memcmp(&src_tmp.sin6_addr, &dst_tmp.sin6_addr, | if (memcmp(&src_tmp.sin6_addr, &dst_tmp.sin6_addr, | ||||
sizeof(dst_tmp.sin6_addr)) == 0) { | sizeof(dst_tmp.sin6_addr)) == 0) { | ||||
ret = true; | ret = true; | ||||
} else { | } else { | ||||
/* non-loopback case */ | /* non-loopback case */ | ||||
rte = rtalloc1((struct sockaddr *)&src_tmp, 1, 0); | nh = fib6_lookup(RT_DEFAULT_FIB, &src_addr->sin6_addr, | ||||
if (rte != NULL) { | net_dev->if_index, NHR_NONE, 0); | ||||
ret = (rte->rt_ifp == net_dev); | if (nh != NULL) | ||||
RTFREE_LOCKED(rte); | ret = (nh->nh_ifp == net_dev); | ||||
} else { | else | ||||
ret = false; | ret = false; | ||||
} | } | ||||
} | |||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return ret; | return ret; | ||||
#else | #else | ||||
return false; | return false; | ||||
#endif | #endif | ||||
} | } | ||||
static bool validate_net_dev(struct net_device *net_dev, | static bool validate_net_dev(struct net_device *net_dev, | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event, | static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event, | ||||
const struct cma_req_info *req) | const struct cma_req_info *req) | ||||
{ | { | ||||
struct sockaddr_storage listen_addr_storage, src_addr_storage; | struct sockaddr_storage listen_addr_storage, src_addr_storage; | ||||
struct sockaddr *listen_addr = (struct sockaddr *)&listen_addr_storage, | struct sockaddr *listen_addr = (struct sockaddr *)&listen_addr_storage, | ||||
*src_addr = (struct sockaddr *)&src_addr_storage; | *src_addr = (struct sockaddr *)&src_addr_storage; | ||||
struct net_device *net_dev; | struct net_device *net_dev; | ||||
const union ib_gid *gid = req->has_gid ? &req->local_gid : NULL; | const union ib_gid *gid = req->has_gid ? &req->local_gid : NULL; | ||||
struct epoch_tracker et; | |||||
int err; | int err; | ||||
err = cma_save_ip_info(listen_addr, src_addr, ib_event, | err = cma_save_ip_info(listen_addr, src_addr, ib_event, | ||||
req->service_id); | req->service_id); | ||||
if (err) | if (err) | ||||
return ERR_PTR(err); | return ERR_PTR(err); | ||||
if (rdma_protocol_roce(req->device, req->port)) { | if (rdma_protocol_roce(req->device, req->port)) { | ||||
net_dev = roce_get_net_dev_by_cm_event(req->device, req->port, | net_dev = roce_get_net_dev_by_cm_event(req->device, req->port, | ||||
ib_event); | ib_event); | ||||
} else { | } else { | ||||
net_dev = ib_get_net_dev_by_params(req->device, req->port, | net_dev = ib_get_net_dev_by_params(req->device, req->port, | ||||
req->pkey, | req->pkey, | ||||
gid, listen_addr); | gid, listen_addr); | ||||
} | } | ||||
if (!net_dev) | if (!net_dev) | ||||
return ERR_PTR(-ENODEV); | return ERR_PTR(-ENODEV); | ||||
NET_EPOCH_ENTER(et); | |||||
if (!validate_net_dev(net_dev, listen_addr, src_addr)) { | if (!validate_net_dev(net_dev, listen_addr, src_addr)) { | ||||
NET_EPOCH_EXIT(et); | |||||
dev_put(net_dev); | dev_put(net_dev); | ||||
return ERR_PTR(-EHOSTUNREACH); | return ERR_PTR(-EHOSTUNREACH); | ||||
} | } | ||||
NET_EPOCH_EXIT(et); | |||||
return net_dev; | return net_dev; | ||||
} | } | ||||
static enum rdma_port_space rdma_ps_from_service_id(__be64 service_id) | static enum rdma_port_space rdma_ps_from_service_id(__be64 service_id) | ||||
{ | { | ||||
return (be64_to_cpu(service_id) >> 16) & 0xffff; | return (be64_to_cpu(service_id) >> 16) & 0xffff; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 3,088 Lines • Show Last 20 Lines |