Linux網路新技術基石——eBPF、XDP

語言: CN / TW / HK

hi,大家好,今天給大家分享的是Linux 網路新技術,當前正流行網路技是什麼?那就是eBPF和XDP技術, Cilium+eBPF超級火熱,Google GCP也剛剛全面轉過來。

新技術出現的歷史原因

廉頗老矣,尚能飯否

iptables/netfilter

iptables/netfilter 是上個時代Linux網路提供的優秀的防火牆技術,擴充套件性強,能夠滿足當時大部分網路應用需求,如果不知道iptables/netfilter是什麼 請參考之前文章: 一個奇葩的網路問題,把技術磚家"搞蒙了" 裡面對iptables/netfilter技術有詳細介紹。

但該框架也存在很多明顯問題:

  • 路徑太長

netfilter 框架在IP層,報文需要經過鏈路層,IP層才能被處理,如果是需要丟棄報文,會白白浪費很多CPU資源,影響整體效能;

  • O(N)匹配

如上圖所示,極端情況下,報文需要依次遍歷所有規則,才能匹配中,極大影響報文處理效能;

  • 規則太多

netfilter 框架類似一套可以自由新增策略規則專家系統,並沒有對新增規則進行合併優化,這些都嚴重依賴操作人員技術水平,隨著規模的增大,規則數量n成指數級增長,而報文處理又是0(n)複雜度,最終效能會直線下降。

核心協議棧

隨著網際網路流量越來愈大, 網絡卡效能越來強,Linux核心協議棧在10Mbps/100Mbps網絡卡的慢速時代是沒有任何問題的,那個時候應用程式大部分時間在等網絡卡送上來資料。

現在到了1000Mbps/10Gbps/40Gbps網絡卡的時代,資料被很快地收入,協議棧複雜處理邏輯,效率捉襟見肘,把大量報文堵在核心裡。

各類連結串列在多CPU環境下的同步開銷。

不可睡眠的軟中斷路徑過長。

sk_buff的分配和釋放。

記憶體拷貝的開銷。

上下文切換造成的cache miss。

於是,核心協議棧各種優化措施應著需求而來:

網絡卡RSS,多佇列。

中斷執行緒化。

分割鎖粒度。

Busypoll。

但卻都是見招拆招,治標不治本。問題的根源不是這些機制需要優化,而是這些機制需要推倒重構。蒸汽機車剛出來的時候,馬車伕為了保持競爭優勢,不是去換一匹昂貴的快馬,而是賣掉馬去買一臺蒸汽機裝上。基本就是這個意思。

重構的思路很顯然有兩個:

upload方法 別讓應用程式等核心了,讓應用程式自己去網絡卡直接拉資料。

offload方法 別讓核心處理網路邏輯了,讓網絡卡自己處理。

總之,繞過核心就對了,核心協議棧揹負太多歷史包袱。

DPDK 讓使用者態程式直接處理網路流,bypass掉核心,使用獨立的CPU專門幹這個事。

XDP 讓灌入網絡卡的eBPF程式直接處理網路流,bypass掉核心,使用網絡卡NPU專門幹這個事

如此一來,核心協議棧就不再參與資料平面的事了,留下來專門處理諸如路由協議,遠端登入等控制平面和管理平面的資料流。

改善iptables/netfilter的規模瓶頸,提高Linux核心協議棧IO效能, 核心需要提供新解決方案,那就是eBPF/XDP框架,讓我們來看一看,這套框架是如何解決問題的。

eBPF到底是什麼?

e BPF的歷史

BPF 是 Linux 核心中高度靈活和高效的類似虛擬機器的技術,允許以安全的方式在各個掛鉤點執行位元組碼。它用於許多 Linux 核心子系統,最突出的是網路、跟蹤和安全(例如沙箱)。

BPF架構

