[openib-general] [PATCH 3/4] IB CM: register and handle COMM_EST events on a QP

Sean Hefty sean.hefty at intel.com
Fri Jul 21 14:54:11 PDT 2006


Register the IB CM to receive and process communication established
events on a QP.  This requires tracking connections using local QPNs
as part of timewait handling.

Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
Index: core/cm.c
===================================================================
--- core/cm.c	(revision 8629)
+++ core/cm.c	(working copy)
@@ -69,6 +69,7 @@ static struct ib_cm {
 	struct rb_root listen_service_table;
 	u64 listen_service_id;
 	/* struct rb_root peer_service_table; todo: fix peer to peer */
+	struct rb_root local_qp_table;
 	struct rb_root remote_qp_table;
 	struct rb_root remote_id_table;
 	struct rb_root remote_sidr_table;
@@ -110,10 +111,14 @@ struct cm_work {
 
 struct cm_timewait_info {
 	struct cm_work work;			/* Must be first. */
+	struct rb_node local_qp_node;
 	struct rb_node remote_qp_node;
 	struct rb_node remote_id_node;
+	__be64 local_ca_guid;
 	__be64 remote_ca_guid;
+	__be32 local_qpn;
 	__be32 remote_qpn;
+	u8 inserted_local_qp;
 	u8 inserted_remote_qp;
 	u8 inserted_remote_id;
 };
@@ -508,6 +513,59 @@ static struct cm_timewait_info * cm_find
 	return NULL;
 }
 
+static struct cm_timewait_info * cm_insert_local_qpn(struct cm_timewait_info
+						     *timewait_info)
+{
+	struct rb_node **link = &cm.local_qp_table.rb_node;
+	struct rb_node *parent = NULL;
+	struct cm_timewait_info *cur_timewait_info;
+	__be64 local_ca_guid = timewait_info->local_ca_guid;
+	__be32 local_qpn = timewait_info->local_qpn;
+
+	while (*link) {
+		parent = *link;
+		cur_timewait_info = rb_entry(parent, struct cm_timewait_info,
+					     local_qp_node);
+		if (local_qpn < cur_timewait_info->local_qpn)
+			link = &(*link)->rb_left;
+		else if (local_qpn > cur_timewait_info->local_qpn)
+			link = &(*link)->rb_right;
+		else if (local_ca_guid < cur_timewait_info->local_ca_guid)
+			link = &(*link)->rb_left;
+		else if (local_ca_guid > cur_timewait_info->local_ca_guid)
+			link = &(*link)->rb_right;
+		else
+			return cur_timewait_info;
+	}
+	timewait_info->inserted_local_qp = 1;
+	rb_link_node(&timewait_info->local_qp_node, parent, link);
+	rb_insert_color(&timewait_info->local_qp_node, &cm.local_qp_table);
+	return NULL;
+}
+
+static struct cm_timewait_info * cm_find_local_qpn(__be64 local_ca_guid,
+						   __be32 local_qpn)
+{
+	struct rb_node *node = cm.local_qp_table.rb_node;
+	struct cm_timewait_info *timewait_info;
+
+	while (node) {
+		timewait_info = rb_entry(node, struct cm_timewait_info,
+					 local_qp_node);
+		if (local_qpn < timewait_info->local_qpn)
+			node = node->rb_left;
+		else if (local_qpn > timewait_info->local_qpn)
+			node = node->rb_right;
+		else if (local_ca_guid < timewait_info->local_ca_guid)
+			node = node->rb_left;
+		else if (local_ca_guid > timewait_info->local_ca_guid)
+			node = node->rb_right;
+		else
+			return timewait_info;
+	}
+	return NULL;
+}
+
 static struct cm_timewait_info * cm_insert_remote_qpn(struct cm_timewait_info
 						      *timewait_info)
 {
@@ -640,11 +698,22 @@ static inline int cm_convert_to_ms(int i
 	return 1 << max(iba_time - 8, 0);
 }
 
+static void cm_cleanup_local_qpn(struct cm_timewait_info *timewait_info)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cm.lock, flags);
+	rb_erase(&timewait_info->local_qp_node, &cm.local_qp_table);
+	timewait_info->inserted_local_qp = 0;
+	spin_unlock_irqrestore(&cm.lock, flags);
+}
+
 static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info)
 {
 	unsigned long flags;
 
 	if (!timewait_info->inserted_remote_id &&
+	    !timewait_info->inserted_local_qp &&
 	    !timewait_info->inserted_remote_qp)
 	    return;
 
@@ -654,6 +723,11 @@ static void cm_cleanup_timewait(struct c
 		timewait_info->inserted_remote_id = 0;
 	}
 
+	if (timewait_info->inserted_local_qp) {
+		rb_erase(&timewait_info->local_qp_node, &cm.local_qp_table);
+		timewait_info->inserted_local_qp = 0;
+	}
+
 	if (timewait_info->inserted_remote_qp) {
 		rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table);
 		timewait_info->inserted_remote_qp = 0;
@@ -1015,20 +1089,33 @@ int ib_send_cm_req(struct ib_cm_id *cm_i
 	cm_id_priv->local_ack_timeout =
 				cm_req_get_primary_local_ack_timeout(req_msg);
 
+	cm_id_priv->timewait_info->local_ca_guid = req_msg->local_ca_guid;
+	cm_id_priv->timewait_info->local_qpn = cm_id_priv->local_qpn;
+	spin_lock_irqsave(&cm.lock, flags);
+	if (cm_insert_local_qpn(cm_id_priv->timewait_info))
+		ret = -EADDRINUSE;
+	spin_unlock_irqrestore(&cm.lock, flags);
+	if (ret)
+		goto error2;
+
 	spin_lock_irqsave(&cm_id_priv->lock, flags);
 	ret = ib_post_send_mad(cm_id_priv->msg, NULL);
 	if (ret) {
 		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-		goto error2;
+		goto error3;
 	}
 	BUG_ON(cm_id->state != IB_CM_IDLE);
 	cm_id->state = IB_CM_REQ_SENT;
 	spin_unlock_irqrestore(&cm_id_priv->lock, flags);
 	return 0;
 
-error2:	cm_free_msg(cm_id_priv->msg);
-error1:	kfree(cm_id_priv->timewait_info);
-out:	return ret;
+error3:
+	cm_cleanup_local_qpn(cm_id_priv->timewait_info);
+error2:
+	cm_free_msg(cm_id_priv->msg);
+error1:
+	kfree(cm_id_priv->timewait_info);
+	return ret;
 }
 EXPORT_SYMBOL(ib_send_cm_req);
 
@@ -1444,7 +1531,7 @@ int ib_send_cm_rep(struct ib_cm_id *cm_i
 		   struct ib_cm_rep_param *param)
 {
 	struct cm_id_private *cm_id_priv;
-	struct ib_mad_send_buf *msg;
+	struct ib_mad_send_buf *msg = NULL;
 	struct cm_rep_msg *rep_msg;
 	unsigned long flags;
 	int ret;
@@ -1458,12 +1545,20 @@ int ib_send_cm_rep(struct ib_cm_id *cm_i
 	if (cm_id->state != IB_CM_REQ_RCVD &&
 	    cm_id->state != IB_CM_MRA_REQ_SENT) {
 		ret = -EINVAL;
-		goto out;
+		goto error;
 	}
 
+	cm_id_priv->timewait_info->local_ca_guid = cm_id->device->node_guid;
+	cm_id_priv->timewait_info->local_qpn = cpu_to_be32(param->qp_num);
+	spin_lock(&cm.lock);
+	ret = cm_insert_local_qpn(cm_id_priv->timewait_info) ? -EADDRINUSE : 0;
+	spin_unlock(&cm.lock);
+	if (ret)
+		goto error;
+
 	ret = cm_alloc_msg(cm_id_priv, &msg);
 	if (ret)
-		goto out;
+		goto error;
 
 	rep_msg = (struct cm_rep_msg *) msg->mad;
 	cm_format_rep(rep_msg, cm_id_priv, param);
@@ -1471,11 +1566,8 @@ int ib_send_cm_rep(struct ib_cm_id *cm_i
 	msg->context[1] = (void *) (unsigned long) IB_CM_REP_SENT;
 
 	ret = ib_post_send_mad(msg, NULL);
-	if (ret) {
-		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-		cm_free_msg(msg);
-		return ret;
-	}
+	if (ret)
+		goto error;
 
 	cm_id->state = IB_CM_REP_SENT;
 	cm_id_priv->msg = msg;
@@ -1483,8 +1575,15 @@ int ib_send_cm_rep(struct ib_cm_id *cm_i
 	cm_id_priv->responder_resources = param->responder_resources;
 	cm_id_priv->rq_psn = cm_rep_get_starting_psn(rep_msg);
 	cm_id_priv->local_qpn = cm_rep_get_local_qpn(rep_msg);
+	spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+	return 0;
 
-out:	spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+error:
+	spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+	if (cm_id_priv->timewait_info->inserted_local_qp)
+		cm_cleanup_local_qpn(cm_id_priv->timewait_info);
+	if (msg)
+		cm_free_msg(msg);
 	return ret;
 }
 EXPORT_SYMBOL(ib_send_cm_rep);
@@ -2603,6 +2702,7 @@ static int cm_timewait_handler(struct cm
 
 	spin_lock_irqsave(&cm_id_priv->lock, flags);
 	if (cm_id_priv->id.state != IB_CM_TIMEWAIT ||
+	    cm_id_priv->local_qpn != timewait_info->local_qpn ||
 	    cm_id_priv->remote_qpn != timewait_info->remote_qpn) {
 		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
 		goto out;
@@ -3113,6 +3213,28 @@ static void cm_recv_handler(struct ib_ma
 	queue_work(cm.wq, &work->work);
 }
 
+static void cm_event_handler(struct ib_event *event)
+{
+	struct cm_id_private *cm_id_priv = NULL;
+	struct cm_timewait_info *timewait_info;
+	unsigned long flags;
+
+	if (event->event == IB_EVENT_COMM_EST) {
+		spin_lock_irqsave(&cm.lock, flags);
+		timewait_info = cm_find_local_qpn(event->device->node_guid,
+						  cpu_to_be32(event->element.
+							      qp->qp_num));
+		if (timewait_info)
+			cm_id_priv = cm_get_id(timewait_info->work.local_id,
+					       timewait_info->work.remote_id);
+		spin_unlock_irqrestore(&cm.lock, flags);
+		if (cm_id_priv) {
+			ib_cm_establish(&cm_id_priv->id);
+			cm_deref_id(cm_id_priv);
+		}
+	}
+}
+
 static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv,
 				struct ib_qp_attr *qp_attr,
 				int *qp_attr_mask)
@@ -3308,6 +3430,7 @@ static void cm_add_one(struct ib_device 
 
 	cm_dev->device = device;
 	cm_dev->ca_guid = device->node_guid;
+	ib_register_cm_handler(device, cm_event_handler);
 
 	set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
 	for (i = 1; i <= device->phys_port_cnt; i++) {
@@ -3345,6 +3468,7 @@ error1:
 		ib_modify_port(device, port->port_num, 0, &port_modify);
 		ib_unregister_mad_agent(port->mad_agent);
 	}
+	ib_unregister_cm_handler(device);
 	kfree(cm_dev);
 }
 
@@ -3371,6 +3495,7 @@ static void cm_remove_one(struct ib_devi
 		ib_modify_port(device, port->port_num, 0, &port_modify);
 		ib_unregister_mad_agent(port->mad_agent);
 	}
+	ib_unregister_cm_handler(device);
 	kfree(cm_dev);
 }
 
@@ -3385,6 +3510,7 @@ static int __init ib_cm_init(void)
 	cm.listen_service_table = RB_ROOT;
 	cm.listen_service_id = __constant_be64_to_cpu(IB_CM_ASSIGN_SERVICE_ID);
 	cm.remote_id_table = RB_ROOT;
+	cm.local_qp_table = RB_ROOT;
 	cm.remote_qp_table = RB_ROOT;
 	cm.remote_sidr_table = RB_ROOT;
 	idr_init(&cm.local_id_table);





More information about the general mailing list