[openib-general] [PATCH] [CM] add support to repeat MRA messages
Sean Hefty
sean.hefty at intel.com
Mon May 23 14:55:12 PDT 2005
The following patch adds support to repeat MRA messages in response to
receiving a duplicate REQ, REP, or LAP.
Signed-off-by: Sean Hefty <sean.hefty at intel.com>
Index: cm.c
===================================================================
--- cm.c (revision 2417)
+++ cm.c (working copy)
@@ -143,6 +143,7 @@ struct cm_id_private {
u8 local_ack_timeout;
u8 retry_count;
u8 rnr_retry_count;
+ u8 service_timeout;
struct list_head work_list;
atomic_t work_count;
@@ -292,12 +293,10 @@ static void cm_free_id(u32 local_id)
spin_unlock_irqrestore(&cm.lock, flags);
}
-static struct cm_id_private * cm_acquire_id(u32 local_id, u32 remote_id)
+static struct cm_id_private * cm_get_id(u32 local_id, u32 remote_id)
{
struct cm_id_private *cm_id_priv;
- unsigned long flags;
- spin_lock_irqsave(&cm.lock, flags);
cm_id_priv = idr_find(&cm.local_id_table, (int) local_id);
if (cm_id_priv) {
if (cm_id_priv->id.remote_id == remote_id)
@@ -305,6 +304,17 @@ static struct cm_id_private * cm_acquire
else
cm_id_priv = NULL;
}
+
+ return cm_id_priv;
+}
+
+static struct cm_id_private * cm_acquire_id(u32 local_id, u32 remote_id)
+{
+ struct cm_id_private *cm_id_priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cm.lock, flags);
+ cm_id_priv = cm_get_id(local_id, remote_id);
spin_unlock_irqrestore(&cm.lock, flags);
return cm_id_priv;
@@ -1029,18 +1039,175 @@ static void cm_process_work(struct cm_id
ib_destroy_cm_id(&cm_id_priv->id);
}
+static void cm_format_mra(struct cm_mra_msg *mra_msg,
+ struct cm_id_private *cm_id_priv,
+ enum cm_msg_response msg_mraed, u8 service_timeout,
+ const void *private_data, u8 private_data_len)
+{
+ /* todo: TID should match REQ or LAP */
+ if (msg_mraed == CM_MSG_RESPONSE_OTHER)
+ cm_format_mad_hdr(&mra_msg->hdr, CM_MRA_ATTR_ID,
+ cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_LAP));
+ else
+ cm_format_mad_hdr(&mra_msg->hdr, CM_MRA_ATTR_ID,
+ cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_REQ));
+
+ cm_mra_set_msg_mraed(mra_msg, msg_mraed);
+
+ mra_msg->local_comm_id = cm_id_priv->id.local_id;
+ mra_msg->remote_comm_id = cm_id_priv->id.remote_id;
+ cm_mra_set_service_timeout(mra_msg, service_timeout);
+
+ if (private_data && private_data_len)
+ memcpy(mra_msg->private_data, private_data, private_data_len);
+}
+
+static void cm_format_rej(struct cm_rej_msg *rej_msg,
+ struct cm_id_private *cm_id_priv,
+ enum ib_cm_rej_reason reason,
+ void *ari,
+ u8 ari_length,
+ const void *private_data,
+ u8 private_data_len)
+{
+ /* todo: TID should match received REQ */
+ cm_format_mad_hdr(&rej_msg->hdr, CM_REJ_ATTR_ID,
+ cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_REQ));
+
+ rej_msg->remote_comm_id = cm_id_priv->id.remote_id;
+
+ switch(cm_id_priv->id.state) {
+ case IB_CM_REQ_RCVD:
+ rej_msg->local_comm_id = 0;
+ cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_REQ);
+ break;
+ case IB_CM_MRA_REQ_SENT:
+ rej_msg->local_comm_id = cm_id_priv->id.local_id;
+ cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_REQ);
+ break;
+ case IB_CM_REP_RCVD:
+ case IB_CM_MRA_REP_SENT:
+ rej_msg->local_comm_id = cm_id_priv->id.local_id;
+ cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_REP);
+ break;
+ default:
+ rej_msg->local_comm_id = cm_id_priv->id.local_id;
+ cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_OTHER);
+ break;
+ }
+
+ rej_msg->reason = reason;
+ if (ari && ari_length) {
+ cm_rej_set_reject_info_len(rej_msg, ari_length);
+ memcpy(rej_msg->ari, ari, ari_length);
+ }
+
+ if (private_data && private_data_len)
+ memcpy(rej_msg->private_data, private_data, private_data_len);
+}
+
+static void cm_dup_req_handler(struct cm_work *work,
+ struct cm_id_private *cm_id_priv)
+{
+ struct ib_mad_send_buf *msg = NULL;
+ struct ib_send_wr *bad_send_wr;
+ unsigned long flags;
+ int ret;
+
+ /* Quick state check to discard duplicate REQs. */
+ if (cm_id_priv->id.state == IB_CM_REQ_RCVD)
+ return;
+
+ ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg);
+ if (ret)
+ return;
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ switch (cm_id_priv->id.state) {
+ case IB_CM_MRA_REQ_SENT:
+ cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
+ CM_MSG_RESPONSE_REQ, cm_id_priv->service_timeout,
+ cm_id_priv->private_data,
+ cm_id_priv->private_data_len);
+ break;
+ case IB_CM_TIMEWAIT:
+ cm_format_rej((struct cm_rej_msg *) msg->mad, cm_id_priv,
+ IB_CM_REJ_STALE_CONN, NULL, 0, NULL, 0);
+ break;
+ default:
+ goto unlock;
+ }
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+
+ ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, &msg->send_wr,
+ &bad_send_wr);
+ if (ret)
+ goto free;
+ return;
+
+unlock: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+free: cm_free_msg(msg);
+}
+
+static struct cm_id_private * cm_match_req(struct cm_work *work,
+ struct cm_id_private *cm_id_priv)
+{
+ struct cm_id_private *listen_cm_id_priv, *cur_cm_id_priv;
+ struct cm_timewait_info *timewait_info;
+ struct cm_req_msg *req_msg;
+ unsigned long flags;
+
+ req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad;
+
+ /* Check for duplicate REQ and stale connections. */
+ spin_lock_irqsave(&cm.lock, flags);
+ timewait_info = cm_insert_remote_id(cm_id_priv->timewait_info);
+ if (!timewait_info)
+ timewait_info = cm_insert_remote_qpn(cm_id_priv->timewait_info);
+
+ if (timewait_info) {
+ cur_cm_id_priv = cm_get_id(timewait_info->work.local_id,
+ timewait_info->work.remote_id);
+ spin_unlock_irqrestore(&cm.lock, flags);
+ if (cur_cm_id_priv) {
+ cm_dup_req_handler(work, cur_cm_id_priv);
+ cm_deref_id(cur_cm_id_priv);
+ } else
+ cm_issue_rej(work->port, work->mad_recv_wc,
+ IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ,
+ NULL, 0);
+ goto error;
+ }
+
+ /* Find matching listen request. */
+ listen_cm_id_priv = cm_find_listen(req_msg->service_id);
+ if (!listen_cm_id_priv) {
+ spin_unlock_irqrestore(&cm.lock, flags);
+ cm_issue_rej(work->port, work->mad_recv_wc,
+ IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ,
+ NULL, 0);
+ goto error;
+ }
+ atomic_inc(&listen_cm_id_priv->refcount);
+ atomic_inc(&cm_id_priv->refcount);
+ cm_id_priv->id.state = IB_CM_REQ_RCVD;
+ atomic_inc(&cm_id_priv->work_count);
+ spin_unlock_irqrestore(&cm.lock, flags);
+ return listen_cm_id_priv;
+
+error: cm_cleanup_timewait(cm_id_priv->timewait_info);
+ return NULL;
+}
+
static int cm_req_handler(struct cm_work *work)
{
struct ib_cm_id *cm_id;
struct cm_id_private *cm_id_priv, *listen_cm_id_priv;
struct cm_req_msg *req_msg;
- unsigned long flags;
int ret;
req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad;
- /* todo: Check for peer-to-peer connection. */
-
cm_id = ib_create_cm_id(NULL, NULL);
if (IS_ERR(cm_id))
return PTR_ERR(cm_id);
@@ -1059,37 +1226,11 @@ static int cm_req_handler(struct cm_work
cm_id_priv->timewait_info->remote_ca_guid = req_msg->local_ca_guid;
cm_id_priv->timewait_info->remote_qpn = cm_req_get_local_qpn(req_msg);
- spin_lock_irqsave(&cm.lock, flags);
- /* Check for duplicate REQ. */
- if (cm_insert_remote_id(cm_id_priv->timewait_info)) {
- spin_unlock_irqrestore(&cm.lock, flags);
- ret = -EINVAL;
- goto error2;
- }
- /* Check for a stale connection. */
- if (cm_insert_remote_qpn(cm_id_priv->timewait_info)) {
- spin_unlock_irqrestore(&cm.lock, flags);
- cm_issue_rej(work->port, work->mad_recv_wc,
- IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ,
- NULL, 0);
- ret = -EINVAL;
- goto error2;
- }
- /* Find matching listen request. */
- listen_cm_id_priv = cm_find_listen(req_msg->service_id);
+ listen_cm_id_priv = cm_match_req(work, cm_id_priv);
if (!listen_cm_id_priv) {
- spin_unlock_irqrestore(&cm.lock, flags);
- cm_issue_rej(work->port, work->mad_recv_wc,
- IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ,
- NULL, 0);
ret = -EINVAL;
goto error2;
}
- atomic_inc(&listen_cm_id_priv->refcount);
- atomic_inc(&cm_id_priv->refcount);
- cm_id_priv->id.state = IB_CM_REQ_RCVD;
- atomic_inc(&cm_id_priv->work_count);
- spin_unlock_irqrestore(&cm.lock, flags);
cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler;
cm_id_priv->id.context = listen_cm_id_priv->id.context;
@@ -1125,8 +1266,8 @@ static int cm_req_handler(struct cm_work
error3: atomic_dec(&cm_id_priv->refcount);
cm_deref_id(listen_cm_id_priv);
-error2: cm_cleanup_timewait(cm_id_priv->timewait_info);
- kfree(cm_id_priv->timewait_info);
+ cm_cleanup_timewait(cm_id_priv->timewait_info);
+error2: kfree(cm_id_priv->timewait_info);
error1: ib_destroy_cm_id(&cm_id_priv->id);
return ret;
}
@@ -1291,7 +1432,7 @@ static void cm_dup_rep_handler(struct cm
{
struct cm_id_private *cm_id_priv;
struct cm_rep_msg *rep_msg;
- struct ib_mad_send_buf *msg;
+ struct ib_mad_send_buf *msg = NULL;
struct ib_send_wr *bad_send_wr;
unsigned long flags;
int ret;
@@ -1304,26 +1445,31 @@ static void cm_dup_rep_handler(struct cm
ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg);
if (ret)
- goto out;
+ goto deref;
spin_lock_irqsave(&cm_id_priv->lock, flags);
- if (cm_id_priv->id.state != IB_CM_ESTABLISHED ||
- cm_id_priv->id.lap_state != IB_CM_LAP_IDLE) {
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- goto error;
- }
- cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv,
- cm_id_priv->private_data, cm_id_priv->private_data_len);
+ if (cm_id_priv->id.state == IB_CM_ESTABLISHED)
+ cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv,
+ cm_id_priv->private_data,
+ cm_id_priv->private_data_len);
+ else if (cm_id_priv->id.state == IB_CM_MRA_REP_SENT)
+ cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
+ CM_MSG_RESPONSE_REP, cm_id_priv->service_timeout,
+ cm_id_priv->private_data,
+ cm_id_priv->private_data_len);
+ else
+ goto unlock;
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent, &msg->send_wr,
&bad_send_wr);
if (ret)
- goto error;
- goto out;
+ goto free;
+ goto deref;
-error: cm_free_msg(msg);
-out: cm_deref_id(cm_id_priv);
+unlock: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+free: cm_free_msg(msg);
+deref: cm_deref_id(cm_id_priv);
}
static int cm_rep_handler(struct cm_work *work)
@@ -1593,7 +1739,7 @@ static int cm_dreq_handler(struct cm_wor
{
struct cm_id_private *cm_id_priv;
struct cm_dreq_msg *dreq_msg;
- struct ib_mad_send_buf *msg;
+ struct ib_mad_send_buf *msg = NULL;
struct ib_send_wr *bad_send_wr;
unsigned long flags;
int ret;
@@ -1689,50 +1835,6 @@ out:
return -EINVAL;
}
-static void cm_format_rej(struct cm_rej_msg *rej_msg,
- struct cm_id_private *cm_id_priv,
- enum ib_cm_rej_reason reason,
- void *ari,
- u8 ari_length,
- const void *private_data,
- u8 private_data_len)
-{
- /* todo: TID should match received REQ */
- cm_format_mad_hdr(&rej_msg->hdr, CM_REJ_ATTR_ID,
- cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_REQ));
-
- rej_msg->remote_comm_id = cm_id_priv->id.remote_id;
-
- switch(cm_id_priv->id.state) {
- case IB_CM_REQ_RCVD:
- rej_msg->local_comm_id = 0;
- cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_REQ);
- break;
- case IB_CM_MRA_REQ_SENT:
- rej_msg->local_comm_id = cm_id_priv->id.local_id;
- cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_REQ);
- break;
- case IB_CM_REP_RCVD:
- case IB_CM_MRA_REP_SENT:
- rej_msg->local_comm_id = cm_id_priv->id.local_id;
- cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_REP);
- break;
- default:
- rej_msg->local_comm_id = cm_id_priv->id.local_id;
- cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_OTHER);
- break;
- }
-
- rej_msg->reason = reason;
- if (ari && ari_length) {
- cm_rej_set_reject_info_len(rej_msg, ari_length);
- memcpy(rej_msg->ari, ari, ari_length);
- }
-
- if (private_data && private_data_len)
- memcpy(rej_msg->private_data, private_data, private_data_len);
-}
-
int ib_send_cm_rej(struct ib_cm_id *cm_id,
enum ib_cm_rej_reason reason,
void *ari,
@@ -1895,48 +1997,6 @@ out:
return -EINVAL;
}
-static void cm_format_mra(struct cm_mra_msg *mra_msg,
- struct cm_id_private *cm_id_priv,
- u8 service_timeout,
- const void *private_data,
- u8 private_data_len)
-{
- enum cm_msg_sequence msg_sequence;
- unsigned long flags;
- enum cm_msg_response msg_mraed;
-
- spin_lock_irqsave(&cm_id_priv->lock, flags);
- switch(cm_id_priv->id.state) {
- case IB_CM_REQ_RCVD:
- msg_sequence = CM_MSG_SEQUENCE_REQ;
- msg_mraed = CM_MSG_RESPONSE_REQ;
- break;
- case IB_CM_REP_RCVD:
- msg_sequence = CM_MSG_SEQUENCE_REQ;
- msg_mraed = CM_MSG_RESPONSE_REP;
- break;
- case IB_CM_ESTABLISHED:
- msg_sequence = CM_MSG_SEQUENCE_LAP;
- msg_mraed = CM_MSG_RESPONSE_OTHER;
- break;
- default:
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- return;
- }
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- /* todo: TID should matched REQ or LAP */
- cm_format_mad_hdr(&mra_msg->hdr, CM_MRA_ATTR_ID,
- cm_form_tid(cm_id_priv, msg_sequence));
- cm_mra_set_msg_mraed(mra_msg, msg_mraed);
-
- mra_msg->local_comm_id = cm_id_priv->id.local_id;
- mra_msg->remote_comm_id = cm_id_priv->id.remote_id;
- cm_mra_set_service_timeout(mra_msg, service_timeout);
-
- if (private_data && private_data_len)
- memcpy(mra_msg->private_data, private_data, private_data_len);
-}
-
int ib_send_cm_mra(struct ib_cm_id *cm_id,
u8 service_timeout,
const void *private_data,
@@ -1954,44 +2014,50 @@ int ib_send_cm_mra(struct ib_cm_id *cm_i
cm_id_priv = container_of(cm_id, struct cm_id_private, id);
ret = cm_alloc_msg(cm_id_priv, &msg);
if (ret)
- goto out;
-
- cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
- service_timeout, private_data, private_data_len);
+ return ret;
spin_lock_irqsave(&cm_id_priv->lock, flags);
- if (cm_id_priv->id.state == IB_CM_REQ_RCVD ||
- cm_id_priv->id.state == IB_CM_REP_RCVD ||
- (cm_id_priv->id.state == IB_CM_ESTABLISHED &&
- cm_id_priv->id.lap_state == IB_CM_LAP_RCVD)) {
-
+ switch(cm_id_priv->id.state) {
+ case IB_CM_REQ_RCVD:
+ cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
+ CM_MSG_RESPONSE_REQ, service_timeout,
+ private_data, private_data_len);
ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
&msg->send_wr, &bad_send_wr);
- } else {
- ret = -EINVAL;
- }
-
- if (ret) {
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- cm_free_msg(msg);
- goto out;
- }
-
- switch (cm_id_priv->id.state) {
- case IB_CM_REQ_RCVD:
+ if (ret)
+ goto error;
cm_id->state = IB_CM_MRA_REQ_SENT;
break;
case IB_CM_REP_RCVD:
+ cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
+ CM_MSG_RESPONSE_REP, service_timeout,
+ private_data, private_data_len);
+ ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
+ &msg->send_wr, &bad_send_wr);
+ if (ret)
+ goto error;
cm_id->state = IB_CM_MRA_REP_SENT;
break;
case IB_CM_ESTABLISHED:
- cm_id_priv->id.lap_state = IB_CM_MRA_LAP_SENT;
+ cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
+ CM_MSG_RESPONSE_OTHER, service_timeout,
+ private_data, private_data_len);
+ ret = ib_post_send_mad(cm_id_priv->av.port->mad_agent,
+ &msg->send_wr, &bad_send_wr);
+ if (ret)
+ goto error;
+ cm_id->lap_state = IB_CM_MRA_LAP_SENT;
break;
default:
- break;
+ ret = -EINVAL;
+ goto error;
}
+ cm_id_priv->service_timeout = service_timeout;
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-out:
+ return 0;
+
+error: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ cm_free_msg(msg);
return ret;
}
EXPORT_SYMBOL(ib_send_cm_mra);
@@ -2177,6 +2243,8 @@ static int cm_lap_handler(struct cm_work
struct cm_id_private *cm_id_priv;
struct cm_lap_msg *lap_msg;
struct ib_cm_lap_event_param *param;
+ struct ib_mad_send_buf *msg = NULL;
+ struct ib_send_wr *bad_send_wr;
unsigned long flags;
int ret;
@@ -2193,11 +2261,31 @@ static int cm_lap_handler(struct cm_work
work->cm_event.private_data = &lap_msg->private_data;
spin_lock_irqsave(&cm_id_priv->lock, flags);
- if (cm_id_priv->id.state != IB_CM_ESTABLISHED &&
- cm_id_priv->id.lap_state != IB_CM_LAP_IDLE) {
+ if (cm_id_priv->id.state != IB_CM_ESTABLISHED)
+ goto unlock;
+
+ switch (cm_id_priv->id.lap_state) {
+ case IB_CM_LAP_IDLE:
+ break;
+ case IB_CM_MRA_LAP_SENT:
+ if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg))
+ goto unlock;
+
+ cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
+ CM_MSG_RESPONSE_OTHER,
+ cm_id_priv->service_timeout,
+ cm_id_priv->private_data,
+ cm_id_priv->private_data_len);
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- goto out;
+
+ if (ib_post_send_mad(cm_id_priv->av.port->mad_agent,
+ &msg->send_wr, &bad_send_wr))
+ cm_free_msg(msg);
+ goto deref;
+ default:
+ goto unlock;
}
+
cm_id_priv->id.lap_state = IB_CM_LAP_RCVD;
ret = atomic_inc_and_test(&cm_id_priv->work_count);
if (!ret)
@@ -2209,8 +2297,9 @@ static int cm_lap_handler(struct cm_work
else
cm_deref_id(cm_id_priv);
return 0;
-out:
- cm_deref_id(cm_id_priv);
+
+unlock: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+deref: cm_deref_id(cm_id_priv);
return -EINVAL;
}
More information about the general
mailing list