DPDK與SPDK(三)DPDK技術(shù)原理簡介

DPDK?是intel 基于其自家?x86 芯片上開發(fā)的一系列的用于快速包處理的驅(qū)?動(dòng)及相關(guān)基礎(chǔ)庫。DPDK?大部分跑在linux?用戶態(tài)(除?UIO?接口部分會(huì)跑在內(nèi)核態(tài)),目前?DPDK 以?BSD license?對外分發(fā),它包括以下幾個(gè)主要的組件:

. multicore framework:多核框架,?dpdk?庫面向?intel?i3/i5/i7/ep?等?多核架構(gòu)芯片,內(nèi)置了對多核的支持

. hugepage?memory: 內(nèi)存管理,dpdk?庫基于?linux?hugepage?實(shí)現(xiàn)了一套?內(nèi)存管理基礎(chǔ)庫,為應(yīng)用層包處理做了很多優(yōu)化

. ring?buffers:共享隊(duì)列,dpdk?庫提供的無鎖多生產(chǎn)者-多消費(fèi)者隊(duì)列,?是應(yīng)用層包處理程序的基礎(chǔ)組件

. poll-mode drivers:輪詢驅(qū)動(dòng),?dpdk 庫基于 linux uio 實(shí)現(xiàn)的用戶?態(tài)網(wǎng)卡驅(qū)動(dòng)

這些庫被用于:

. 在最小的?CPU cycles 內(nèi)發(fā)送或是接收數(shù)據(jù)包(通常小于?80?個(gè)?cycles,?DDIO?功能實(shí)現(xiàn))

. 開發(fā)快速的報(bào)文捕獲算法(如?tcpdump?之類的)

.?用于加速第三方的協(xié)議棧

典型的?DPDK?組件如下圖所示:


上圖中?DPDK?Libraries?及?Environment?Abstraction?Layer?均為?DPDK?提供,其中?EAL?模塊必須是最先初始化的代碼,?同一系統(tǒng)下只有一個(gè)?EAL?進(jìn)程為主進(jìn)程,?其它的均為?slave?進(jìn)程。內(nèi)核態(tài)?EAL?為一驅(qū)動(dòng),需要事先加載。這部分詳見后文

描述。下面分別對?DPDK?的各個(gè)組件進(jìn)行簡單的介紹。


環(huán)境抽象層概述

環(huán)境抽象層(Environment?Abstraction?Layer)提供了一層通用的接口給?DPDK?的各種庫使用,?同時(shí)屏蔽了硬件的各種形態(tài)帶來的差異化,它提供了以下服務(wù):

. DPDK?的加載及各個(gè)?core 間的分發(fā)

.?CPU CORE?的親和設(shè)置

.?系統(tǒng)內(nèi)存的申請及描述

.?原子操作及鎖操作

.?時(shí)間參考源

.?PCI?總線訪問

.?Trace?及?debug?功能


核心組件分析


從上圖中可以看出,?DPDK?所有的核心組件均基于?EAL,通過?EAL?提供的相關(guān)?功能,?DPDK?提供了?timer,malloc,mempool,mbuf,ring,debug?等核心功能,?另外上圖中沒有畫出的功能還有?FLOW classification?功能,此功能在當(dāng)前?DPDK(1.7.0)版本中暫未提供,后續(xù)版本中會(huì)實(shí)現(xiàn);另外關(guān)于?POLL-MODE driver ?在上圖中也沒有描述,?在接下來的文檔中,?會(huì)有詳細(xì)的描述。上圖中的核心組件

分別簡要描述如下:

.?內(nèi)存管理(librte_malloc):提供?API?從堆中申請內(nèi)存

. Ring?管理(librte_ring):從特定大小的表中申請無鎖?FIFO。

. 內(nèi)存池管理(librte_mempool):從內(nèi)存中申請對象池,每個(gè)內(nèi)存池由

name?及一個(gè)?ring?組成??商峁┗?core?的對象?cache?及對齊,能夠保?證對象在所有的?RAM?通道的一致性。

. 網(wǎng)絡(luò)報(bào)文緩沖管理(librte_mbuf):提供基于?DPDK?的應(yīng)用存儲(chǔ)消息所需?的?buffer?的創(chuàng)建及銷毀,?所有的?mbuf?都存儲(chǔ)在內(nèi)存池中,使用?DPDK ?的內(nèi)存池管理(librte_mempool)。

. 定時(shí)器管理(librte_timer):向?DPDK?的應(yīng)用提供定時(shí)器服務(wù)用于執(zhí)行異?步功能,它使用?EAL?模塊提供的?HPET?接口來獲取精確的時(shí)間參考源。

DPDK?的?C?運(yùn)行庫選用的是?newlib,一個(gè)是基于?license?的考慮,newlib?使用的是?BSD 的?license,另外就是在嵌入式的系統(tǒng)里面,?newlibc?也能夠有比較?優(yōu)秀的表現(xiàn),可方便基于?DPDK?的?APP?的移植。Newlib?的所有庫函數(shù)都建立在?20?個(gè)樁函數(shù)的基礎(chǔ)上,這?20?個(gè)樁函數(shù)完成一些?newlib?無法實(shí)現(xiàn)的功能:

1)?I/O?和文件系統(tǒng)訪問(open、close、read、write、lseek、stat、fstat、?fcntl、link、unlink、rename);

2) 擴(kuò)大內(nèi)存堆的需求(sbrk);

3) 獲得當(dāng)前系統(tǒng)的日期和時(shí)間(gettimeofday、times);

4) 各種類型的任務(wù)管理函數(shù)(execve、fork、getpid、kill、wait、_exit);


這?20?個(gè)樁函數(shù)在語義、語法上與?POSIX?標(biāo)準(zhǔn)下對應(yīng)的?20?個(gè)同名系統(tǒng)調(diào)用是?完全兼容的。?Newlib?為每個(gè)樁函數(shù)提供了可重入的和不可重入的兩種版本。兩種版本的區(qū)別在于,?如果不可重入版樁函數(shù)的名字是?xxx,則對應(yīng)的可重入版樁?函數(shù)的名字是_xxx_r,如?close?和_close_r,open?和_open_r,等等。此外,?可?重入的樁函數(shù)在參數(shù)表中含有一個(gè)_reent?結(jié)構(gòu)指針,這個(gè)指針使得系統(tǒng)的實(shí)現(xiàn)者能在庫和目標(biāo)操作環(huán)境之間傳送上下文相關(guān)的信息,尤其是發(fā)生錯(cuò)誤時(shí),?能夠?便捷的傳送?errno?的值到適當(dāng)?shù)娜蝿?wù)中。?DPDK 內(nèi)使用的大多數(shù)是可重入版本的樁函數(shù)。

DPDK環(huán)境抽象層

環(huán)境抽象層用于?APP?訪問底層資源,?如硬件、內(nèi)存等。它提供了一種通用的?接口來屏蔽底層硬件或是庫定義的接口,用于初始化運(yùn)行環(huán)境(內(nèi)存空間、?PCI設(shè)備、定時(shí)器、控制臺等)。

典型的?EAL?層提供的服務(wù)包括:

. DPDK?的加載與運(yùn)行:?intel DPDK?必須與應(yīng)用程序一起鏈接成一個(gè)?APP,?并且必須以某種方式來進(jìn)行加載并運(yùn)行。

. 核的親和設(shè)置及工作分配:?EAL?提供一種機(jī)制將特定的執(zhí)行單元分配到?不同的?core?運(yùn)行。

. 系統(tǒng)內(nèi)存預(yù)留:?EAL?預(yù)留不同的內(nèi)存區(qū)域供使用,如預(yù)留物理內(nèi)存給設(shè)?備交互使用。

. PCI?地址抽象:?EAL?提供接口去訪問?PCI?設(shè)備的地址空間。

. 公用接口:提供?libc?里沒有的?spinlock?及原子操作

本章節(jié)僅主要介紹?EAL?實(shí)現(xiàn)的功能,?其中會(huì)涉及到多個(gè)庫的實(shí)現(xiàn),?關(guān)于這些庫的詳細(xì)實(shí)現(xiàn),請見后面原理分析章節(jié),本章節(jié)只做簡要描述。


LIBC與EAL的區(qū)別

從前面的描述中,我們可以看出?libc?實(shí)際上也完也了?EAL?提供的相關(guān)接口,?關(guān)于它們之間的區(qū)別實(shí)際上是很,對于一個(gè)應(yīng)用程序來說,使用?EAL+LIBC?基本上就可以使用任何應(yīng)用程序或是庫的接口了:

C?標(biāo)準(zhǔn)庫基本上提供了通用的操作,?如輸入/輸出、字符處理、類型以及?ISOC?標(biāo)準(zhǔn)里面定義的功能。

而?EAL?是?DPDK?特定使用的,提供了一系列訪問特定硬件或是在用戶態(tài)訪問內(nèi)核的接口供?APP?使用。

在實(shí)際的應(yīng)用編寫過程中,?可以靈活的使用這兩種方式,?下圖是一個(gè)典型的混合用?libc+EAL?的程序框架。





EAL加載過程

在?linux?用戶態(tài)的運(yùn)行環(huán)境,DPDP?所有的實(shí)例都使用?pthread?庫來運(yùn)行,PCI設(shè)備所有的信息及地址空間的發(fā)布是通過內(nèi)核提供的/sys 下面的文件接口來實(shí)?現(xiàn)的。同時(shí)?EAL?使用?hugetlbfs?來保留一段內(nèi)存,然后通過?mmap?的方式來使用?這些物理內(nèi)存,并且使用了?huge page 來提高性能,?mmap 出來的內(nèi)存會(huì)暴露給?DPDK?的?mempool?使用。DPDK?被初始化后,會(huì)通過?pthread?的調(diào)用將特定的執(zhí)行單元綁定到邏輯?core?上去作為用戶態(tài)的線程運(yùn)行。

下圖是?linux?用戶態(tài)模式下基于DPDK?的APP?初始化及?core?任務(wù)分發(fā)的過程:






在?APP 運(yùn)行的時(shí)候,?首先調(diào)的是?main 函數(shù),這個(gè)是 glibc 調(diào)用,然后在main?函數(shù)內(nèi)部會(huì)去調(diào)用?ret_eal_init,這個(gè)函數(shù)是?DPDK?環(huán)境建立起來的初始化函數(shù),?會(huì)進(jìn)行?core?的初始化及任務(wù)分發(fā)操作、內(nèi)存初始化、LOG?初始化、PCI?設(shè)備初始?化等操作,這些和硬件強(qiáng)相關(guān)的操作完成后,就會(huì)根據(jù)?core 的數(shù)量及配置文件?進(jìn)行線程的創(chuàng)建及線程的綁定,?然后緊接著進(jìn)行其它庫及驅(qū)動(dòng)的初始化,所有初?始化完成后,就會(huì)將最小的執(zhí)行單元通過?rte_eal_remote_lanch?分發(fā)到不同的core?上去執(zhí)行。


需要注意的是,?在PCI?訪問的時(shí)候,?EAL?是使用的/sys(具體點(diǎn)就是?/sys/bus/pci 及/sys/bus/pci_express)下面的文件去掃描總線上的?PCI 設(shè)備,而訪問?PCI?設(shè)備的內(nèi)存則是通過?UIO?或是?libpciaccess?來實(shí)現(xiàn)的。

注:?DPDK 也可以用在裸環(huán)境下面,即沒有任何操作系統(tǒng)的環(huán)境,在這種環(huán)境下?需要將?DPDK?的鏡象通過?GRUB?來進(jìn)行引導(dǎo)。由于我們沒有使用這個(gè)功能,本文暫不介紹。

內(nèi)存分片介紹

由于與硬件交互時(shí)必須要使用連續(xù)的物理內(nèi)存,而DPDK的內(nèi)存申請是依賴?OS?的機(jī)制的(如?huge?page),OS?并沒有辦法保證所有申請的物理內(nèi)存的地址是?連續(xù)的(因?yàn)橛锌斩创嬖冢?,所以申請的?nèi)存是以在一個(gè)表中的多個(gè)描述符的形?式進(jìn)行分片組織起來的,?每一個(gè)分片描述符(rte_memseg)表示了一部分物理內(nèi)?存、虛擬地址都連續(xù),并且都在同一個(gè)socket,pagesize 也相同的 hugepage頁面的集合,這樣做的好處就是優(yōu)化內(nèi)存。而memzone 是通過 rte_memzone_reserve 來從 rte_memseg?中分配那些基?dpdk?hugepage?的屬于同一個(gè)物理?cpu?的物理內(nèi)存連續(xù)的虛擬內(nèi)存也連續(xù)的一塊?地址。Memzone?是?DPDK 內(nèi)存管理最終向用戶程序提供的基礎(chǔ)接口,?ret_mempool內(nèi)的組件均依于?rte_memzone?來實(shí)現(xiàn)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容