diff options
Diffstat (limited to 'drivers/infiniband/core/ucma.c')
| -rw-r--r-- | drivers/infiniband/core/ucma.c | 321 | 
1 files changed, 283 insertions, 38 deletions
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 5ca44cd9b00c..b0f189be543b 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -47,6 +47,8 @@  #include <rdma/ib_marshall.h>  #include <rdma/rdma_cm.h>  #include <rdma/rdma_cm_ib.h> +#include <rdma/ib_addr.h> +#include <rdma/ib.h>  MODULE_AUTHOR("Sean Hefty");  MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access"); @@ -510,10 +512,10 @@ static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf,  	return ret;  } -static ssize_t ucma_bind_addr(struct ucma_file *file, const char __user *inbuf, +static ssize_t ucma_bind_ip(struct ucma_file *file, const char __user *inbuf,  			      int in_len, int out_len)  { -	struct rdma_ucm_bind_addr cmd; +	struct rdma_ucm_bind_ip cmd;  	struct ucma_context *ctx;  	int ret; @@ -529,24 +531,75 @@ static ssize_t ucma_bind_addr(struct ucma_file *file, const char __user *inbuf,  	return ret;  } +static ssize_t ucma_bind(struct ucma_file *file, const char __user *inbuf, +			 int in_len, int out_len) +{ +	struct rdma_ucm_bind cmd; +	struct sockaddr *addr; +	struct ucma_context *ctx; +	int ret; + +	if (copy_from_user(&cmd, inbuf, sizeof(cmd))) +		return -EFAULT; + +	addr = (struct sockaddr *) &cmd.addr; +	if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr))) +		return -EINVAL; + +	ctx = ucma_get_ctx(file, cmd.id); +	if (IS_ERR(ctx)) +		return PTR_ERR(ctx); + +	ret = rdma_bind_addr(ctx->cm_id, addr); +	ucma_put_ctx(ctx); +	return ret; +} + +static ssize_t ucma_resolve_ip(struct ucma_file *file, +			       const char __user *inbuf, +			       int in_len, int out_len) +{ +	struct rdma_ucm_resolve_ip cmd; +	struct ucma_context *ctx; +	int ret; + +	if (copy_from_user(&cmd, inbuf, sizeof(cmd))) +		return -EFAULT; + +	ctx = ucma_get_ctx(file, cmd.id); +	if (IS_ERR(ctx)) +		return PTR_ERR(ctx); + +	ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr, +				(struct sockaddr *) &cmd.dst_addr, +				cmd.timeout_ms); +	ucma_put_ctx(ctx); +	return ret; +} +  static ssize_t ucma_resolve_addr(struct ucma_file *file,  				 const char __user *inbuf,  				 int in_len, int out_len)  {  	struct rdma_ucm_resolve_addr cmd; +	struct sockaddr *src, *dst;  	struct ucma_context *ctx;  	int ret;  	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))  		return -EFAULT; +	src = (struct sockaddr *) &cmd.src_addr; +	dst = (struct sockaddr *) &cmd.dst_addr; +	if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) || +	    !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst))) +		return -EINVAL; +  	ctx = ucma_get_ctx(file, cmd.id);  	if (IS_ERR(ctx))  		return PTR_ERR(ctx); -	ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr, -				(struct sockaddr *) &cmd.dst_addr, -				cmd.timeout_ms); +	ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms);  	ucma_put_ctx(ctx);  	return ret;  } @@ -649,7 +702,7 @@ static ssize_t ucma_query_route(struct ucma_file *file,  				const char __user *inbuf,  				int in_len, int out_len)  { -	struct rdma_ucm_query_route cmd; +	struct rdma_ucm_query cmd;  	struct rdma_ucm_query_route_resp resp;  	struct ucma_context *ctx;  	struct sockaddr *addr; @@ -709,7 +762,162 @@ out:  	return ret;  } -static void ucma_copy_conn_param(struct rdma_conn_param *dst, +static void ucma_query_device_addr(struct rdma_cm_id *cm_id, +				   struct rdma_ucm_query_addr_resp *resp) +{ +	if (!cm_id->device) +		return; + +	resp->node_guid = (__force __u64) cm_id->device->node_guid; +	resp->port_num = cm_id->port_num; +	resp->pkey = (__force __u16) cpu_to_be16( +		     ib_addr_get_pkey(&cm_id->route.addr.dev_addr)); +} + +static ssize_t ucma_query_addr(struct ucma_context *ctx, +			       void __user *response, int out_len) +{ +	struct rdma_ucm_query_addr_resp resp; +	struct sockaddr *addr; +	int ret = 0; + +	if (out_len < sizeof(resp)) +		return -ENOSPC; + +	memset(&resp, 0, sizeof resp); + +	addr = (struct sockaddr *) &ctx->cm_id->route.addr.src_addr; +	resp.src_size = rdma_addr_size(addr); +	memcpy(&resp.src_addr, addr, resp.src_size); + +	addr = (struct sockaddr *) &ctx->cm_id->route.addr.dst_addr; +	resp.dst_size = rdma_addr_size(addr); +	memcpy(&resp.dst_addr, addr, resp.dst_size); + +	ucma_query_device_addr(ctx->cm_id, &resp); + +	if (copy_to_user(response, &resp, sizeof(resp))) +		ret = -EFAULT; + +	return ret; +} + +static ssize_t ucma_query_path(struct ucma_context *ctx, +			       void __user *response, int out_len) +{ +	struct rdma_ucm_query_path_resp *resp; +	int i, ret = 0; + +	if (out_len < sizeof(*resp)) +		return -ENOSPC; + +	resp = kzalloc(out_len, GFP_KERNEL); +	if (!resp) +		return -ENOMEM; + +	resp->num_paths = ctx->cm_id->route.num_paths; +	for (i = 0, out_len -= sizeof(*resp); +	     i < resp->num_paths && out_len > sizeof(struct ib_path_rec_data); +	     i++, out_len -= sizeof(struct ib_path_rec_data)) { + +		resp->path_data[i].flags = IB_PATH_GMP | IB_PATH_PRIMARY | +					   IB_PATH_BIDIRECTIONAL; +		ib_sa_pack_path(&ctx->cm_id->route.path_rec[i], +				&resp->path_data[i].path_rec); +	} + +	if (copy_to_user(response, resp, +			 sizeof(*resp) + (i * sizeof(struct ib_path_rec_data)))) +		ret = -EFAULT; + +	kfree(resp); +	return ret; +} + +static ssize_t ucma_query_gid(struct ucma_context *ctx, +			      void __user *response, int out_len) +{ +	struct rdma_ucm_query_addr_resp resp; +	struct sockaddr_ib *addr; +	int ret = 0; + +	if (out_len < sizeof(resp)) +		return -ENOSPC; + +	memset(&resp, 0, sizeof resp); + +	ucma_query_device_addr(ctx->cm_id, &resp); + +	addr = (struct sockaddr_ib *) &resp.src_addr; +	resp.src_size = sizeof(*addr); +	if (ctx->cm_id->route.addr.src_addr.ss_family == AF_IB) { +		memcpy(addr, &ctx->cm_id->route.addr.src_addr, resp.src_size); +	} else { +		addr->sib_family = AF_IB; +		addr->sib_pkey = (__force __be16) resp.pkey; +		rdma_addr_get_sgid(&ctx->cm_id->route.addr.dev_addr, +				   (union ib_gid *) &addr->sib_addr); +		addr->sib_sid = rdma_get_service_id(ctx->cm_id, (struct sockaddr *) +						    &ctx->cm_id->route.addr.src_addr); +	} + +	addr = (struct sockaddr_ib *) &resp.dst_addr; +	resp.dst_size = sizeof(*addr); +	if (ctx->cm_id->route.addr.dst_addr.ss_family == AF_IB) { +		memcpy(addr, &ctx->cm_id->route.addr.dst_addr, resp.dst_size); +	} else { +		addr->sib_family = AF_IB; +		addr->sib_pkey = (__force __be16) resp.pkey; +		rdma_addr_get_dgid(&ctx->cm_id->route.addr.dev_addr, +				   (union ib_gid *) &addr->sib_addr); +		addr->sib_sid = rdma_get_service_id(ctx->cm_id, (struct sockaddr *) +						    &ctx->cm_id->route.addr.dst_addr); +	} + +	if (copy_to_user(response, &resp, sizeof(resp))) +		ret = -EFAULT; + +	return ret; +} + +static ssize_t ucma_query(struct ucma_file *file, +			  const char __user *inbuf, +			  int in_len, int out_len) +{ +	struct rdma_ucm_query cmd; +	struct ucma_context *ctx; +	void __user *response; +	int ret; + +	if (copy_from_user(&cmd, inbuf, sizeof(cmd))) +		return -EFAULT; + +	response = (void __user *)(unsigned long) cmd.response; +	ctx = ucma_get_ctx(file, cmd.id); +	if (IS_ERR(ctx)) +		return PTR_ERR(ctx); + +	switch (cmd.option) { +	case RDMA_USER_CM_QUERY_ADDR: +		ret = ucma_query_addr(ctx, response, out_len); +		break; +	case RDMA_USER_CM_QUERY_PATH: +		ret = ucma_query_path(ctx, response, out_len); +		break; +	case RDMA_USER_CM_QUERY_GID: +		ret = ucma_query_gid(ctx, response, out_len); +		break; +	default: +		ret = -ENOSYS; +		break; +	} + +	ucma_put_ctx(ctx); +	return ret; +} + +static void ucma_copy_conn_param(struct rdma_cm_id *id, +				 struct rdma_conn_param *dst,  				 struct rdma_ucm_conn_param *src)  {  	dst->private_data = src->private_data; @@ -721,6 +929,7 @@ static void ucma_copy_conn_param(struct rdma_conn_param *dst,  	dst->rnr_retry_count = src->rnr_retry_count;  	dst->srq = src->srq;  	dst->qp_num = src->qp_num; +	dst->qkey = (id->route.addr.src_addr.ss_family == AF_IB) ? src->qkey : 0;  }  static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf, @@ -741,7 +950,7 @@ static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf,  	if (IS_ERR(ctx))  		return PTR_ERR(ctx); -	ucma_copy_conn_param(&conn_param, &cmd.conn_param); +	ucma_copy_conn_param(ctx->cm_id, &conn_param, &cmd.conn_param);  	ret = rdma_connect(ctx->cm_id, &conn_param);  	ucma_put_ctx(ctx);  	return ret; @@ -784,7 +993,7 @@ static ssize_t ucma_accept(struct ucma_file *file, const char __user *inbuf,  		return PTR_ERR(ctx);  	if (cmd.conn_param.valid) { -		ucma_copy_conn_param(&conn_param, &cmd.conn_param); +		ucma_copy_conn_param(ctx->cm_id, &conn_param, &cmd.conn_param);  		mutex_lock(&file->mut);  		ret = rdma_accept(ctx->cm_id, &conn_param);  		if (!ret) @@ -1020,23 +1229,23 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,  	return ret;  } -static ssize_t ucma_join_multicast(struct ucma_file *file, -				   const char __user *inbuf, -				   int in_len, int out_len) +static ssize_t ucma_process_join(struct ucma_file *file, +				 struct rdma_ucm_join_mcast *cmd,  int out_len)  { -	struct rdma_ucm_join_mcast cmd;  	struct rdma_ucm_create_id_resp resp;  	struct ucma_context *ctx;  	struct ucma_multicast *mc; +	struct sockaddr *addr;  	int ret;  	if (out_len < sizeof(resp))  		return -ENOSPC; -	if (copy_from_user(&cmd, inbuf, sizeof(cmd))) -		return -EFAULT; +	addr = (struct sockaddr *) &cmd->addr; +	if (cmd->reserved || !cmd->addr_size || (cmd->addr_size != rdma_addr_size(addr))) +		return -EINVAL; -	ctx = ucma_get_ctx(file, cmd.id); +	ctx = ucma_get_ctx(file, cmd->id);  	if (IS_ERR(ctx))  		return PTR_ERR(ctx); @@ -1047,14 +1256,14 @@ static ssize_t ucma_join_multicast(struct ucma_file *file,  		goto err1;  	} -	mc->uid = cmd.uid; -	memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr); +	mc->uid = cmd->uid; +	memcpy(&mc->addr, addr, cmd->addr_size);  	ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr, mc);  	if (ret)  		goto err2;  	resp.id = mc->id; -	if (copy_to_user((void __user *)(unsigned long)cmd.response, +	if (copy_to_user((void __user *)(unsigned long) cmd->response,  			 &resp, sizeof(resp))) {  		ret = -EFAULT;  		goto err3; @@ -1079,6 +1288,38 @@ err1:  	return ret;  } +static ssize_t ucma_join_ip_multicast(struct ucma_file *file, +				      const char __user *inbuf, +				      int in_len, int out_len) +{ +	struct rdma_ucm_join_ip_mcast cmd; +	struct rdma_ucm_join_mcast join_cmd; + +	if (copy_from_user(&cmd, inbuf, sizeof(cmd))) +		return -EFAULT; + +	join_cmd.response = cmd.response; +	join_cmd.uid = cmd.uid; +	join_cmd.id = cmd.id; +	join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr); +	join_cmd.reserved = 0; +	memcpy(&join_cmd.addr, &cmd.addr, join_cmd.addr_size); + +	return ucma_process_join(file, &join_cmd, out_len); +} + +static ssize_t ucma_join_multicast(struct ucma_file *file, +				   const char __user *inbuf, +				   int in_len, int out_len) +{ +	struct rdma_ucm_join_mcast cmd; + +	if (copy_from_user(&cmd, inbuf, sizeof(cmd))) +		return -EFAULT; + +	return ucma_process_join(file, &cmd, out_len); +} +  static ssize_t ucma_leave_multicast(struct ucma_file *file,  				    const char __user *inbuf,  				    int in_len, int out_len) @@ -1221,25 +1462,29 @@ file_put:  static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,  				   const char __user *inbuf,  				   int in_len, int out_len) = { -	[RDMA_USER_CM_CMD_CREATE_ID]	= ucma_create_id, -	[RDMA_USER_CM_CMD_DESTROY_ID]	= ucma_destroy_id, -	[RDMA_USER_CM_CMD_BIND_ADDR]	= ucma_bind_addr, -	[RDMA_USER_CM_CMD_RESOLVE_ADDR]	= ucma_resolve_addr, -	[RDMA_USER_CM_CMD_RESOLVE_ROUTE]= ucma_resolve_route, -	[RDMA_USER_CM_CMD_QUERY_ROUTE]	= ucma_query_route, -	[RDMA_USER_CM_CMD_CONNECT]	= ucma_connect, -	[RDMA_USER_CM_CMD_LISTEN]	= ucma_listen, -	[RDMA_USER_CM_CMD_ACCEPT]	= ucma_accept, -	[RDMA_USER_CM_CMD_REJECT]	= ucma_reject, -	[RDMA_USER_CM_CMD_DISCONNECT]	= ucma_disconnect, -	[RDMA_USER_CM_CMD_INIT_QP_ATTR]	= ucma_init_qp_attr, -	[RDMA_USER_CM_CMD_GET_EVENT]	= ucma_get_event, -	[RDMA_USER_CM_CMD_GET_OPTION]	= NULL, -	[RDMA_USER_CM_CMD_SET_OPTION]	= ucma_set_option, -	[RDMA_USER_CM_CMD_NOTIFY]	= ucma_notify, -	[RDMA_USER_CM_CMD_JOIN_MCAST]	= ucma_join_multicast, -	[RDMA_USER_CM_CMD_LEAVE_MCAST]	= ucma_leave_multicast, -	[RDMA_USER_CM_CMD_MIGRATE_ID]	= ucma_migrate_id +	[RDMA_USER_CM_CMD_CREATE_ID] 	 = ucma_create_id, +	[RDMA_USER_CM_CMD_DESTROY_ID]	 = ucma_destroy_id, +	[RDMA_USER_CM_CMD_BIND_IP]	 = ucma_bind_ip, +	[RDMA_USER_CM_CMD_RESOLVE_IP]	 = ucma_resolve_ip, +	[RDMA_USER_CM_CMD_RESOLVE_ROUTE] = ucma_resolve_route, +	[RDMA_USER_CM_CMD_QUERY_ROUTE]	 = ucma_query_route, +	[RDMA_USER_CM_CMD_CONNECT]	 = ucma_connect, +	[RDMA_USER_CM_CMD_LISTEN]	 = ucma_listen, +	[RDMA_USER_CM_CMD_ACCEPT]	 = ucma_accept, +	[RDMA_USER_CM_CMD_REJECT]	 = ucma_reject, +	[RDMA_USER_CM_CMD_DISCONNECT]	 = ucma_disconnect, +	[RDMA_USER_CM_CMD_INIT_QP_ATTR]	 = ucma_init_qp_attr, +	[RDMA_USER_CM_CMD_GET_EVENT]	 = ucma_get_event, +	[RDMA_USER_CM_CMD_GET_OPTION]	 = NULL, +	[RDMA_USER_CM_CMD_SET_OPTION]	 = ucma_set_option, +	[RDMA_USER_CM_CMD_NOTIFY]	 = ucma_notify, +	[RDMA_USER_CM_CMD_JOIN_IP_MCAST] = ucma_join_ip_multicast, +	[RDMA_USER_CM_CMD_LEAVE_MCAST]	 = ucma_leave_multicast, +	[RDMA_USER_CM_CMD_MIGRATE_ID]	 = ucma_migrate_id, +	[RDMA_USER_CM_CMD_QUERY]	 = ucma_query, +	[RDMA_USER_CM_CMD_BIND]		 = ucma_bind, +	[RDMA_USER_CM_CMD_RESOLVE_ADDR]	 = ucma_resolve_addr, +	[RDMA_USER_CM_CMD_JOIN_MCAST]	 = ucma_join_multicast  };  static ssize_t ucma_write(struct file *filp, const char __user *buf,  | 
