9. RDMA之Queue Pair

本文轉自知乎“Savir“賬號

Queue Pair

我們曾經在3。 RDMA基本元素一文中簡單的介紹了QP的概念,本文將更深入的講解一些關於QP的細節。

基本概念回顧

首先我們來簡單回顧下關於QP的基礎知識:

根據IB協議中的描述,QP是硬體和軟體之間的一個虛擬介面。QP是佇列結構,按順序儲存著軟體給硬體下發的任務(WQE),WQE中包含從哪裡取出多長的資料,並且傳送給哪個目的地等等資訊。

9. RDMA之Queue Pair

QP的概念

每個QP間都是獨立的,彼此透過PD隔離,因此一個QP可以被視為某個使用者獨佔的一種資源,一個使用者也可以同時使用多個QP。

QP有很多種服務型別,包括RC、UD、RD和UC等,所有的源QP和目的QP必須為同一種類型才能進行資料互動。

雖然IB協議將QP稱為“虛擬介面”,但是它是有實體的:

硬體上,QP是一段包含著若干個WQE的儲存空間,IB網絡卡會從這段空間中讀取WQE的內容,並按照使用者的期望去記憶體中存取資料。至於這個儲存空間是記憶體空間還是IB網絡卡的片記憶體儲空間,IB協議並未做出限制,每個廠商有各自的實現

軟體上,QP是一個由IB網絡卡的驅動程式所維護的資料結構,其中包含QP的地址指標以及一些相關的軟體屬性。

QPC

5。 RDMA基本服務型別一文中,我們曾經提到過QPC全稱是Queue Pair Context,用於儲存QP相關屬性。驅動程式裡面是有儲存QP的軟體屬性的,既然我們可以在軟體裡儲存QP的屬性,為什麼還要用使用QPC呢?

這是因為

QPC主要是給硬體看的,也會用來在軟硬體之間同步QP的資訊

我們說過QP在硬體上的實體只是一段儲存空間而已,硬體除了知道這段空間的起始地址和大小之外一無所知,甚至連這個QP服務型別都不知道。還有很多其他的重要資訊,比如某個QP中包含了若干個WQE,硬體怎麼知道有多少個,當前應該處理第幾個呢?

所有上述的這些資訊,軟體是可以設計一定的資料結構併為其申請記憶體空間的,但是軟體看到的都是虛擬地址,這些記憶體空間在物理上是離散的,硬體並不知道這些資料存放到了哪裡。所以就需要軟體透過作業系統提前申請好一大片連續的空間,即QPC來承載這些資訊給硬體看。網絡卡及其配套的驅動程式提前約定好了QPC中都有哪些內容,這些內容分別佔據多少空間,按照什麼順序存放。這樣驅動和硬體就可以透過透過QPC這段空間來讀寫QP的狀態等等資訊。

9. RDMA之Queue Pair

QPC的概念

如上圖所示,硬體其實只需要知道QPC的地址0x12350000就可以了,因為它可以解析QPC的內容,從而得知QP的位置,QP序號,QP大小等等資訊。進而就能找到QP,知道應該取第幾個WQE去處理。不同的廠商可能實現有些差異,但是大致的原理就是這樣。

IB軟體棧中還有很多Context的概念,除了QPC之外,還有Device Context,SRQC,CQC,EQC(Event Queue Context,事件佇列上下文)等,它們的作用與QPC類似,都是用來在記錄和同步某種資源的相關屬性。

QP Number

簡稱為QPN,就是每個QP的編號。IB協議中規定用24個bit來表示QPN,即每個節點最大可以同時使用

個QP,這已經是一個很大的數量了,幾乎不可能用完。每個節點都各自維護著QPN的集合,相互之間是獨立的,即不同的節點上可以存在編號相同的QP。

QPN的概念本身非常簡單,但是有兩個特殊的保留編號需要額外注意一下:

QP0

編號為0的QP用於子網管理介面SMI(Subnet Management Interface),用於管理子網中的全部節點,說實話我也還沒搞清楚這個介面的作用,暫且按下不表。

QP1

編號為1的QP用於通用服務介面GSI(General Service Interface),GSI是一組管理服務,其中最出名的就是CM(Communication Management),是一種在通訊雙方節點正式建立連線之前用來交換必須資訊的一種方式。其細節將在後面的文章中專門展開介紹。

這也就是我們之前的文章畫的關於QP的圖中,沒有出現過QP0和QP1的原因了。這兩個QP之外的其他QP就都是普通QP了。使用者在建立QP的時候,驅動或者硬體會給這個新QP分配一個QPN,一般的QPN都是2、3、4這樣按順序分配的。當QP被銷燬之後,它的QPN也會被重新回收,並在合適的時候分配給其他新建立的QP。

使用者介面

我們從控制層面和資料層面來分類介紹使用者介面,控制面即使用者對某種資源進行某種設定,一般都是在正式收發資料之前進行;而資料面自然就是真正的資料收發過程中進行的操作。

控制面

接觸過演算法的讀者應該都瞭解,連結串列的節點涉及到“增、刪、改、查”四個操作,連結串列的節點是一片記憶體區域,是一種軟體資源。

“增”即向作業系統申請一片記憶體用來存放資料,系統將在記憶體中劃分一塊空間,並將其標記為“已被程序XX使用”,其他沒有許可權的程序將無法覆蓋甚至讀取這片記憶體空間。

“刪”即通知作業系統,這片空間我不使用了,可以標記成“未使用”並給其它程序使用了。

“改”就是寫,即修改這片記憶體區域的內容。

”查“就是讀,即獲取這片記憶體區域的內容。

QP作為RDMA技術中最重要的一種資源,在生命週期上與連結串列並無二致:

9. RDMA之Queue Pair

