Skip to content

Commit 4c21b5b

Browse files
haggaiedledford
authored andcommitted
IB/cma: Add net_dev and private data checks to RDMA CM
Instead of relying on a the ib_cm module to check an incoming CM request's private data header, add these checks to the RDMA CM module. This allows a following patch to to clean up the ib_cm interface and remove the code that looks into the private headers. It will also allow supporting namespaces in RDMA CM by making these checks namespace aware later on. Signed-off-by: Haggai Eran <[email protected]> Signed-off-by: Doug Ledford <[email protected]>
1 parent 24cad9a commit 4c21b5b

File tree

1 file changed

+185
-3
lines changed
  • drivers/infiniband/core

1 file changed

+185
-3
lines changed

drivers/infiniband/core/cma.c

Lines changed: 185 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,15 @@ struct cma_hdr {
263263

264264
#define CMA_VERSION 0x00
265265

266+
struct cma_req_info {
267+
struct ib_device *device;
268+
int port;
269+
union ib_gid local_gid;
270+
__be64 service_id;
271+
u16 pkey;
272+
bool has_gid:1;
273+
};
274+
266275
static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp)
267276
{
268277
unsigned long flags;
@@ -300,7 +309,7 @@ static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv,
300309
return old;
301310
}
302311

303-
static inline u8 cma_get_ip_ver(struct cma_hdr *hdr)
312+
static inline u8 cma_get_ip_ver(const struct cma_hdr *hdr)
304313
{
305314
return hdr->ip_version >> 4;
306315
}
@@ -1016,7 +1025,7 @@ static int cma_save_ip_info(struct sockaddr *src_addr,
10161025
cma_save_ip6_info(src_addr, dst_addr, hdr, port);
10171026
break;
10181027
default:
1019-
return -EINVAL;
1028+
return -EAFNOSUPPORT;
10201029
}
10211030

10221031
return 0;
@@ -1040,6 +1049,176 @@ static int cma_save_net_info(struct sockaddr *src_addr,
10401049
return cma_save_ip_info(src_addr, dst_addr, ib_event, service_id);
10411050
}
10421051

