[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