這四種操作,其實就是Verbs(RDMA對上層應用的API)在控制面上對上層使用者提供給使用者的幾個介面:

Create QP

建立一個QP的軟硬體資源,包含QP本身以及QPC。使用者建立時會寫傳入一系列的初始化屬性,包含該QP的服務型別,可以儲存的WQE數量等資訊

Destroy QP

釋放一個QP的全部軟硬體資源,包含QP本身及QPC。銷燬QP後,使用者將無法透過QPN索引到這個QP。

Modify QP

修改一個QP的某些屬性,比如QP的狀態,路徑的MTU等等。這個修改過程既包括軟體資料結構的修改,也包括對QPC的修改。

Query QP

查詢一個QP當前的狀態和一些屬性,查詢到的資料來源於驅動以及QPC的內容。

這四種操作都有配套的Verbs介面,類似於ibv_create_qp()這種形式,我們編寫APP時直接呼叫就可以了。更多關於對上層的API的細節,我們將在後面專門進行介紹。

資料面

資料面上,一個QP對上層的介面其實只有兩種,分別用於向QP中填寫傳送和接收請求。

這裡的“傳送”和“接收”並不是指的傳送和接收資料,而是指的是一次通訊過程的“發起方”(Requestor)和“接收方”(Responser)

在行為上都是軟體向QP中填寫一個WQE(對應用層來說叫WR),請求硬體執行一個動作。所以這兩種行為都叫做“Post XXX Request”的形式,即下發XXX請求。

Post Send Request

再強調一下,Post Send本身不是指這個WQE的操作型別是Send,而是表示這個WQE屬於通訊發起方。這個流程中填寫到QP中的WQE/WR可以是Send操作,RDMA Write操作以及RDMA Read操作等。

使用者需要提前準備好資料緩衝區、目的地址等資訊,然後呼叫介面將WR傳給驅動,驅動再把WQE填寫到QP中。

Post Receive Request

Post Recv的使用場景就相對比較少了,一般只在Send-Recv操作的接收端執行,接收端需要提前準備好接收資料的緩衝區,並將緩衝區地址等資訊以WQE的形式告知硬體。

QP狀態機

說到QP的狀態,就不得不祭出下面這張圖(取自IB協議10。3。1節):

9. RDMA之Queue Pair

QP的狀態機

所謂狀態機,就是描述一個物件的不同狀態,以及觸發狀態間跳轉的條件。為一個物件設計狀態機可以使這個物件的生命週期變得非常明確,實現上也會使得邏輯更加清晰。

對於QP來說,IB規範也為其設計了幾種狀態,處於不同狀態的QP的功能是有差異的,比如只有進入到Ready to Send狀態之後,QP才能夠進行Post Send資料操作。正常狀態(綠色的)之間的狀態轉換都是由使用者透過上文介紹的Modify QP的使用者介面來主動觸發的;而錯誤狀態(紅色的)往往是出錯之後自動跳轉的,當一個QP處於錯誤狀態之後就無法執行正常的業務了,就需要上層透過Modify QP將其重新配置到正常狀態上。

上圖中我們只關注QP的部分,EE(End-to-End Context)是專門給RD服務型別使用的一個概念,我們暫不涉及。我們透過Create QP介面來進入這個狀態圖,透過Destroy QP介面來離開這個狀態圖。

QP有以下幾種狀態,我們僅介紹一下比較重要的點:

RST(Reset)

復位狀態。當一個QP透過Create QP建立好之後就處於這個狀態,相關的資源都已經申請好了,但是這個QP目前什麼都做不了,其無法接收使用者下發的WQE,也無法接受對端某個QP的訊息。

INIT(Initialized)

已初始化狀態。這個狀態下,使用者可以透過Post Receive給這個QP下發Receive WR,但是接收到的訊息並不會被處理,會被靜默丟棄;如果使用者下發了一個Post Send的WR,則會報錯。

RTR(Ready to Receive)

準備接收狀態。在INIT狀態的基礎上,RQ可以正常工作,即對於接收到的訊息,可以按照其中WQE的指示搬移資料到指定記憶體位置。此狀態下SQ仍然不能工作。

RTS(Ready to Send)

準備傳送狀態。在RTR基礎上,SQ可以正常工作,即使用者可以進行Post Send,並且硬體也會根據SQ的內容將資料傳送出去。進入該狀態前,QP必須已於對端建立好連結。

SQD(Send Queue Drain)

SQ排空狀態。顧名思義,該狀態會將SQ佇列中現存的未處理的WQE全部處理掉,這個時候使用者還可以下發新的WQE下來,但是這些WQE要等到舊的WQE全處理之後才會被處理。

SQEr(Send Queue Error)

SQ錯誤狀態。當某個Send WR發生完成錯誤(即硬體透過CQE告知驅動發生的錯誤)時,會導致QP進入此狀態。

ERR(Error)

即錯誤狀態。其他狀態如果發生了錯誤,都可能進入該狀態。Error狀態時,QP會停止處理WQE,已經處理到一半的WQE也會停止。上層需要在修復錯誤後再將QP重新切換到RST的初始狀態。

總結

本文先回顧了QP的一些重要基本概念,然後講解了QPC、QPN等QP強相關的概念,最後介紹了使用者操作QP常用的介面以及QP狀態機,相信本文過後讀者一定對QP有了更深的瞭解。

其實作為RDMA的核心概念,QP的內容很多,本文難以全部囊括。我將在後面的文章中逐漸把相關的內容補全,比如QKey的概念將在後續專門介紹各種Key的文章中講解。

好了,本文就到這了,感謝閱讀。預告下一篇文章將詳細講解CQ。

協議相關章節

3。5。1 10。2。4 QP的基本概念

10。3 QP 狀態機

10。2。5 QP相關的軟體介面

11。4 Post Send Post Recv