天天看點

【vbers】ibv_post_send|IBV_SEND_SOLICITED|RDMA

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 

【vbers】ibv_post_send|IBV_SEND_SOLICITED|RDMA

 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)&amp;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 &amp;(qp-&gt;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時,可能會誤判&amp;(qp-&gt;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

原文: