aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorSean Hefty <sean.hefty@intel.com>2006-06-17 23:37:28 -0400
committerRoland Dreier <rolandd@cisco.com>2006-06-17 23:37:28 -0400
commit6e61d04f2d8c7ac4f67e1f498ed2a2a3ad8edaa3 (patch)
treecf184fe1a9ebc7187cd452b2427234726436da94 /drivers/infiniband
parent6a9af2e18a5c6ebcf8283309d20ac0e9fa35e346 (diff)
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: Sean Hefty <sean.hefty@intel.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/core/cm.c91
-rw-r--r--drivers/infiniband/core/ucm.c19
2 files changed, 97 insertions, 13 deletions
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 86fee43502cd..490fd03766db 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -32,7 +32,7 @@
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE. 33 * SOFTWARE.
34 * 34 *
35 * $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $ 35 * $Id: cm.c 4311 2005-12-05 18:42:01Z sean.hefty $
36 */ 36 */
37 37
38#include <linux/completion.h> 38#include <linux/completion.h>
@@ -132,6 +132,7 @@ struct cm_id_private {
132 /* todo: use alternate port on send failure */ 132 /* todo: use alternate port on send failure */
133 struct cm_av av; 133 struct cm_av av;
134 struct cm_av alt_av; 134 struct cm_av alt_av;
135 struct ib_cm_compare_data *compare_data;
135 136
136 void *private_data; 137 void *private_data;
137 __be64 tid; 138 __be64 tid;
@@ -357,6 +358,41 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id)
357 return cm_id_priv; 358 return cm_id_priv;
358} 359}
359 360
361static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask)
362{
363 int i;
364
365 for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++)
366 ((unsigned long *) dst)[i] = ((unsigned long *) src)[i] &
367 ((unsigned long *) mask)[i];
368}
369
370static int cm_compare_data(struct ib_cm_compare_data *src_data,
371 struct ib_cm_compare_data *dst_data)
372{
373 u8 src[IB_CM_COMPARE_SIZE];
374 u8 dst[IB_CM_COMPARE_SIZE];
375
376 if (!src_data || !dst_data)
377 return 0;
378
379 cm_mask_copy(src, src_data->data, dst_data->mask);
380 cm_mask_copy(dst, dst_data->data, src_data->mask);
381 return memcmp(src, dst, IB_CM_COMPARE_SIZE);
382}
383
384static int cm_compare_private_data(u8 *private_data,
385 struct ib_cm_compare_data *dst_data)
386{
387 u8 src[IB_CM_COMPARE_SIZE];
388
389 if (!dst_data)
390 return 0;
391
392 cm_mask_copy(src, private_data, dst_data->mask);
393 return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE);
394}
395
360static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) 396static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
361{ 397{
362 struct rb_node **link = &cm.listen_service_table.rb_node; 398 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 struct cm_id_private *cur_cm_id_priv; 400 struct cm_id_private *cur_cm_id_priv;
365 __be64 service_id = cm_id_priv->id.service_id; 401 __be64 service_id = cm_id_priv->id.service_id;
366 __be64 service_mask = cm_id_priv->id.service_mask; 402 __be64 service_mask = cm_id_priv->id.service_mask;
403 int data_cmp;
367 404
368 while (*link) { 405 while (*link) {
369 parent = *link; 406 parent = *link;
370 cur_cm_id_priv = rb_entry(parent, struct cm_id_private, 407 cur_cm_id_priv = rb_entry(parent, struct cm_id_private,
371 service_node); 408 service_node);
409 data_cmp = cm_compare_data(cm_id_priv->compare_data,
410 cur_cm_id_priv->compare_data);
372 if ((cur_cm_id_priv->id.service_mask & service_id) == 411 if ((cur_cm_id_priv->id.service_mask & service_id) ==
373 (service_mask & cur_cm_id_priv->id.service_id) && 412 (service_mask & cur_cm_id_priv->id.service_id) &&
374 (cm_id_priv->id.device == cur_cm_id_priv->id.device)) 413 (cm_id_priv->id.device == cur_cm_id_priv->id.device) &&
414 !data_cmp)
375 return cur_cm_id_priv; 415 return cur_cm_id_priv;
376 416
377 if (cm_id_priv->id.device < cur_cm_id_priv->id.device) 417 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 link = &(*link)->rb_right; 420 link = &(*link)->rb_right;
381 else if (service_id < cur_cm_id_priv->id.service_id) 421 else if (service_id < cur_cm_id_priv->id.service_id)
382 link = &(*link)->rb_left; 422 link = &(*link)->rb_left;
423 else if (service_id > cur_cm_id_priv->id.service_id)
424 link = &(*link)->rb_right;
425 else if (data_cmp < 0)
426 link = &(*link)->rb_left;
383 else 427 else
384 link = &(*link)->rb_right; 428 link = &(*link)->rb_right;
385 } 429 }
@@ -389,16 +433,20 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
389} 433}
390 434
391static struct cm_id_private * cm_find_listen(struct ib_device *device, 435static struct cm_id_private * cm_find_listen(struct ib_device *device,
392 __be64 service_id) 436 __be64 service_id,
437 u8 *private_data)
393{ 438{
394 struct rb_node *node = cm.listen_service_table.rb_node; 439 struct rb_node *node = cm.listen_service_table.rb_node;
395 struct cm_id_private *cm_id_priv; 440 struct cm_id_private *cm_id_priv;
441 int data_cmp;
396 442
397 while (node) { 443 while (node) {
398 cm_id_priv = rb_entry(node, struct cm_id_private, service_node); 444 cm_id_priv = rb_entry(node, struct cm_id_private, service_node);
445 data_cmp = cm_compare_private_data(private_data,
446 cm_id_priv->compare_data);
399 if ((cm_id_priv->id.service_mask & service_id) == 447 if ((cm_id_priv->id.service_mask & service_id) ==
400 cm_id_priv->id.service_id && 448 cm_id_priv->id.service_id &&
401 (cm_id_priv->id.device == device)) 449 (cm_id_priv->id.device == device) && !data_cmp)
402 return cm_id_priv; 450 return cm_id_priv;
403 451
404 if (device < cm_id_priv->id.device) 452 if (device < cm_id_priv->id.device)
@@ -407,6 +455,10 @@ static struct cm_id_private * cm_find_listen(struct ib_device *device,
407 node = node->rb_right; 455 node = node->rb_right;
408 else if (service_id < cm_id_priv->id.service_id) 456 else if (service_id < cm_id_priv->id.service_id)
409 node = node->rb_left; 457 node = node->rb_left;
458 else if (service_id > cm_id_priv->id.service_id)
459 node = node->rb_right;
460 else if (data_cmp < 0)
461 node = node->rb_left;
410 else 462 else
411 node = node->rb_right; 463 node = node->rb_right;
412 } 464 }
@@ -730,15 +782,14 @@ retest:
730 wait_for_completion(&cm_id_priv->comp); 782 wait_for_completion(&cm_id_priv->comp);
731 while ((work = cm_dequeue_work(cm_id_priv)) != NULL) 783 while ((work = cm_dequeue_work(cm_id_priv)) != NULL)
732 cm_free_work(work); 784 cm_free_work(work);
733 if (cm_id_priv->private_data && cm_id_priv->private_data_len) 785 kfree(cm_id_priv->compare_data);
734 kfree(cm_id_priv->private_data); 786 kfree(cm_id_priv->private_data);
735 kfree(cm_id_priv); 787 kfree(cm_id_priv);
736} 788}
737EXPORT_SYMBOL(ib_destroy_cm_id); 789EXPORT_SYMBOL(ib_destroy_cm_id);
738 790
739int ib_cm_listen(struct ib_cm_id *cm_id, 791int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
740 __be64 service_id, 792 struct ib_cm_compare_data *compare_data)
741 __be64 service_mask)
742{ 793{
743 struct cm_id_private *cm_id_priv, *cur_cm_id_priv; 794 struct cm_id_private *cm_id_priv, *cur_cm_id_priv;
744 unsigned long flags; 795 unsigned long flags;
@@ -752,7 +803,19 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
752 return -EINVAL; 803 return -EINVAL;
753 804
754 cm_id_priv = container_of(cm_id, struct cm_id_private, id); 805 cm_id_priv = container_of(cm_id, struct cm_id_private, id);
755 BUG_ON(cm_id->state != IB_CM_IDLE); 806 if (cm_id->state != IB_CM_IDLE)
807 return -EINVAL;
808
809 if (compare_data) {
810 cm_id_priv->compare_data = kzalloc(sizeof *compare_data,
811 GFP_KERNEL);
812 if (!cm_id_priv->compare_data)
813 return -ENOMEM;
814 cm_mask_copy(cm_id_priv->compare_data->data,
815 compare_data->data, compare_data->mask);
816 memcpy(cm_id_priv->compare_data->mask, compare_data->mask,
817 IB_CM_COMPARE_SIZE);
818 }
756 819
757 cm_id->state = IB_CM_LISTEN; 820 cm_id->state = IB_CM_LISTEN;
758 821
@@ -769,6 +832,8 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
769 832
770 if (cur_cm_id_priv) { 833 if (cur_cm_id_priv) {
771 cm_id->state = IB_CM_IDLE; 834 cm_id->state = IB_CM_IDLE;
835 kfree(cm_id_priv->compare_data);
836 cm_id_priv->compare_data = NULL;
772 ret = -EBUSY; 837 ret = -EBUSY;
773 } 838 }
774 return ret; 839 return ret;
@@ -1241,7 +1306,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
1241 1306
1242 /* Find matching listen request. */ 1307 /* Find matching listen request. */
1243 listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, 1308 listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device,
1244 req_msg->service_id); 1309 req_msg->service_id,
1310 req_msg->private_data);
1245 if (!listen_cm_id_priv) { 1311 if (!listen_cm_id_priv) {
1246 spin_unlock_irqrestore(&cm.lock, flags); 1312 spin_unlock_irqrestore(&cm.lock, flags);
1247 cm_issue_rej(work->port, work->mad_recv_wc, 1313 cm_issue_rej(work->port, work->mad_recv_wc,
@@ -2654,7 +2720,8 @@ static int cm_sidr_req_handler(struct cm_work *work)
2654 goto out; /* Duplicate message. */ 2720 goto out; /* Duplicate message. */
2655 } 2721 }
2656 cur_cm_id_priv = cm_find_listen(cm_id->device, 2722 cur_cm_id_priv = cm_find_listen(cm_id->device,
2657 sidr_req_msg->service_id); 2723 sidr_req_msg->service_id,
2724 sidr_req_msg->private_data);
2658 if (!cur_cm_id_priv) { 2725 if (!cur_cm_id_priv) {
2659 rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); 2726 rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);
2660 spin_unlock_irqrestore(&cm.lock, flags); 2727 spin_unlock_irqrestore(&cm.lock, flags);
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index b396bf703f80..0136aee0faa7 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -648,6 +648,17 @@ out:
648 return result; 648 return result;
649} 649}
650 650
651static int ucm_validate_listen(__be64 service_id, __be64 service_mask)
652{
653 service_id &= service_mask;
654
655 if (((service_id & IB_CMA_SERVICE_ID_MASK) == IB_CMA_SERVICE_ID) ||
656 ((service_id & IB_SDP_SERVICE_ID_MASK) == IB_SDP_SERVICE_ID))
657 return -EINVAL;
658
659 return 0;
660}
661
651static ssize_t ib_ucm_listen(struct ib_ucm_file *file, 662static ssize_t ib_ucm_listen(struct ib_ucm_file *file,
652 const char __user *inbuf, 663 const char __user *inbuf,
653 int in_len, int out_len) 664 int in_len, int out_len)
@@ -663,7 +674,13 @@ static ssize_t ib_ucm_listen(struct ib_ucm_file *file,
663 if (IS_ERR(ctx)) 674 if (IS_ERR(ctx))
664 return PTR_ERR(ctx); 675 return PTR_ERR(ctx);
665 676
666 result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask); 677 result = ucm_validate_listen(cmd.service_id, cmd.service_mask);
678 if (result)
679 goto out;
680
681 result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask,
682 NULL);
683out:
667 ib_ucm_ctx_put(ctx); 684 ib_ucm_ctx_put(ctx);
668 return result; 685 return result;
669} 686}