1052+
static int cma_save_req_info(const struct ib_cm_event *ib_event,
1053+
struct cma_req_info *req)
1054+
{
1055+
const struct ib_cm_req_event_param *req_param =
1056+
&ib_event->param.req_rcvd;
1057+
const struct ib_cm_sidr_req_event_param *sidr_param =
1058+
&ib_event->param.sidr_req_rcvd;
1059+
1060+
switch (ib_event->event) {
1061+
case IB_CM_REQ_RECEIVED:
1062+
req->device = req_param->listen_id->device;
1063+
req->port = req_param->port;
1064+
memcpy(&req->local_gid, &req_param->primary_path->sgid,
1065+
sizeof(req->local_gid));
1066+
req->has_gid = true;
1067+
req->service_id = req_param->primary_path->service_id;
1068+
req->pkey = req_param->bth_pkey;
1069+
break;
1070+
case IB_CM_SIDR_REQ_RECEIVED:
1071+
req->device = sidr_param->listen_id->device;
1072+
req->port = sidr_param->port;
1073+
req->has_gid = false;
1074+
req->service_id = sidr_param->service_id;
1075+
req->pkey = sidr_param->bth_pkey;
1076+
break;
1077+
default:
1078+
return -EINVAL;
1079+
}
1080+
1081+
return 0;
1082+
}
1083+
1084+
static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event,
1085+
const struct cma_req_info *req)
1086+
{
1087+
struct sockaddr_storage listen_addr_storage;
1088+
struct sockaddr *listen_addr = (struct sockaddr *)&listen_addr_storage;
1089+
struct net_device *net_dev;
1090+
const union ib_gid *gid = req->has_gid ? &req->local_gid : NULL;
1091+
int err;
1092+
1093+
err = cma_save_ip_info(listen_addr, NULL, ib_event, req->service_id);
1094+
if (err)
1095+
return ERR_PTR(err);
1096+
1097+
net_dev = ib_get_net_dev_by_params(req->device, req->port, req->pkey,
1098+
gid, listen_addr);
1099+
if (!net_dev)
1100+
return ERR_PTR(-ENODEV);
1101+
1102+
return net_dev;
1103+
}
1104+
1105+
static enum rdma_port_space rdma_ps_from_service_id(__be64 service_id)
1106+
{
1107+
return (be64_to_cpu(service_id) >> 16) & 0xffff;
1108+
}
1109+
1110+
static bool cma_match_private_data(struct rdma_id_private *id_priv,
1111+
const struct cma_hdr *hdr)
1112+
{
1113+
struct sockaddr *addr = cma_src_addr(id_priv);
1114+
__be32 ip4_addr;
1115+
struct in6_addr ip6_addr;
1116+
1117+
if (cma_any_addr(addr) && !id_priv->afonly)
1118+
return true;
1119+
1120+
switch (addr->sa_family) {
1121+
case AF_INET:
1122+
ip4_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
1123+
if (cma_get_ip_ver(hdr) != 4)
1124+
return false;
1125+
if (!cma_any_addr(addr) &&
1126+
hdr->dst_addr.ip4.addr != ip4_addr)
1127+
return false;
1128+
break;
1129+
case AF_INET6:
1130+
ip6_addr = ((struct sockaddr_in6 *)addr)->sin6_addr;
1131+
if (cma_get_ip_ver(hdr) != 6)
1132+
return false;
1133+
if (!cma_any_addr(addr) &&
1134+
memcmp(&hdr->dst_addr.ip6, &ip6_addr, sizeof(ip6_addr)))
1135+
return false;
1136+
break;
1137+
case AF_IB:
1138+
return true;
1139+
default:
1140+
return false;
1141+
}
1142+
1143+
return true;
1144+
}
1145+
1146+
static bool cma_match_net_dev(const struct rdma_id_private *id_priv,
1147+
const struct net_device *net_dev)
1148+
{
1149+
const struct rdma_addr *addr = &id_priv->id.route.addr;
1150+
1151+
if (!net_dev)
1152+
/* This request is an AF_IB request */
1153+
return addr->src_addr.ss_family == AF_IB;
1154+
1155+
return !addr->dev_addr.bound_dev_if ||
1156+
(net_eq(dev_net(net_dev), &init_net) &&
1157+
addr->dev_addr.bound_dev_if == net_dev->ifindex);
1158+
}
1159+
1160+
static struct rdma_id_private *cma_find_listener(
1161+
const struct rdma_bind_list *bind_list,
1162+
const struct ib_cm_id *cm_id,
1163+
const struct ib_cm_event *ib_event,
1164+
const struct cma_req_info *req,
1165+
const struct net_device *net_dev)
1166+
{
1167+
struct rdma_id_private *id_priv, *id_priv_dev;
1168+
1169+
if (!bind_list)
1170+
return ERR_PTR(-EINVAL);
1171+
1172+
hlist_for_each_entry(id_priv, &bind_list->owners, node) {
1173+
if (cma_match_private_data(id_priv, ib_event->private_data)) {
1174+
if (id_priv->id.device == cm_id->device &&
1175+
cma_match_net_dev(id_priv, net_dev))
1176+
return id_priv;
1177+
list_for_each_entry(id_priv_dev,
1178+
&id_priv->listen_list,
1179+
listen_list) {
1180+
if (id_priv_dev->id.device == cm_id->device &&
1181+
cma_match_net_dev(id_priv_dev, net_dev))
1182+
return id_priv_dev;
1183+
}
1184+
}
1185+
}
1186+
1187+
return ERR_PTR(-EINVAL);
1188+
}
1189+
1190+
static struct rdma_id_private *cma_id_from_event(struct ib_cm_id *cm_id,
1191+
struct ib_cm_event *ib_event)
1192+
{
1193+
struct cma_req_info req;
1194+
struct rdma_bind_list *bind_list;
1195+
struct rdma_id_private *id_priv;
1196+
struct net_device *net_dev;
1197+
int err;
1198+
1199+
err = cma_save_req_info(ib_event, &req);
1200+
if (err)
1201+
return ERR_PTR(err);
1202+
1203+
net_dev = cma_get_net_dev(ib_event, &req);
1204+
if (IS_ERR(net_dev)) {
1205+
if (PTR_ERR(net_dev) == -EAFNOSUPPORT) {
1206+
/* Assuming the protocol is AF_IB */
1207+
net_dev = NULL;
1208+
} else {
1209+
return ERR_CAST(net_dev);
1210+
}
1211+
}
1212+
1213+
bind_list = cma_ps_find(rdma_ps_from_service_id(req.service_id),
1214+
cma_port_from_service_id(req.service_id));
1215+
id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, net_dev);
1216+
1217+
dev_put(net_dev);
1218+
1219+
return id_priv;
1220+
}
1221+
10431222
static inline int cma_user_data_offset(struct rdma_id_private *id_priv)
10441223
{
10451224
return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr);
@@ -1399,7 +1578,10 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
13991578
struct rdma_cm_event event;
14001579
int offset, ret;
14011580

1402-
listen_id = cm_id->context;
1581+
listen_id = cma_id_from_event(cm_id, ib_event);
1582+
if (IS_ERR(listen_id))
1583+
return PTR_ERR(listen_id);
1584+
14031585
if (!cma_check_req_qp_type(&listen_id->id, ib_event))
14041586
return -EINVAL;
14051587

0 commit comments

Comments
 (0)