BPF 是一個通用目的 RISC 指令集,其最初的設計目標是:用 C 語言的一個子集編 寫程式,然後用一個編譯器後端(例如 LLVM)將其編譯成 BPF 指令,稍後核心再通 過一個位於核心中的(in-kernel)即時編譯器(JIT Compiler)將 BPF 指令對映成處理器的原生指令(opcode ),以取得在核心中的最佳執行效能。

BPF指令

儘管 BPF 自 1992 年就存在,擴充套件的 Berkeley Packet Filter (eBPF) 版本首次出現在 Kernel3.18中,如今被稱為“經典”BPF (cBPF) 的版本已過時。許多人都知道 cBPF是tcpdump使用的資料包過濾語言。現在Linux核心只執行 eBPF,並且載入的 cBPF 位元組碼在程式執行之前被透明地轉換為核心中的eBPF表示。除非指出 eBPF 和 cBPF 之間的明確區別,一般現在說的BPF就是指eBPF。

e BPF總體設計

  • BPF 不僅通過提供其指令集來定義自己,而且還通過提供圍繞它的進一步基礎設施,例如充當高效鍵/值儲存的對映、與核心功能互動並利用核心功能的輔助函式、呼叫其他 BPF 程式的尾呼叫、安全加固原語、用於固定物件(地圖、程式)的偽檔案系統,以及允許將 BPF 解除安裝到網絡卡的基礎設施。

  • LLVM 提供了一個 BPF後端,因此可以使用像 clang 這樣的工具將 C 編譯成 BPF 目標檔案,然後可以將其載入到核心中。BPF與Linux 核心緊密相連,允許在不犧牲本機核心效能的情況下實現完全可程式設計。

eBPF總體設計包括以下幾個部分:

eBPF Runtime

  • 安全保障 :  eBPF的verifier 將拒絕任何不安全的程式並提供沙箱執行環境

  • 持續交付:  程式可以更新在不中斷工作負載的情況下

  • 高效能:JIT編譯器可以保證執行效能

eBPF Hooks

  • 核心函式 (kprobes)、使用者空間函式 (uprobes)、系統呼叫、fentry/fexit、跟蹤點、網路裝置 (tc/xdp)、網路路由、TCP 擁塞演算法、套接字(資料面)

eBPF Maps

Map 型別

- Hash tables, Arrays

- LRU (Least Recently Used)

- Ring Buffer

- Stack Trace

- LPM (Longest Prefix match)

作用

  • 程式狀態

  • 程式配置

  • 程式間共享資料

  • 和使用者空間共享狀態、指標和統計

eBPF Helpers

有哪些Helpers?

  • 隨機數

  • 獲取當前時間

  • map訪問

  • 獲取程序/cgroup 上下文

  • 處理網路資料包和轉發

  • 訪問套接字資料

  • 執行尾呼叫

  • 訪問程序棧

  • 訪問系統呼叫引數

  • ...

eBPF Tail and Function Calls

尾呼叫有什麼用?

● 將程式連結在一起

● 將程式拆分為獨立的邏輯元件

● 使 BPF 程式可組合

函式呼叫有什麼用?

● 重用內部的功能程式

● 減少程式大小(避免內聯)

eBPF JIT Compiler

  • 確保本地執行效能而不需要了解CPU

  • 將 BPF位元組碼編譯到CPU架構特定指令集

eBPF可以做什麼?

eBPF 開源 Projects

Cilium

  • Cilium 是開源軟體,用於Linux容器管理平臺(如 Docker 和 Kubernetes)部署的服務之間的 透明通訊和提供安全隔離保護

  • Cilium基於微服務的應用,使用HTTP、gRPC、Kafka等輕量級協議API相互通訊。

  • Cilium 的基於 eBPF 的新 Linux 核心技術,它能夠在 Linux 本身中動態插入強大的安全可見性和控制邏輯。由於 eBPF 在 Linux 核心中執行,因此可以在不更改應用程式程式碼或容器配置的情況下應用和更新 Cilium 安全策略。

Cilium 在它的 datapath 中重度 使用了 BPF 技術

  • Cilium 是位於 Linux kernel 與容器編排系統的中間層。向上可以為容器配置網路,向下可以向 Linux 核心生成 BPF 程式來控制容器的安全性和轉發行為。

  • 利用 Linux BPF,Cilium 保留了透明地插入安全可視性 + 強制執行的能力,但這種方式基於服務 /pod/ 容器標識(與傳統系統中的 IP 地址識別相反),並且可以根據應用層進行過濾 (例如 HTTP)。因此,通過將安全性與定址分離,Cilium 不僅可以在高度動態的環境中應用安全策略,而且除了提供傳統的第 3 層和第 4 層分割之外,還可以通過在 HTTP 層執行來提供更強的安全隔離

  • BPF 的使用使得 Cilium 能夠以高度可擴充套件的方式實現以上功能,即使對於大規模環境也不例外

對比傳統容器網路(採用iptables/netfilter):

  • eBPF主機路由允許繞過主機名稱空間中所有的 iptables 和上層網路棧,以及穿過Veth對時的一些上下文切換,以節省資源開銷。網路資料包到達網路介面裝置時就被儘早捕獲,並直接傳送到Kubernetes Pod的網路名稱空間中。在流量出口側,資料包同樣穿過Veth對,被eBPF捕獲後,直接被傳送到外部網路介面上。eBPF直接查詢路由表,因此這種優化完全透明。

  • 基於eBPF中的kube-proxy網路技術正在替換基於iptables的kube-proxy技術,與Kubernetes中的原始kube-proxy相比,eBPF中的kuber-proxy替代方案具有一系列重要優勢,例如更出色的效能、可靠性以及可除錯性等等。

BCC(BPF Compiler Collection)

BCC 是一個框架,它使使用者能夠編寫嵌入其中的 eBPF 程式的 Python 程式。該框架主要針對涉及應用程式和系統分析/跟蹤的用例,其中 eBPF 程式用於收集統計資訊或生成事件,使用者空間中的對應部分收集資料並以人類可讀的形式顯示。執行 python 程式將生成 eBPF 位元組碼並將其載入到核心中。

bpftrace

bpftrace 是一種用於 Linux eBPF 的高階跟蹤語言,可在最近的 Linux 核心 (4.x) 中使用。bpftrace 使用 LLVM 作為後端將指令碼編譯為 eBPF 位元組碼,並利用 BCC 與 Linux eBPF 子系統以及現有的 Linux 跟蹤功能進行互動:核心動態跟蹤 (kprobes)、使用者級動態跟蹤 (uprobes) 和跟蹤點. bpftrace 語言的靈感來自 awk、C 和前身跟蹤器,例如 DTrace 和 SystemTap。

eBPF Go 庫

eBPF Go 庫提供了一個通用的 eBPF 庫,它將獲取 eBPF 位元組碼的過程與 eBPF 程式的載入和管理解耦。eBPF 程式通常是通過編寫高階語言建立的,然後使用 clang/LLVM 編譯器編譯為 eBPF 位元組碼。

libbpf C/C++ 庫

libbpf 庫是一個基於 C/C++ 的通用 eBPF 庫,它有助於解耦從 clang/LLVM 編譯器生成的 eBPF 目標檔案載入到核心中,並通過提供易於使用的庫 API 來抽象與 BPF 系統呼叫的互動應用程式。

那XDP又是什麼?

XDP的全稱是:  eXpress Data Path

XDP 是Linux 核心中提供高效能、可程式設計的網路資料包處理框架。

XDP整體框架

  • 直接接管網絡卡的RX資料包(類似DPDK使用者態驅動)處理;

  • 通過執行BPF指令快速處理報文;

  • 和Linux協議棧無縫對接;

XDP總體設計

XDP總體設計包括以下幾個部分:

XDP驅動

網絡卡驅動中XDP程式的一個掛載點,每當網絡卡接收到一個數據包就會執行這個XDP程式;XDP程式可以對資料包進行逐層解析、按規則進行過濾,或者對資料包進行封裝或者解封裝,修改欄位對資料包進行轉發等;

BPF虛擬機器

並沒有在圖裡畫出來,一個XDP程式首先是由使用者編寫用受限制的C語言編寫的,然後通過clang前端編譯生成BPF位元組碼,位元組碼載入到核心之後執行在eBPF虛擬機器上,虛擬機器通過即時編譯將XDP位元組碼編譯成底層二進位制指令;eBPF虛擬機器支援XDP程式的動態載入和解除安裝;

BPF maps

儲存鍵值對,作為使用者態程式和核心態XDP程式、核心態XDP程式之間的通訊媒介,類似於程序間通訊的共享記憶體訪問;使用者態程式可以在BPF對映中預定義規則,XDP程式匹配對映中的規則對資料包進行過濾等;XDP程式將資料包統計資訊存入BPF對映,使用者態程式可訪問BPF對映獲取資料包統計資訊;

BPF程式校驗器

XDP程式肯定是我們自己編寫的,那麼如何確保XDP程式載入到核心之後不會導致核心崩潰或者帶來其他的安全問題呢?程式校驗器就是在將XDP位元組碼載入到核心之前對位元組碼進行安全檢查,比如判斷是否有迴圈,程式長度是否超過限制,程式記憶體訪問是否越界,程式是否包含不可達的指令;

XDP Action

XDP用於報文的處理,支援如下action:

enum xdp_action {

XDP_ABORTED = 0,

XDP_DROP,

XDP_PASS,

XDP_TX,

XDP_REDIRECT,

};

  • XDP_DROP :在驅動層丟棄報文,通常用於實現DDos或防火牆

  • XDP_PASS :允許報文上送到核心網路棧,同時處理該報文的CPU會分配並填充一個skb,將其傳遞到GRO引擎。之後的處理與沒有XDP程式的過程相同。

  • XDP_TX 從當前網絡卡傳送出去

  • XDP_REDIRECT 從其他網絡卡傳送出去

  • XDP_ABORTED :表示程式產生了異常,其行為和 XDP_DROP相同,但 XDP_ABORTED 會經過 trace_xdp_exception tracepoint,因此可以通過 tracing 工具來監控這種非正常行為。

AF_XDP

AF_XDP 是為高效能資料包處理而優化的地址族,AF_XDP 套接字使 XDP 程式可以將幀重定向到使用者空間應用程式中的記憶體緩衝區。

XDP設計原則

  • XDP 專為高效能而設計。它使用已知技術並應用選擇性約束來實現效能目標

  • XDP 還具有可程式設計性。無需修改核心即可即時實現新功能

  • XDP 不是核心旁路。它是核心協議棧的快速路徑

  • XDP 不替代TCP/IP 協議棧。與協議棧協同工作

  • XDP 不需要任何專門的硬體。它支援網路硬體的少即是多原則

XDP技術優勢

及時處理

  • 在網路協議棧前處理, 由於 XDP 位於整個 Linux 核心網路軟體棧的底部,能夠非常早地識別並丟棄攻擊報文,具有很高的效能。可以改善 iptables 協議棧丟包的效能瓶頸

  • DDIO

  • Packeting steering

  • 輪詢式

高效能優化

  • 無鎖設計

  • 批量I/O操作

  • 不需要分配skbuff

  • 支援網路解除安裝

  • 支援網絡卡RSS

指令虛擬機器

  • 規則優化,編譯成精簡指令,快速執行

  • 支援熱更新,可以動態擴充套件核心功能

  • 易程式設計-高階語言也可以間接在核心執行

  • 安全可靠,BPF程式先校驗後執行,XDP程式沒有迴圈

