-
对于 Client 来讲,setupConnection 中的 cm_id 应该是本地的,意味着后续 create pd \ cq \ qp 等等传入的 cm_id 都是本地 id。但是对于 Server 来讲,收到 client 的链接请求时将 client 的 cm_id 传入 setupConnection,意味着后续 create pd \ cq \ qp 等等传入的 cm_id 都是远端 id。为什么?
-
因为所有的 create_xxx 操作都需要 ibv 的链接信息,资源是服务于链接的。
-
在 rdma_create_qp 的介绍中说到,传入的 cm_id 必须要拥有链接信息,否则会创建失败,这就是解释了为什么 Server 调用时不能传入自己的 local_cm_id,因为此时 Server 的 cm_id 是没有链接信息的,所以失败。
-
那么为什么 Client 可以传入自己的 local_cm_id 呢。因为在 Client 在 create_xxx 之间,首先进行了地址解析:
-
rdma_resolve_addr(client_id_, nullptr, dst_addr_->ai_addr, DEFAULT_CONNECTION_TIMEOUT); rdma_resolve_route(client_id_, DEFAULT_CONNECTION_TIMEOUT);
-
这些操作会将 Client <-> Server 的一些链接信息存入 cm_id , 比如 addr、route 什么的,之后 cm_id 就具有了链接信息,可以通过其创建资源。
-
同理,Server 拿到 Client 的 cm_id 后要用它来创建资源
-
附上一张官方的 cm 建链流程:
-
-
ibv_destroy_cq 和 rdma_destroy_id 会卡住,有什么头绪吗?
-
ibv 博客里这么解释:
-
There is at least one affiliated asynchronous event on that CQ that was read without a proper acknowledgement.
-
意思是还有 event 没有发 ack。最后 debug 确实是这样,Server 收到 DISCONNECT 时,没有 ack 就调用了 ibv_destroy_cp ,然后就一直卡住。
-
去看了下源码,发现 ibv_destroy_cp 一直往后调用有这么一句话:
-
int ibv_cmd_destroy_cq(struct ibv_cq *cq) { // ... while (cq->comp_events_completed != resp.comp_events_reported || cq->async_events_completed != resp.async_events_reported) // ... }
-
cq 里其实是有一个 event channel 的:
-
struct ibv_cq { struct ibv_comp_channel *channel; }
-
说白了应该就是要等所有的 event 全部完毕才能 destroy,否则卡住。
-
-
cm_id 是对应节点还是对应 qp ?
- 应该是对应 qp
-
Client rdma_disconnect 之后,rdma_get_cm_event 堵住了。按理说是不应该的,因为当任意一端启动 rdma_disconnect 后,会在两端均产生 RDMA_CM_EVENT_DISCONNECTED 事件。
-
官方解释是这么说的:
-
After successfully disconnecting, an RDMA_CM_EVENT_DISCONNECTED event will be generated on both sides of the connection.
-
意思是成功 disconnect 之后才会在双端产生事件。首先,当 Client 调用 rdma_disconnect 后,Server 会立刻产生该事件,但是 Client 不会,只有当 disconnect “完成” 之后,才会产生事件。那么问题就在于这个 “完成” 指什么。
-
经过多次尝试,发现这个 “完成” 是指 Server 端释放所有 Connection 资源,也就是 ibv_destroy_xxx。因此该 bug 产生的原因是 Server 收到 Client 的 disconnect 请求后没有即使释放资源,导致 Client 一直收不到事件。
-