提交 6e61d04f 编写于 作者: S Sean Hefty 提交者: Roland Dreier

IB/cm: Match connection requests based on private data

Extend matching connection requests to listens in the InfiniBand CM to
include private data checks.

This allows applications to listen on the same service identifier,
with private data directing the request to the appropriate application.
Signed-off-by: NSean Hefty <sean.hefty@intel.com>
Signed-off-by: NRoland Dreier <rolandd@cisco.com>
上级 6a9af2e1
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
* *
* $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $ * $Id: cm.c 4311 2005-12-05 18:42:01Z sean.hefty $
*/ */
#include <linux/completion.h> #include <linux/completion.h>
...@@ -132,6 +132,7 @@ struct cm_id_private { ...@@ -132,6 +132,7 @@ struct cm_id_private {
/* todo: use alternate port on send failure */ /* todo: use alternate port on send failure */
struct cm_av av; struct cm_av av;
struct cm_av alt_av; struct cm_av alt_av;
struct ib_cm_compare_data *compare_data;
void *private_data; void *private_data;
__be64 tid; __be64 tid;
...@@ -357,6 +358,41 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id) ...@@ -357,6 +358,41 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id)
return cm_id_priv; return cm_id_priv;
} }
static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask)
{
int i;
for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++)
((unsigned long *) dst)[i] = ((unsigned long *) src)[i] &
((unsigned long *) mask)[i];
}
static int cm_compare_data(struct ib_cm_compare_data *src_data,
struct ib_cm_compare_data *dst_data)
{
u8 src[IB_CM_COMPARE_SIZE];
u8 dst[IB_CM_COMPARE_SIZE];
if (!src_data || !dst_data)
return 0;
cm_mask_copy(src, src_data->data, dst_data->mask);
cm_mask_copy(dst, dst_data->data, src_data->mask);
return memcmp(src, dst, IB_CM_COMPARE_SIZE);
}
static int cm_compare_private_data(u8 *private_data,
struct ib_cm_compare_data *dst_data)
{
u8 src[IB_CM_COMPARE_SIZE];
if (!dst_data)
return 0;
cm_mask_copy(src, private_data, dst_data->mask);
return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE);
}
static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
{ {
struct rb_node **link = &cm.listen_service_table.rb_node; struct rb_node **link = &cm.listen_service_table.rb_node;
...@@ -364,14 +400,18 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) ...@@ -364,14 +400,18 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
struct cm_id_private *cur_cm_id_priv; struct cm_id_private *cur_cm_id_priv;
__be64 service_id = cm_id_priv->id.service_id; __be64 service_id = cm_id_priv->id.service_id;
__be64 service_mask = cm_id_priv->id.service_mask; __be64 service_mask = cm_id_priv->id.service_mask;
int data_cmp;
while (*link) { while (*link) {
parent = *link; parent = *link;
cur_cm_id_priv = rb_entry(parent, struct cm_id_private, cur_cm_id_priv = rb_entry(parent, struct cm_id_private,
service_node); service_node);
data_cmp = cm_compare_data(cm_id_priv->compare_data,
cur_cm_id_priv->compare_data);
if ((cur_cm_id_priv->id.service_mask & service_id) == if ((cur_cm_id_priv->id.service_mask & service_id) ==
(service_mask & cur_cm_id_priv->id.service_id) && (service_mask & cur_cm_id_priv->id.service_id) &&
(cm_id_priv->id.device == cur_cm_id_priv->id.device)) (cm_id_priv->id.device == cur_cm_id_priv->id.device) &&
!data_cmp)
return cur_cm_id_priv; return cur_cm_id_priv;
if (cm_id_priv->id.device < cur_cm_id_priv->id.device) if (cm_id_priv->id.device < cur_cm_id_priv->id.device)
...@@ -380,6 +420,10 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) ...@@ -380,6 +420,10 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
link = &(*link)->rb_right; link = &(*link)->rb_right;
else if (service_id < cur_cm_id_priv->id.service_id) else if (service_id < cur_cm_id_priv->id.service_id)
link = &(*link)->rb_left; link = &(*link)->rb_left;
else if (service_id > cur_cm_id_priv->id.service_id)
link = &(*link)->rb_right;
else if (data_cmp < 0)
link = &(*link)->rb_left;
else else
link = &(*link)->rb_right; link = &(*link)->rb_right;
} }
...@@ -389,16 +433,20 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) ...@@ -389,16 +433,20 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
} }
static struct cm_id_private * cm_find_listen(struct ib_device *device, static struct cm_id_private * cm_find_listen(struct ib_device *device,
__be64 service_id) __be64 service_id,
u8 *private_data)
{ {
struct rb_node *node = cm.listen_service_table.rb_node; struct rb_node *node = cm.listen_service_table.rb_node;
struct cm_id_private *cm_id_priv; struct cm_id_private *cm_id_priv;
int data_cmp;
while (node) { while (node) {
cm_id_priv = rb_entry(node, struct cm_id_private, service_node); cm_id_priv = rb_entry(node, struct cm_id_private, service_node);
data_cmp = cm_compare_private_data(private_data,
cm_id_priv->compare_data);
if ((cm_id_priv->id.service_mask & service_id) == if ((cm_id_priv->id.service_mask & service_id) ==
cm_id_priv->id.service_id && cm_id_priv->id.service_id &&
(cm_id_priv->id.device == device)) (cm_id_priv->id.device == device) && !data_cmp)
return cm_id_priv; return cm_id_priv;
if (device < cm_id_priv->id.device) if (device < cm_id_priv->id.device)
...@@ -407,6 +455,10 @@ static struct cm_id_private * cm_find_listen(struct ib_device *device, ...@@ -407,6 +455,10 @@ static struct cm_id_private * cm_find_listen(struct ib_device *device,
node = node->rb_right; node = node->rb_right;
else if (service_id < cm_id_priv->id.service_id) else if (service_id < cm_id_priv->id.service_id)
node = node->rb_left; node = node->rb_left;
else if (service_id > cm_id_priv->id.service_id)
node = node->rb_right;
else if (data_cmp < 0)
node = node->rb_left;
else else
node = node->rb_right; node = node->rb_right;
} }
...@@ -730,15 +782,14 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id) ...@@ -730,15 +782,14 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id)
wait_for_completion(&cm_id_priv->comp); wait_for_completion(&cm_id_priv->comp);
while ((work = cm_dequeue_work(cm_id_priv)) != NULL) while ((work = cm_dequeue_work(cm_id_priv)) != NULL)
cm_free_work(work); cm_free_work(work);
if (cm_id_priv->private_data && cm_id_priv->private_data_len) kfree(cm_id_priv->compare_data);
kfree(cm_id_priv->private_data); kfree(cm_id_priv->private_data);
kfree(cm_id_priv); kfree(cm_id_priv);
} }
EXPORT_SYMBOL(ib_destroy_cm_id); EXPORT_SYMBOL(ib_destroy_cm_id);
int ib_cm_listen(struct ib_cm_id *cm_id, int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
__be64 service_id, struct ib_cm_compare_data *compare_data)
__be64 service_mask)
{ {
struct cm_id_private *cm_id_priv, *cur_cm_id_priv; struct cm_id_private *cm_id_priv, *cur_cm_id_priv;
unsigned long flags; unsigned long flags;
...@@ -752,7 +803,19 @@ int ib_cm_listen(struct ib_cm_id *cm_id, ...@@ -752,7 +803,19 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
return -EINVAL; return -EINVAL;
cm_id_priv = container_of(cm_id, struct cm_id_private, id); cm_id_priv = container_of(cm_id, struct cm_id_private, id);
BUG_ON(cm_id->state != IB_CM_IDLE); if (cm_id->state != IB_CM_IDLE)
return -EINVAL;
if (compare_data) {
cm_id_priv->compare_data = kzalloc(sizeof *compare_data,
GFP_KERNEL);
if (!cm_id_priv->compare_data)
return -ENOMEM;
cm_mask_copy(cm_id_priv->compare_data->data,
compare_data->data, compare_data->mask);
memcpy(cm_id_priv->compare_data->mask, compare_data->mask,
IB_CM_COMPARE_SIZE);
}
cm_id->state = IB_CM_LISTEN; cm_id->state = IB_CM_LISTEN;
...@@ -769,6 +832,8 @@ int ib_cm_listen(struct ib_cm_id *cm_id, ...@@ -769,6 +832,8 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
if (cur_cm_id_priv) { if (cur_cm_id_priv) {
cm_id->state = IB_CM_IDLE; cm_id->state = IB_CM_IDLE;
kfree(cm_id_priv->compare_data);
cm_id_priv->compare_data = NULL;
ret = -EBUSY; ret = -EBUSY;
} }
return ret; return ret;
...@@ -1241,7 +1306,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work, ...@@ -1241,7 +1306,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
/* Find matching listen request. */ /* Find matching listen request. */
listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device,
req_msg->service_id); req_msg->service_id,
req_msg->private_data);
if (!listen_cm_id_priv) { if (!listen_cm_id_priv) {
spin_unlock_irqrestore(&cm.lock, flags); spin_unlock_irqrestore(&cm.lock, flags);
cm_issue_rej(work->port, work->mad_recv_wc, cm_issue_rej(work->port, work->mad_recv_wc,
...@@ -2654,7 +2720,8 @@ static int cm_sidr_req_handler(struct cm_work *work) ...@@ -2654,7 +2720,8 @@ static int cm_sidr_req_handler(struct cm_work *work)
goto out; /* Duplicate message. */ goto out; /* Duplicate message. */
} }
cur_cm_id_priv = cm_find_listen(cm_id->device, cur_cm_id_priv = cm_find_listen(cm_id->device,
sidr_req_msg->service_id); sidr_req_msg->service_id,
sidr_req_msg->private_data);
if (!cur_cm_id_priv) { if (!cur_cm_id_priv) {
rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);
spin_unlock_irqrestore(&cm.lock, flags); spin_unlock_irqrestore(&cm.lock, flags);
......
...@@ -648,6 +648,17 @@ static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file, ...@@ -648,6 +648,17 @@ static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file,
return result; return result;
} }
static int ucm_validate_listen(__be64 service_id, __be64 service_mask)
{
service_id &= service_mask;
if (((service_id & IB_CMA_SERVICE_ID_MASK) == IB_CMA_SERVICE_ID) ||
((service_id & IB_SDP_SERVICE_ID_MASK) == IB_SDP_SERVICE_ID))
return -EINVAL;
return 0;
}
static ssize_t ib_ucm_listen(struct ib_ucm_file *file, static ssize_t ib_ucm_listen(struct ib_ucm_file *file,
const char __user *inbuf, const char __user *inbuf,
int in_len, int out_len) int in_len, int out_len)
...@@ -663,7 +674,13 @@ static ssize_t ib_ucm_listen(struct ib_ucm_file *file, ...@@ -663,7 +674,13 @@ static ssize_t ib_ucm_listen(struct ib_ucm_file *file,
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return PTR_ERR(ctx); return PTR_ERR(ctx);
result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask); result = ucm_validate_listen(cmd.service_id, cmd.service_mask);
if (result)
goto out;
result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask,
NULL);
out:
ib_ucm_ctx_put(ctx); ib_ucm_ctx_put(ctx);
return result; return result;
} }
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
* *
* $Id: ib_cm.h 2730 2005-06-28 16:43:03Z sean.hefty $ * $Id: ib_cm.h 4311 2005-12-05 18:42:01Z sean.hefty $
*/ */
#if !defined(IB_CM_H) #if !defined(IB_CM_H)
#define IB_CM_H #define IB_CM_H
...@@ -102,7 +102,8 @@ enum ib_cm_data_size { ...@@ -102,7 +102,8 @@ enum ib_cm_data_size {
IB_CM_APR_INFO_LENGTH = 72, IB_CM_APR_INFO_LENGTH = 72,
IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE = 216, IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE = 216,
IB_CM_SIDR_REP_PRIVATE_DATA_SIZE = 136, IB_CM_SIDR_REP_PRIVATE_DATA_SIZE = 136,
IB_CM_SIDR_REP_INFO_LENGTH = 72 IB_CM_SIDR_REP_INFO_LENGTH = 72,
IB_CM_COMPARE_SIZE = 64
}; };
struct ib_cm_id; struct ib_cm_id;
...@@ -238,7 +239,6 @@ struct ib_cm_sidr_rep_event_param { ...@@ -238,7 +239,6 @@ struct ib_cm_sidr_rep_event_param {
u32 qpn; u32 qpn;
void *info; void *info;
u8 info_len; u8 info_len;
}; };
struct ib_cm_event { struct ib_cm_event {
...@@ -317,6 +317,15 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id); ...@@ -317,6 +317,15 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id);
#define IB_SERVICE_ID_AGN_MASK __constant_cpu_to_be64(0xFF00000000000000ULL) #define IB_SERVICE_ID_AGN_MASK __constant_cpu_to_be64(0xFF00000000000000ULL)
#define IB_CM_ASSIGN_SERVICE_ID __constant_cpu_to_be64(0x0200000000000000ULL) #define IB_CM_ASSIGN_SERVICE_ID __constant_cpu_to_be64(0x0200000000000000ULL)
#define IB_CMA_SERVICE_ID __constant_cpu_to_be64(0x0000000001000000ULL)
#define IB_CMA_SERVICE_ID_MASK __constant_cpu_to_be64(0xFFFFFFFFFF000000ULL)
#define IB_SDP_SERVICE_ID __constant_cpu_to_be64(0x0000000000010000ULL)
#define IB_SDP_SERVICE_ID_MASK __constant_cpu_to_be64(0xFFFFFFFFFFFF0000ULL)
struct ib_cm_compare_data {
u8 data[IB_CM_COMPARE_SIZE];
u8 mask[IB_CM_COMPARE_SIZE];
};
/** /**
* ib_cm_listen - Initiates listening on the specified service ID for * ib_cm_listen - Initiates listening on the specified service ID for
...@@ -330,10 +339,12 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id); ...@@ -330,10 +339,12 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id);
* range of service IDs. If set to 0, the service ID is matched * range of service IDs. If set to 0, the service ID is matched
* exactly. This parameter is ignored if %service_id is set to * exactly. This parameter is ignored if %service_id is set to
* IB_CM_ASSIGN_SERVICE_ID. * IB_CM_ASSIGN_SERVICE_ID.
* @compare_data: This parameter is optional. It specifies data that must
* appear in the private data of a connection request for the specified
* listen request.
*/ */
int ib_cm_listen(struct ib_cm_id *cm_id, int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
__be64 service_id, struct ib_cm_compare_data *compare_data);
__be64 service_mask);
struct ib_cm_req_param { struct ib_cm_req_param {
struct ib_sa_path_rec *primary_path; struct ib_sa_path_rec *primary_path;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册