可擴充套件模型

  • 支援應用處理(如應用層協議GRO)

  • 支援將BPF程式解除安裝到網絡卡

  • BPF程式可以移植到使用者空間或其他作業系統

可程式設計性

  • 包檢測,BPF程式發現的動作

  • 靈活(無迴圈)協議頭解析

  • 可能由於流查詢而有狀態

  • 簡單的包欄位重寫(encap/decap)

XDP 工作模式

XDP 有三種工作模式,預設是 native (原生)模式,當討論 XDP 時通常隱含的都是指這 種模式。

  • Native XDP

    預設模式,在這種模式中,XDP BPF 程式直接執行在網路驅動的早期接收路徑上( early receive path)。

  • Offloaded XDP

    在這種模式中,XDP BPF程式直接 offload 到網絡卡。

  • Generic XDP

    對於還沒有實現 native 或 offloaded XDP 的驅動,核心提供了一個 generic XDP 選 項,這種設定主要面向的是用核心的 XDP API 來編寫和測試程式的開發者,對於在生產環境使用XDP,推薦要麼選擇native要麼選擇offloaded模式。

XDP vs DPDK

相對於DPDK,XDP:

優點

  • 無需第三方程式碼庫和許可

  • 同時支援輪詢式和中斷式網路

  • 無需分配大頁

  • 無需專用的CPU

  • 無需定義新的安全網路模型

缺點

注意XDP的效能提升是有代價的,它犧牲了通用型和公平性

  • XDP不提供快取佇列(qdisc),TX裝置太慢時直接丟包,因而不要在RX比TX快的裝置上使用XDP

  • XDP程式是專用的,不具備網路協議棧的通用性

如何選擇?

  • 核心延伸專案,不想bypass核心的下一代高效能方案;

  • 想直接重用核心程式碼;

  • 不支援DPDK程式環境;

XDP適合場景

  • DDoS防禦

  • 防火牆

  • 基於XDP_TX的負載均衡

  • 網路統計

  • 流量監控

  • 棧前過濾/處理

  • ...

XDP例子

下面是 一個最小的完整 XDP 程式 ,實現丟棄包的功能( xdp-example.c ):

#include <linux/bpf.h>

#ifndef __section
# define __section(NAME) \
__attribute__((section(NAME), used))
#endif

__section("prog")
int xdp_drop(struct xdp_md *ctx)
{
return XDP_DROP;
}

char __license[] __section("license") = "GPL";

用下面的命令編譯並載入到核心:

$ clang -O2 -Wall -target bpf -c xdp-example.c -o xdp-example.o
$ ip link set dev em1 xdp obj xdp-example.o

以上命令將一個 XDP 程式 attach 到一個網路裝置,需要是 Linux 4.11 核心中支援 XDP 的裝置,或者 4.12+ 版本的核心。

最後

eBPF/XDP 作為Linux網路革新技術正在悄悄改變著Linux網路發展模式。

eBPF正在將Linux核心轉變為微核心,越來越多的新核心功能採用eBPF實現,讓新增核心功能更加快捷高效。

總體而言,基於業界基準測試結果,eBPF 顯然是解決具有挑戰性的雲原生需求的最佳技術。

參考&延伸閱讀

The eXpress Data Path: 

Fast Programmable Packet Processing in the Operating System Kernel

https://docs.cilium.io/en/v1.6/bpf/

bpf-rethinkingthelinuxkernel-200303183208

https://ebpf.io/what-is-ebpf/

https://www.kernel.org/doc/html/latest/networking/af_xdp.html

https://cilium.io/blog/2021/05/11/cni-benchmark

https://blog.csdn.net/dog250/article/details/107243696

- END -

關注公眾號:Knative,瞭解更多 Serverless 、Knative,雲原生相關資訊

關注公眾號,回覆 " 進群 ",即可進群與眾多雲原生 Serverless 技術大佬探討技術,探討人生。