📄 cm.c
字号:
while (node) { timewait_info = rb_entry(node, struct cm_timewait_info, remote_id_node); if (remote_id < timewait_info->work.remote_id) node = node->rb_left; else if (remote_id > timewait_info->work.remote_id) node = node->rb_right; else if (remote_ca_guid < timewait_info->remote_ca_guid) node = node->rb_left; else if (remote_ca_guid > timewait_info->remote_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){ struct rb_node **link = &cm.remote_qp_table.rb_node; struct rb_node *parent = NULL; struct cm_timewait_info *cur_timewait_info; __be64 remote_ca_guid = timewait_info->remote_ca_guid; __be32 remote_qpn = timewait_info->remote_qpn; while (*link) { parent = *link; cur_timewait_info = rb_entry(parent, struct cm_timewait_info, remote_qp_node); if (remote_qpn < cur_timewait_info->remote_qpn) link = &(*link)->rb_left; else if (remote_qpn > cur_timewait_info->remote_qpn) link = &(*link)->rb_right; else if (remote_ca_guid < cur_timewait_info->remote_ca_guid) link = &(*link)->rb_left; else if (remote_ca_guid > cur_timewait_info->remote_ca_guid) link = &(*link)->rb_right; else return cur_timewait_info; } timewait_info->inserted_remote_qp = 1; rb_link_node(&timewait_info->remote_qp_node, parent, link); rb_insert_color(&timewait_info->remote_qp_node, &cm.remote_qp_table); return NULL;}static struct cm_id_private * cm_insert_remote_sidr(struct cm_id_private *cm_id_priv){ struct rb_node **link = &cm.remote_sidr_table.rb_node; struct rb_node *parent = NULL; struct cm_id_private *cur_cm_id_priv; union ib_gid *port_gid = &cm_id_priv->av.dgid; __be32 remote_id = cm_id_priv->id.remote_id; while (*link) { parent = *link; cur_cm_id_priv = rb_entry(parent, struct cm_id_private, sidr_id_node); if (remote_id < cur_cm_id_priv->id.remote_id) link = &(*link)->rb_left; else if (remote_id > cur_cm_id_priv->id.remote_id) link = &(*link)->rb_right; else { int cmp; cmp = memcmp(port_gid, &cur_cm_id_priv->av.dgid, sizeof *port_gid); if (cmp < 0) link = &(*link)->rb_left; else if (cmp > 0) link = &(*link)->rb_right; else return cur_cm_id_priv; } } rb_link_node(&cm_id_priv->sidr_id_node, parent, link); rb_insert_color(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); return NULL;}static void cm_reject_sidr_req(struct cm_id_private *cm_id_priv, enum ib_cm_sidr_status status){ struct ib_cm_sidr_rep_param param; memset(¶m, 0, sizeof param); param.status = status; ib_send_cm_sidr_rep(&cm_id_priv->id, ¶m);}struct ib_cm_id *ib_create_cm_id(struct ib_device *device, ib_cm_handler cm_handler, void *context){ struct cm_id_private *cm_id_priv; int ret; cm_id_priv = kzalloc(sizeof *cm_id_priv, GFP_KERNEL); if (!cm_id_priv) return ERR_PTR(-ENOMEM); cm_id_priv->id.state = IB_CM_IDLE; cm_id_priv->id.device = device; cm_id_priv->id.cm_handler = cm_handler; cm_id_priv->id.context = context; cm_id_priv->id.remote_cm_qpn = 1; ret = cm_alloc_id(cm_id_priv); if (ret) goto error; spin_lock_init(&cm_id_priv->lock); init_waitqueue_head(&cm_id_priv->wait); INIT_LIST_HEAD(&cm_id_priv->work_list); atomic_set(&cm_id_priv->work_count, -1); atomic_set(&cm_id_priv->refcount, 1); return &cm_id_priv->id;error: kfree(cm_id_priv); return ERR_PTR(-ENOMEM);}EXPORT_SYMBOL(ib_create_cm_id);static struct cm_work * cm_dequeue_work(struct cm_id_private *cm_id_priv){ struct cm_work *work; if (list_empty(&cm_id_priv->work_list)) return NULL; work = list_entry(cm_id_priv->work_list.next, struct cm_work, list); list_del(&work->list); return work;}static void cm_free_work(struct cm_work *work){ if (work->mad_recv_wc) ib_free_recv_mad(work->mad_recv_wc); kfree(work);}static inline int cm_convert_to_ms(int iba_time){ /* approximate conversion to ms from 4.096us x 2^iba_time */ return 1 << max(iba_time - 8, 0);}static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info){ unsigned long flags; if (!timewait_info->inserted_remote_id && !timewait_info->inserted_remote_qp) return; spin_lock_irqsave(&cm.lock, flags); if (timewait_info->inserted_remote_id) { rb_erase(&timewait_info->remote_id_node, &cm.remote_id_table); timewait_info->inserted_remote_id = 0; } if (timewait_info->inserted_remote_qp) { rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table); timewait_info->inserted_remote_qp = 0; } spin_unlock_irqrestore(&cm.lock, flags);}static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id){ struct cm_timewait_info *timewait_info; timewait_info = kzalloc(sizeof *timewait_info, GFP_KERNEL); if (!timewait_info) return ERR_PTR(-ENOMEM); timewait_info->work.local_id = local_id; INIT_WORK(&timewait_info->work.work, cm_work_handler, &timewait_info->work); timewait_info->work.cm_event.event = IB_CM_TIMEWAIT_EXIT; return timewait_info;}static void cm_enter_timewait(struct cm_id_private *cm_id_priv){ int wait_time; /* * The cm_id could be destroyed by the user before we exit timewait. * To protect against this, we search for the cm_id after exiting * timewait before notifying the user that we've exited timewait. */ cm_id_priv->id.state = IB_CM_TIMEWAIT; wait_time = cm_convert_to_ms(cm_id_priv->local_ack_timeout); queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work, msecs_to_jiffies(wait_time)); cm_id_priv->timewait_info = NULL;}static void cm_reset_to_idle(struct cm_id_private *cm_id_priv){ cm_id_priv->id.state = IB_CM_IDLE; if (cm_id_priv->timewait_info) { cm_cleanup_timewait(cm_id_priv->timewait_info); kfree(cm_id_priv->timewait_info); cm_id_priv->timewait_info = NULL; }}void ib_destroy_cm_id(struct ib_cm_id *cm_id){ struct cm_id_private *cm_id_priv; struct cm_work *work; unsigned long flags; cm_id_priv = container_of(cm_id, struct cm_id_private, id);retest: spin_lock_irqsave(&cm_id_priv->lock, flags); switch (cm_id->state) { case IB_CM_LISTEN: cm_id->state = IB_CM_IDLE; spin_unlock_irqrestore(&cm_id_priv->lock, flags); spin_lock_irqsave(&cm.lock, flags); rb_erase(&cm_id_priv->service_node, &cm.listen_service_table); spin_unlock_irqrestore(&cm.lock, flags); break; case IB_CM_SIDR_REQ_SENT: cm_id->state = IB_CM_IDLE; ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); spin_unlock_irqrestore(&cm_id_priv->lock, flags); break; case IB_CM_SIDR_REQ_RCVD: spin_unlock_irqrestore(&cm_id_priv->lock, flags); cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT); break; case IB_CM_REQ_SENT: case IB_CM_MRA_REQ_RCVD: case IB_CM_REP_SENT: case IB_CM_MRA_REP_RCVD: ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); /* Fall through */ case IB_CM_REQ_RCVD: case IB_CM_MRA_REQ_SENT: case IB_CM_REP_RCVD: case IB_CM_MRA_REP_SENT: spin_unlock_irqrestore(&cm_id_priv->lock, flags); ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT, &cm_id_priv->av.port->cm_dev->ca_guid, sizeof cm_id_priv->av.port->cm_dev->ca_guid, NULL, 0); break; case IB_CM_ESTABLISHED: spin_unlock_irqrestore(&cm_id_priv->lock, flags); ib_send_cm_dreq(cm_id, NULL, 0); goto retest; case IB_CM_DREQ_SENT: ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); cm_enter_timewait(cm_id_priv); spin_unlock_irqrestore(&cm_id_priv->lock, flags); break; case IB_CM_DREQ_RCVD: spin_unlock_irqrestore(&cm_id_priv->lock, flags); ib_send_cm_drep(cm_id, NULL, 0); break; default: spin_unlock_irqrestore(&cm_id_priv->lock, flags); break; } cm_free_id(cm_id->local_id); atomic_dec(&cm_id_priv->refcount); wait_event(cm_id_priv->wait, !atomic_read(&cm_id_priv->refcount)); while ((work = cm_dequeue_work(cm_id_priv)) != NULL) cm_free_work(work); if (cm_id_priv->private_data && cm_id_priv->private_data_len) kfree(cm_id_priv->private_data); kfree(cm_id_priv);}EXPORT_SYMBOL(ib_destroy_cm_id);int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask){ struct cm_id_private *cm_id_priv, *cur_cm_id_priv; unsigned long flags; int ret = 0; service_mask = service_mask ? service_mask : __constant_cpu_to_be64(~0ULL); service_id &= service_mask; if ((service_id & IB_SERVICE_ID_AGN_MASK) == IB_CM_ASSIGN_SERVICE_ID && (service_id != IB_CM_ASSIGN_SERVICE_ID)) return -EINVAL; cm_id_priv = container_of(cm_id, struct cm_id_private, id); BUG_ON(cm_id->state != IB_CM_IDLE); cm_id->state = IB_CM_LISTEN; spin_lock_irqsave(&cm.lock, flags); if (service_id == IB_CM_ASSIGN_SERVICE_ID) { cm_id->service_id = cpu_to_be64(cm.listen_service_id++); cm_id->service_mask = __constant_cpu_to_be64(~0ULL); } else { cm_id->service_id = service_id; cm_id->service_mask = service_mask; } cur_cm_id_priv = cm_insert_listen(cm_id_priv); spin_unlock_irqrestore(&cm.lock, flags); if (cur_cm_id_priv) { cm_id->state = IB_CM_IDLE; ret = -EBUSY; } return ret;}EXPORT_SYMBOL(ib_cm_listen);static __be64 cm_form_tid(struct cm_id_private *cm_id_priv, enum cm_msg_sequence msg_seq){ u64 hi_tid, low_tid; hi_tid = ((u64) cm_id_priv->av.port->mad_agent->hi_tid) << 32; low_tid = (u64) ((__force u32)cm_id_priv->id.local_id | (msg_seq << 30)); return cpu_to_be64(hi_tid | low_tid);}static void cm_format_mad_hdr(struct ib_mad_hdr *hdr, __be16 attr_id, __be64 tid){ hdr->base_version = IB_MGMT_BASE_VERSION; hdr->mgmt_class = IB_MGMT_CLASS_CM; hdr->class_version = IB_CM_CLASS_VERSION; hdr->method = IB_MGMT_METHOD_SEND; hdr->attr_id = attr_id; hdr->tid = tid;}static void cm_format_req(struct cm_req_msg *req_msg, struct cm_id_private *cm_id_priv, struct ib_cm_req_param *param){ cm_format_mad_hdr(&req_msg->hdr, CM_REQ_ATTR_ID, cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_REQ)); req_msg->local_comm_id = cm_id_priv->id.local_id; req_msg->service_id = param->service_id; req_msg->local_ca_guid = cm_id_priv->av.port->cm_dev->ca_guid; cm_req_set_local_qpn(req_msg, cpu_to_be32(param->qp_num)); cm_req_set_resp_res(req_msg, param->responder_resources); cm_req_set_init_depth(req_msg, param->initiator_depth); cm_req_set_remote_resp_timeout(req_msg, param->remote_cm_response_timeout); cm_req_set_qp_type(req_msg, param->qp_type); cm_req_set_flow_ctrl(req_msg, param->flow_control); cm_req_set_starting_psn(req_msg, cpu_to_be32(param->starting_psn)); cm_req_set_local_resp_timeout(req_msg, param->local_cm_response_timeout); cm_req_set_retry_count(req_msg, param->retry_count); req_msg->pkey = param->primary_path->pkey; cm_req_set_path_mtu(req_msg, param->primary_path->mtu); cm_req_set_rnr_retry_count(req_msg, param->rnr_retry_count); cm_req_set_max_cm_retries(req_msg, param->max_cm_retries); cm_req_set_srq(req_msg, param->srq); req_msg->primary_local_lid = param->primary_path->slid; req_msg->primary_remote_lid = param->primary_path->dlid; req_msg->primary_local_gid = param->primary_path->sgid; req_msg->primary_remote_gid = param->primary_path->dgid; cm_req_set_primary_flow_label(req_msg, param->primary_path->flow_label); cm_req_set_primary_packet_rate(req_msg, param->primary_path->rate); req_msg->primary_traffic_class = param->primary_path->traffic_class; req_msg->primary_hop_limit = param->primary_path->hop_limit; cm_req_set_primary_sl(req_msg, param->primary_path->sl); cm_req_set_primary_subnet_local(req_msg, 1); /* local only... */ cm_req_set_primary_local_ack_timeout(req_msg, min(31, param->primary_path->packet_life_time + 1)); if (param->alternate_path) { req_msg->alt_local_lid = param->alternate_path->slid; req_msg->alt_remote_lid = param->alternate_path->dlid; req_msg->alt_local_gid = param->alternate_path->sgid; req_msg->alt_remote_gid = param->alternate_path->dgid; cm_req_set_alt_flow_label(req_msg, param->alternate_path->flow_label); cm_req_set_alt_packet_rate(req_msg, param->alternate_path->rate); req_msg->alt_traffic_class = param->alternate_path->traffic_class; req_msg->alt_hop_limit = param->alternate_path->hop_limit; cm_req_set_alt_sl(req_msg, param->alternate_path->sl); cm_req_set_alt_subnet_local(req_msg, 1); /* local only... */ cm_req_set_alt_local_ack_timeout(req_msg, min(31, param->alternate_path->packet_life_time + 1)); } if (param->private_data && param->private_data_len) memcpy(req_msg->private_data, param->private_data, param->private_data_len);}static inline int cm_validate_req_param(struct ib_cm_req_param *param){ /* peer-to-peer not supported */ if (param->peer_to_peer) return -EINVAL; if (!param->primary_path) return -EINVAL; if (param->qp_type != IB_QPT_RC && param->qp_type != IB_QPT_UC) return -EINVAL; if (param->private_data && param->private_data_len > IB_CM_REQ_PRIVATE_DATA_SIZE) return -EINVAL; if (param->alternate_path && (param->alternate_path->pkey != param->primary_path->pkey || param->alternate_path->mtu != param->primary_path->mtu)) return -EINVAL; return 0;}int ib_send_cm_req(struct ib_cm_id *cm_id, struct ib_cm_req_param *param){ struct cm_id_private *cm_id_priv; struct cm_req_msg *req_msg; unsigned long flags; int ret; ret = cm_validate_req_param(param); if (ret) return ret; /* Verify that we're not in timewait. */ cm_id_priv = container_of(cm_id, struct cm_id_private, id); spin_lock_irqsave(&cm_id_priv->lock, flags); if (cm_id->state != IB_CM_IDLE) { spin_unlock_irqrestore(&cm_id_priv->lock, flags); ret = -EINVAL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -