使用 NVIDIA BlueField DPU 和 DPDK 開(kāi)發(fā)應(yīng)用程序
數(shù)據(jù)中心轉(zhuǎn)型
本文引用地址:http://www.ex-cimer.com/article/202205/433848.htmNVIDIA BlueField DPU (數(shù)據(jù)處理器)可用于網(wǎng)絡(luò)功能加速。這種網(wǎng)絡(luò)卸載可以用 DPDK ,也可以用 NVIDIA DOCA 軟件框架。
在本系列中,我構(gòu)建了一個(gè)應(yīng)用并用兩種方式進(jìn)行了卸載:DPDK 和 NVIDIA DOCA SDK 。我將每個(gè)步驟記錄為一個(gè)單獨(dú)的代碼補(bǔ)丁,并在每個(gè)系列中提供完整的步驟。這部分將向您展示如何用 DPDK 編程 BlueField DPU 。
用例
首先,我需要一個(gè)簡(jiǎn)單但有意義的用例來(lái)在 DPU 上部署應(yīng)用程序。我選擇了基于策略的路由( PBR )來(lái)根據(jù)第 3 層和第 4 層數(shù)據(jù)包屬性將流量引導(dǎo)到不同的網(wǎng)關(guān),覆蓋(或補(bǔ)充) X86 主機(jī)選擇的網(wǎng)關(guān)?,F(xiàn)實(shí)世界中有各種原因需要這樣做,包括以下示例:
· 將選定主機(jī)流量發(fā)送到外部防火墻以進(jìn)行額外審核
· 增強(qiáng) Anycast 服務(wù)器的負(fù)載平衡
· 應(yīng)用 QoS
圖 1 . 使用 PBR 將流量從主機(jī)引導(dǎo)到兩個(gè)網(wǎng)關(guān)之一
我在 DPU (BF2-ARM)上使用 PBR 將流量從主機(jī)( server1-x86 )引導(dǎo)到兩個(gè)網(wǎng)關(guān) [leaf2, leaf3] 之一。葉交換機(jī)隨后將流量轉(zhuǎn)發(fā)給其本地連接的選播服務(wù)提供商 [server2, server3] 。
構(gòu)建應(yīng)用程序
第一個(gè)問(wèn)題:我是寫一個(gè)全新的應(yīng)用程序,還是卸載一個(gè)現(xiàn)有的應(yīng)用程序?
我決定卸載我最喜歡的開(kāi)源路由軟件棧 FRRouting ( FRR )的 PBR 功能。這使我能夠擴(kuò)展現(xiàn)有的代碼庫(kù),并與現(xiàn)有的 sample apps 形成很好的對(duì)比。FRR 有一個(gè)支持多種數(shù)據(jù)平面插件的框架,可以輕松用 DPDK 和 DOCA 實(shí)現(xiàn)新的數(shù)據(jù)平面插件并集成到 FRR 。
圖 2 . DPDK 和 DOCA 插件可以很容易地添加到 FRR中
DPU 應(yīng)用程序原型
在本節(jié)中,我將介紹創(chuàng)建具有 DPU 硬件加速功能的應(yīng)用程序所需的準(zhǔn)備工作。
DPU 硬件
我有一個(gè) x86 服務(wù)器并在上面安裝了一塊 BlueFied-2 DPU , 該 DPU 有兩個(gè) 25G 上行鏈路和一個(gè)帶有 8GB 內(nèi)存的 ARM 處理器 。有關(guān)硬件安裝的更多信息,請(qǐng)參閱 DOCA SDK 文檔 。您也可以使用 DPU PocKit 來(lái)構(gòu)建和引導(dǎo)你的系統(tǒng)環(huán)境.
我安裝了 BlueField 啟動(dòng)流文件( BFB ),它為 DPU 提供了 Ubuntu 操作系統(tǒng)映像,并附帶了 DOCA-1.2 和 DPDK-20.11.3 的庫(kù)。
圖 3 . Netdev Representors
使用 SR-IOV ,我在主機(jī)上為兩個(gè)虛擬機(jī)創(chuàng)建了兩個(gè)虛擬函數(shù)( VF )接口。
主機(jī)上的 PF 和 VF 分別映射到 DPU ARM 上的以下 netdev representors 。
表 1 .主機(jī)上 PF 和 VF 的映射
使用 DPDK testpmd 應(yīng)用程序進(jìn)行原型設(shè)計(jì)
首先,我使用 DPDK 的 testpmd 進(jìn)行了我的用例的原型化設(shè)計(jì),它位于 DPU 的 / opt / mellanox / 目錄下。
包括 testpmd 在內(nèi)的任何 DPDK 應(yīng)用程序都必須設(shè)置 hugepages 。
(可選)保留配置,使其在 DPU 重新啟動(dòng)后仍然有效。
啟動(dòng) testpmd 。
Testpmd 會(huì)消耗比較多的內(nèi)存,默認(rèn)情況下會(huì)分配 3.5 GB 。由于我不需要在 CPU 中處理數(shù)據(jù)流量,我把 total-mem 的值設(shè)定為 200M ,其中 total-mem = total-num-mbufs * mbuf-size (默認(rèn) mbuf-size 為 2048 字節(jié))。我還使用了 flow-isolation 模式,因?yàn)槲冶仨殞?ARP 數(shù)據(jù)包發(fā)送到 DPU 上的內(nèi)核網(wǎng)絡(luò)堆棧來(lái)解析 PBR 的下一跳)。初始化完成后,-i選項(xiàng)使得 testpmd 進(jìn)入交互式 shell 。
作為 testpmd 完成 rte_eal 初始化的一部分, mlx5_pci 設(shè)備被探測(cè)并成為可以被訪問(wèn)的 DPDK 端口。
您在這里看到的 DPDK 端口對(duì)應(yīng) PF / VF representor 和兩個(gè)上行鏈路。
表 2 . DPDK 端口映射
流創(chuàng)建
接下來(lái),通過(guò)定義 ingress port 、源 IP 、目標(biāo) IP 、協(xié)議和端口,我用 rte_flow 下發(fā)了PBR規(guī)則。除此之外,我還定義了對(duì)匹配數(shù)據(jù)包采取的 ACTION 。源 MAC 和目標(biāo) MAC 被重寫, TTL 被遞減,出口端口被設(shè)置為物理上行鏈路 p0 。
這條 PBR 規(guī)則從 VM1接收 DNS 流量,并將其發(fā)送到特定的 GW ( leaf2, server2 )。我還增加了一個(gè)計(jì)數(shù)器以便故障定位。
DPU 卸載可以工作在 Switch ( FDB )模式,也可以工作在 NIC 模式。在這個(gè)用例中,經(jīng)過(guò)幾次數(shù)據(jù)包修改后,我需要將流量從 X86 主機(jī)重定向到 25G 上行鏈路。所以從概念上講,這里使用了 Switch ( FDB ) 模式,因此需要設(shè)置 rte_flow 的 transfer 屬性。
流程驗(yàn)證
我從 VM1 發(fā)送了一些流量,看看它是否與我用 testpmd 創(chuàng)建的 flow 是否匹配,可以通過(guò)執(zhí)行 query 命令來(lái)查看。
結(jié)果是匹配的,在 leaf2/server2 上可以看到這些流量且具有修改后的數(shù)據(jù)包頭。因?yàn)楸徊僮鞯牧髁渴?DNS ,所以為了測(cè)試流量,我從 VM1 發(fā)送 DNS 請(qǐng)求。為了控制流量速率和其他數(shù)據(jù)包字段,我使用 mz 來(lái)生成測(cè)試流量。
另一個(gè)健全性檢查是查看此流是否真的被卸載。有兩種方法可以做到這一點(diǎn):
· 在 Arm CPU 上使用 tcpdump 以確保內(nèi)核不接收此類數(shù)據(jù)包。
· 檢查硬件 eSwitch 是否有對(duì)應(yīng)的流規(guī)則。
mlx_steering_dump 允許您查看硬件上已經(jīng)下發(fā)成功的流規(guī)則。使用 git 下載并安裝該工具。
使用 mlx_steering_dump_parser.py 腳本驗(yàn)證硬件中下發(fā)的流規(guī)則。
此命令打印出 testpmd 應(yīng)用程序下發(fā)的所有流規(guī)則。我們可以看到硬件上設(shè)置的外部 頭匹配信息和前面RTE_FLOW定義的匹配 [SIP = 172.20.0.8 , DIP = 172.30.0.8 , IP proto = UDP , UDP dport = 53] 是一致的。作為打印輸出的一部分,流量計(jì)數(shù)器的值也被讀取并被重置。
原型設(shè)計(jì),作為應(yīng)用程序設(shè)計(jì)思維過(guò)程的最后一步現(xiàn)在已經(jīng)完成。我現(xiàn)在知道我可以在 DPDK 中建立一個(gè) PBR 規(guī)則,把它安裝在硬件中并對(duì)我們感興趣的數(shù)據(jù)報(bào)文進(jìn)行修改。現(xiàn)在在下一節(jié)中添加 DPDK 數(shù)據(jù)平面。
構(gòu)建 DPDK 數(shù)據(jù)平面插件
在本節(jié)中,我將通過(guò)向 Zebra 添加一個(gè) DPDK 數(shù)據(jù)平面插件,介紹 DPU 對(duì) PBR進(jìn)行 硬件加速的步驟。我將這些步驟分解為單獨(dú)的代碼提交,整個(gè)補(bǔ)丁集以 reference 的形式提供。
圖 4 .基于策略的路由 DPDK 卸載工作流
開(kāi)發(fā)環(huán)境
由于目標(biāo)體系結(jié)構(gòu)是 DPU Arm ,因此可以直接在 DPU Arm上構(gòu)建、在 X86 CPU 上交叉編譯或在云中構(gòu)建。在這篇文章中,我直接在 DPU Arm 上進(jìn)行編碼和構(gòu)建。
以 root 用戶身份運(yùn)行應(yīng)用程序
FRR 通常作為非 root 用戶運(yùn)行。FRR 可以下載和上傳整個(gè)互聯(lián)網(wǎng)路由表;這可能會(huì)出什么問(wèn)題?然而,幾乎所有的 DPDK 應(yīng)用程序都是以 root 用戶身份運(yùn)行, DPDK 庫(kù)和驅(qū)動(dòng)程序也都是基于這樣設(shè)計(jì)的。
經(jīng)過(guò)多次實(shí)驗(yàn),并使用 root 用戶選項(xiàng)重新編譯 FRR, 我還是無(wú)法讓 FRR 作為非 root 用戶工作。這是可以接受的,因?yàn)槲以谝粋€(gè)安全的空間,即 DPU Arm 中運(yùn)行 FRR 。
向 Zebra 添加新插件
Zebra 是 FRR 中的一個(gè)守護(hù)進(jìn)程,負(fù)責(zé)整合路由協(xié)議守護(hù)進(jìn)程的更新并構(gòu)建轉(zhuǎn)發(fā)表。Zebra 還有一個(gè)基礎(chǔ)設(shè)施,可以將這些轉(zhuǎn)發(fā)表推送到像 Linux 內(nèi)核這樣的數(shù)據(jù)平面。
將 DPDK 共享庫(kù)鏈接到 zebra
FRR 有自己的構(gòu)建系統(tǒng),限制直接導(dǎo)入外部 make 文件。由于 pkg-config 的簡(jiǎn)單優(yōu)雅,將相關(guān)庫(kù)鏈接到 Zebra 很容易。
我找到了 libdpdk.pc 并將其添加到 PKG_CONFIG_PATH 值中:
FRR 有自己的構(gòu)建系統(tǒng),限制直接導(dǎo)入外部 make 文件。由于 pkg-config 的簡(jiǎn)單優(yōu)雅,將相關(guān)庫(kù)鏈接到 Zebra 很容易。
我找到了 libdpdk.pc 并將其添加到 PKG_CONFIG_PATH 值中:
我在 FRR makefile (configure.ac)中為 DPDK 添加了 pkg check-and-define 宏。
我將 DPDK libs和cflags抽象包含在zebra-dp-dpdk make 宏( zebra/subdir.am )中。
有了這些,我就有了構(gòu)建插件所需的所有頭文件和庫(kù)。
初始化硬件
第一步是初始化硬件。
這將探測(cè) PCIe 設(shè)備并填充 DPDK rte_eth_dev 數(shù)據(jù)庫(kù)。
初始化端口
接下來(lái)設(shè)置硬件端口。
設(shè)置應(yīng)用程序的端口映射
FRR 有自己的基于 Linux netdevs 表的接口(端口)表,該表使用 NetLink 更新填充,并使用 ifIndex 鍵值來(lái)索引。PBR 規(guī)則錨定到此表中的一個(gè)接口。要編程 PBR 數(shù)據(jù)平面條目,需要一個(gè) Linux ifIndex 和 DPDK port-id 值之間的映射表。netdev 信息已經(jīng)在 DPDK 驅(qū)動(dòng)程序中可用,可以通過(guò) rte_eth_dev_info_get 查詢。
配置硬件端口
此外,所有端口都需要置于 flow-isolation 模式并啟動(dòng)。
Flow-isolation 模式將未命中數(shù)據(jù)包發(fā)送到內(nèi)核網(wǎng)絡(luò)堆棧,允許它處理 ARP 請(qǐng)求之類的事情。
使用 rte _流 API 編程 PBR 規(guī)則
PBR 規(guī)則現(xiàn)在需要用 rte_flow 來(lái)編寫,下面是一個(gè)示例規(guī)則:
這些參數(shù)通過(guò) rte_flow_attributes 、 rte_flow_item ( match ) 和 rte_flow_action 數(shù)據(jù)結(jié)構(gòu)填充。
流屬性
此數(shù)據(jù)結(jié)構(gòu)用于指示 PBR 流用于分組重定向或 transfer flow 。
流匹配項(xiàng)
DPDK 為數(shù)據(jù)包頭中的每一層使用 {key, mask} 匹配結(jié)構(gòu):以太網(wǎng)、 IP 、 UDP 等。
填充這些數(shù)據(jù)結(jié)構(gòu)需要大量重復(fù)的代碼。
流動(dòng)作
DPDK 為每個(gè) Action 使用單獨(dú)的數(shù)據(jù)結(jié)構(gòu),然后允許您在創(chuàng)建流規(guī)則時(shí)以可變長(zhǎng)度數(shù)組的形式提供所有 Actions 。有關(guān) Actions 如下:
流驗(yàn)證和創(chuàng)建
作為可選項(xiàng),您可以驗(yàn)證 rte_flow_attr、rte_flow_item 和 rte_flow_action 列表。
流驗(yàn)證通常用于檢查底層 DPDK 驅(qū)動(dòng)程序是否支持特定的流配置。流驗(yàn)證是一個(gè)可選步驟,在最后的代碼中,您可以直接跳轉(zhuǎn)到流創(chuàng)建。
Rte_flow 命令被錨定到輸入端口??梢詣?chuàng)建多個(gè)流條目組并將這些組鏈起來(lái)。即使流條目不存在鏈的第一個(gè)組中,也就是不在組 0 中,它仍然必須錨定到輸入端口。group-0 存在性能限制。
流量插入率在 group-0 中受到限制。要繞過(guò)該限制,您可以在 group-0 中安裝一個(gè)默認(rèn)流,以“跳轉(zhuǎn)到 group-1 ”,然后在 group-1 中創(chuàng)建流規(guī)則。
流刪除
流創(chuàng)建 API 返回一個(gè)流指針,該指針必須被緩存以進(jìn)行后續(xù)的流刪除。
FRR-PBR 守護(hù)進(jìn)程管理狀態(tài)機(jī)來(lái)解析,添加或刪除 PBR 流。因此,我不必使用 DPDK 的原生函數(shù)來(lái)老化 PBR 規(guī)則。
流量統(tǒng)計(jì)
在創(chuàng)建流時(shí),我將計(jì)數(shù)操作附加到流??捎糜诓樵兞髁拷y(tǒng)計(jì)信息和命中次數(shù)。
為了便于測(cè)試和驗(yàn)證,我將該統(tǒng)計(jì)顯示插入了 FRR 的 vtysh CLI 。
測(cè)試應(yīng)用程序
我以 root 用戶的身份啟動(dòng)了 FRR ,并通過(guò) /etc/frr/daemons 文件啟用了新添加的 DPDK 插件:
DPDK-port 映射表的 FRR 接口已填充:
接下來(lái),我將 PBR 規(guī)則配置為匹配來(lái)自 VM1 的 DNS 流量,并使用 frr.conf 將其重定向到 leaf2 。
我從 VM1 發(fā)送 DNS 查詢到 anycast DNS 服務(wù)器。
匹配流,并使用修改后的數(shù)據(jù)包頭將流量轉(zhuǎn)發(fā)到目的地 leaf2/server2 。這可以通過(guò)連接到流的計(jì)數(shù)器和使用 mlx_steering_dump 做硬件轉(zhuǎn)儲(chǔ)來(lái)驗(yàn)證。
FRR 現(xiàn)在有一個(gè)功能齊全的 DPDK 數(shù)據(jù)平面插件,可以在 DPU 硬件上卸載 PBR 規(guī)則。
總結(jié)
這篇文章回顧了使用 DPDK RTE_FLOW庫(kù)在 BlueField 上硬件加速 PBR 規(guī)則的 FRR 數(shù)據(jù)平面插件的創(chuàng)建。在下一篇文章中,我將帶您了解 FRR DOCA 數(shù)據(jù)平面插件,并向您展示如何使用新的 DOCA_FLOW 庫(kù)卸載 PBR 規(guī)則。
評(píng)論