API 查询网址:
https://docs.oracle.com/cd/E88353_01/html/E37842/ibv-modify-qp-3.html
https://www.rdmamojo.com/2013/01/26/ibv_post_send/
ibv_post_send()
函数原型为
在ibv_send_wr 结构体中opcode参数决定了数据传输类型,比如说:
IBV_WR_SEND——这种传输方式,当前buffer内存中在sg_list中的内容会被发送给远方的QP。发送方并不会知道数据会写到远方节点的何处(接收方决定)。接收方要post_recv,并且接收到的数据要放到指定的地址中。
IBV_WR_RDMA_WRITE——这种传输方式,本地内存buffer中sg_list中的内容会被发送和写到远方节点的QP的虚拟空间中的一段连续内存块中——这并不意味着远方的内存在物理上也是连续的。并且remote QP也不需要post_recv。 (真正的RDMA,对方cpu不参与,本端直接用最开始握手时得到的addr和key 操作对端的内存。)
ibv_send_flags send_flags
描述WR的属性。它是0或以下一个或多个标志的按位“或”:
IBV_SEND_FENCE -设置此WR的围栅指示符。这意味着该WR的处理将被阻塞,直到所有先前发布的RDMA读取和原子WR完成。仅对Transport Service Type为IBV_QPT_RC的QP有效。
IBV_SEND_SIGNALED -设置此WR的完成通知指示符。这意味着,如果QP是使用sq_sig_all = 0创建的,则当此WR的处理结束时,将生成WC。如果QP是使用sq_sig_all = 1创建的,则此标志不会有任何影响。
IBV_SEND_SOLICITED-设置此WR的'请求事件'(solicited event)指示器。这意味着当此WR中的消息在远程QP中将完结时,将为其创建一个'请求的事件'(solicited event),如果在远程端用户正在等待一个'请求的事件'(solicited event),则它将被唤醒。仅与带有立即操作码的发送和RDMA写操作有关。
IBV_SEND_INLINE -sg_list中指定的内存缓冲区将内联放置在SR中。这意味着底层驱动程序(即CPU)将读取数据,而不是RDMA设备。这意味着将不会检查L_Key,实际上那些内存缓冲区甚至不必注册(毕竟CPU本来是老大/主子),并且可以在ibv_post_send()将要结束后,立即重用它们。仅对Send和RDMA write操作码有效。
由于在该代码中没有涉及到key的交换,所以也无法使用RDMA传输,所以还是使用了CPU读取数据,既然是CPU读取,那么也就不需要注册内存缓冲区了,这个标记只能用于发送和写操作。
ibv_sge
struct ibv_sge describes a scatter/gather entry. The memory buffer that this entry describes must be registered until any posted Work Request that uses it isn't considered outstanding anymore. The order in which the RDMA device access the memory in a scatter/gather list isn't defined. This means that if some of the entries overlap the same memory address, the content of this address is undefined.
<col>
Here is the full description of struct ibv_sge:
addr
The address of the buffer to read from or write to
length
The length of the buffer in bytes. The value 0 is a special value and is equal to

