DPDK?是intel 基于其自家?x86 芯片上開發(fā)的一系列的用于快速包處理的驅(qū)?動(dòng)及相關(guān)基礎(chǔ)庫晓淀。DPDK?大部分跑在linux?用戶態(tài)(除?UIO?接口部分會(huì)跑在內(nèi)核態(tài))都办,目前?DPDK 以?BSD license?對(duì)外分發(fā),它包括以下幾個(gè)主要的組件:
. multicore framework:多核框架,?dpdk?庫面向?intel?i3/i5/i7/ep?等?多核架構(gòu)芯片,內(nèi)置了對(duì)多核的支持
. 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)牛曹,需要事先加載佛点。這部分詳見后文
描述。下面分別對(duì)?DPDK?的各個(gè)組件進(jìn)行簡(jiǎn)單的介紹黎比。
環(huán)境抽象層概述
環(huán)境抽象層(Environment?Abstraction?Layer)提供了一層通用的接口給?DPDK?的各種庫使用超营,?同時(shí)屏蔽了硬件的各種形態(tài)帶來的差異化,它提供了以下服務(wù):
. DPDK?的加載及各個(gè)?core 間的分發(fā)
.?CPU CORE?的親和設(shè)置
.?系統(tǒng)內(nèi)存的申請(qǐng)及描述
.?原子操作及鎖操作
.?時(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ì)的描述瘪板。上圖中的核心組件
分別簡(jiǎn)要描述如下:
.?內(nèi)存管理(librte_malloc):提供?API?從堆中申請(qǐng)內(nèi)存
. Ring?管理(librte_ring):從特定大小的表中申請(qǐng)無鎖?FIFO吴趴。
. 內(nèi)存池管理(librte_mempool):從內(nèi)存中申請(qǐng)對(duì)象池,每個(gè)內(nèi)存池由
name?及一個(gè)?ring?組成侮攀÷嘀Γ可提供基于?core?的對(duì)象?cache?及對(duì)齊,能夠保?證對(duì)象在所有的?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)下對(duì)應(yīng)的?20?個(gè)同名系統(tǒng)調(diào)用是?完全兼容的辞色。?Newlib?為每個(gè)樁函數(shù)提供了可重入的和不可重入的兩種版本。兩種版本的區(qū)別在于谚赎,?如果不可重入版樁函數(shù)的名字是?xxx淫僻,則對(duì)應(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í)器、控制臺(tái)等)垃瞧。
典型的?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)意推,請(qǐng)見后面原理分析章節(jié)豆瘫,本章節(jié)只做簡(jiǎn)要描述。
LIBC與EAL的區(qū)別
從前面的描述中菊值,我們可以看出?libc?實(shí)際上也完也了?EAL?提供的相關(guān)接口外驱,?關(guān)于它們之間的區(qū)別實(shí)際上是很,對(duì)于一個(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)存申請(qǐng)是依賴?OS?的機(jī)制的(如?huge?page)舷蟀,OS?并沒有辦法保證所有申請(qǐng)的物理內(nèi)存的地址是?連續(xù)的(因?yàn)橛锌斩创嬖冢陨暾?qǐng)的內(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)。