bytes (and not zero bytes, as one might imagine)
lkey
The Local key of the Memory Region that this memory buffer was registered with
Sending inline'd data is an implementation extension that isn't defined in any RDMA specification: it allows send the data itself in the Work Request (instead the scatter/gather entries) that is posted to the RDMA device.The memory that holds this message doesn't have to be registered.
发送inline'd data是一个在任何一个RDMA规范中都没有定义的实现扩展 :inline'd 允许 在WR(而不是 scatter/gather )上的数据Post到 RDMA 驱动上,存储这个message的内存不需要注册。
There isn't any verb that specifies the maximum message size that can be sent inline'd in a QP.Some of the RDMA devices support it.In some RDMA devices, creating a QP with will set the value of max_inline_data to the size of messages that can be sent using the requested number of scatter/gather elements of the Send Queue.
verb没有规范QP的最大可以inline多大的message,有一些RDMA驱动支持它,在某些RDMA设备中,创建QP会将max_inline_data的值设置为 可以使用请求的Send Queue的 scatter/gather的元素的数量发送的消息的大小。
If others, one should specify explicitly the message size to be sent inline before the creation of a QP. for those devices, it is advised to try to create the QP with the required message size and continue to decrease it if the QP creation fails.
如果是其他版本,则应在创建QP之前明确指定要内联发送的消息大小。对于这些设备,建议尝试创建具有所需消息大小的QP,如果QP创建失败,则继续减小它。
While a WR is considered outstanding:
尽管WR被认为是出色的:
If the WR sends data, the local memory buffers content shouldn't be changed since one doesn't know when the RDMA device will stop reading from it (one exception is inline data)
If the WR reads data, the local memory buffers content shouldn't be read since one doesn't know when the RDMA device will stop writing new content to it
如果WR发送数据,则不应更改本地内存缓冲区的内容,因为不知道RDMA设备何时停止从中读取内容(inline data方式是例外)
如果WR读取数据,则不应读取本地内存缓冲区中的内容,因为不知道RDMA设备何时会停止向其中写入新内容
============================
ibv_post_send() work queue overflow问题
发生这个问题是因为发送的时候, send队列里面没有地方, 一个原因是发送的太频繁, 另外一个原因就是发送的WC(work complete)没处理.
设计了一个简单场景 发送用inline, 根据文档, inline发送不需要等待wc就可以重用发送buffer.
实测发现, 每次发送到一定数量就停止, errno: 12 (ENOMEM) - Cannot allocate memory. 这个数量就是qp初始化时候的req_num:
很多人在问这个鬼问题, 大家都以为inline发送就不需要wc, 实际不然, inline只是把数据copy到wr(work request)一起给硬件, 网卡不用再次dma. 如果没有wc, 硬件处理完队列中的数据, 发送队列中的首位指针没有更新, 所以verbs驱动以为硬件还在操作, 所以没空间继续发送.
建议是虽然发送inline, 还是要隔三差五去polling一下cq, 这样队列指针就更新了.
所以inline这个鸟功能只是减少了去响应wc的频率, 不能根除.
那么我的sq和rq共用一个cq, rq我是经常轮训的? 从测试结果看不行.
在qp初始化的时候加入: .sq_sigall = 1,
或者发送send_wr没隔一定数量指定flag: IBV_SEND_SIGNALED...
在处理inline wc的时候如果op_code是IBV_WC_SEND, 忽略.
CQE's wr_id could be:
1)BEACON_WRID
2)&RDMAConnectedSocketImpl::qp
3)Chunks address start from Cluster::chunk_base
When assuming qp as Chunk through CQE's wr_id, it's possible to misjudge &(qp->ib_physical_port) into Cluster::[base, end) because there're 4 bytes random data filled in the higher 4 bytes address around ib_pysical_port due to the address alignement requirement of structure member.
CQE 的 wr_id 可以是:
3)从 Cluster::chunk_base 开始的Chunk 地址
当通过CQE的wr_id假设qp为Chunk时,可能会误判&(qp->ib_physical_port) 进入 Cluster::[base, end) 因为由于结构成员的地址对齐要求,有 4 个字节的随机数据填入ib_pysical_port 周围的高 4 字节地址中
通过检查 wr_id 值是否在分配的块空间中来解决这种情况。
解决:https://tracker.ceph.com/issues/44346
https://github.com/ceph/ceph/pull/36908
==========================================
5、为什么要设置IBV_SEND_INLINE?
int send_flags,描述了WR的属性,其值为0或者一个或多个flags的按位异或。
IBV_SEND_FENCE - 为此WR设置围栏指示器。这意味着这个WR的处理将被阻止,直到所有之前发布的RDMA Read和Atomic WR都将被完成。仅对运输服务类型为IBV_QPT_RC的QP有效
IBV_SEND_SIGNALED - 设置此WR的完成通知指示符。这意味着如果QP是使用sq_sig_all = 0创建的,那么当WR的处理结束时,将会产生一个工作完成。如果QP是使用sq_sig_all = 1创建的,则不会对此标志产生任何影响
IBV_SEND_SOLICITED - 为此WR设置请求事件指示器。这意味着,当这个WR中的消息将在远程QP中结束时,将会创建一个请求事件,如果在远程侧,用户正在等待请求事件,它将被唤醒。与仅用于发送和RDMA写入的立即操作码相关
IBV_SEND_INLINE - sg_list中指定的内存缓冲区将内联放置在发送请求中。这意味着低级驱动程序(即CPU)将读取数据而不是RDMA设备。这意味着L_Key将不会被检查,实际上这些内存缓冲区甚至不需要被注册,并且在ibv_post_send()结束之后可以立即重用。仅对发送和RDMA写操作码有效。由于在该代码中没有涉及到key的交换,所以也无法使用RDMA传输,所以还是使用了CPU读取数据,既然是CPU读取,那么也就不需要注册内存缓冲区了,这个标记只能用于发送和写操作。
6、操作码和对应的QP传输服务类型的关系?
7、libibverbs和librdmacm的区别?
在infiniband/verbs.h中,定义了ibv_post_send()和ibv_post_recv()操作,分别表示,将wr发布到SQ和RQ中,至于是什么操作,和wr中的opcode有关。对ibv_post_send()来说,对应的是struct ibv_send_wr,其中有opcode,表示操作码,有SEND/WRITE/READ等。对于ibv_post_recv()来说,对应的是struct ibv_recv_wr,没有操作码,因为只有接收一个动作,所以不需要定义其它的操作码。但是发送来说,有三类。
在rdma/rdma_verbs.h中,有rdma_post_send(),rdma_post_recv(),rdma_post_read(),rdma_post_write()。
rdma_post_send():把wr发布到QP的SQ中,需要mr
rdma_post_recv():把wr发布到QP的RQ中,需要mr
rdma_post_read():把wr发布到QP的SQ中,执行RDMA READ操作,需要远程地址和rkey,以及本地存储地址和长度,以及mr
rdma_post_write():把wr发布到QP的SQ中,RDMA WRITE操作,需要远程的被写入地址和rkey,以及本地要发送数据的地址和长度,以及mr
所以rdma/rdma_verbs.h中的四种通信函数其实和infiniband/verbs.h中的两种方法是一致的。ibv_post_send()对应rdma_post_send()、rdma_post_read()、rdma_post_write(),ibv_post_recv()对应rdma_post_recv()。
IBV_SEND_INLINE
The flag IBV_SEND_INLINE describe to the low level driver how the datawill be read from the memory buffer
(the driver will read the data and give it to the HCA or the HCA will fetch the data from the memory usingthe gather list).
标志IBV_SEND_INLINE向底层驱动程序描述 数据将以哪种方式从(应用程序的)内存缓冲区中读取(有两种方式):
(1、驱动程序将读取数据并将其提供给HCA 或者
2、HCA将使用 gather list 从内存中获取数据)
https://lists.openfabrics.org/pipermail/ewg/2008-April/006271.html
原文: