eBPF 介紹


 

本文是有關eBPF的系列文章中的第一篇。每個都將在先前的基礎上發展,並從概念和上下文過渡到示例和實現。第一篇文章將探討eBPF的歷史,當前狀態和未來軌跡。為此,我希望使eBPF的當前狀態和功能更加一致。與許多軟件項目一樣,如果沒有塑造它的歷史背景,eBPF可能會顯得奇怪而痙攣。

本文還引用了將在本系列中撰寫的未來文章。對於那些可能引用此文章的人,將在發布這些文章時對其進行更新以引用這些文章。但是,本文的早期版本將可供參考,並且指向它們的鏈接將發布在此頁面上。

介紹

擴展的伯克利數據包過濾器(簡稱eBPF)很難完整地解釋和理解。部分原因是與解決eBPF解決的問題的現有努力有何不同。然而,可以說,最大的原因是它的名字。當某人第一次了解eBPF時,他們可能不知道什么是BPF或對其進行“擴展”意味着什么。“ Berkely”這個世界除了提及美國加利福尼亞州的伯克利市外也無濟於事。eBPF名稱中唯一可能對初次見過的人有意義的單詞是“包過濾器”。這沒有說明eBPF可以用於網絡過濾以外的許多用途。但是,Linux社區並沒有意識到eBPF在命名時會傳播多遠。

eBPF的核心是駐留在內核中的高效虛擬機。它的初衷是,有效的網絡幀過濾,使該虛擬機以及eBPF成為一般處理事件的理想引擎。因此,在撰寫本文時,目前有十二種不同類型的eBPF程序,其中許多用於與網絡無關的目的。

本文“ eBPF:過去,現在和未來”將介紹BPF(eBPF的前身)的歷史,eBPF的當前狀態以及未來的發展方向。這樣做的目的是讓不熟悉eBPF和不熟悉Linux的讀者牢牢掌握eBPF的概念和用法,並為它的本質提供一個強有力的上下文。

澄清,術語和更正

本文試圖盡可能地做到正確,同時又使對eBPF主題一無所知的人也可以接近。設定這樣一個崇高的目標迫在眉睫。

  1. 澄清。不熟悉eBPF和不熟悉Linux的讀者可以閱讀本文。但是,在花了很多時間研究本文之后,我希望有些細節對我來說似乎很明顯,但對於那些不熟悉該主題的人來說卻不是。這不是故意的,而是在此內容上花費了40多個小時的結果。如果本文的任何部分需要更多的解釋或說明,請向該網站Github存儲庫提交問題,說明需要更多信息的地方。
  2. 條款。 本文主張使用技術上正確的術語,而不是不正確的常用術語。這樣的一個例子是伯克利數據包過濾器,盡管它的名字,它過濾的是網絡幀,而不是數據包。以下標題為術語的小節列出了由於某種原因可能會被誤解的所有術語,以及它們在本文范圍內的明確含義。
  3. 更正。 在撰寫本文時,我嘗試研究,查找和引用盡可能多的證據來證明此處的內容。話雖這么說,但這是一種代表歷史的嘗試,在這個領域中,總是要多說些話,並且對一切事物都有多種觀點。因此,本文歡迎有支持證據的反饋和更正。可以將反饋和相應的證據作為問題提交到本網站Github存儲庫

條款

  • BPF:在FreeBSD中找到的Berkeley數據包過濾器。
  • eBPF: Linux中的擴展Berkeley數據包過濾器。
  • eBPF映射: eBPF中可用的所有不同類型的數據存儲區的總稱。即使存在多種類型,eBPF的文檔也將所有eBPF數據存儲類型都稱為“映射”,其中有些不是映射。因此,本文使用術語eBPF-map來明確指定eBPF的數據存儲類型,而不是使其完全脫離eBPF自己的文檔。
  • 網絡框架:OSI網絡模型鏈路層(第2層)的數據單位。示例:以太網。
  • 網絡數據包:OSI網絡模型網絡層(第3層)的數據單位。示例:IPv4
  • 網絡段:OSI網絡模型傳輸層(第4層)的數據單位。示例:TCP

BPFFreeBSD:過去

要了解Linux中的eBPF,最好從其他操作系統開始:FreeBSD。1993年,在美國加利福尼亞州聖地亞哥舉行的1993年冬季USENIX會議上,發表了論文“ BSD數據包過濾器-一種用於用戶級數據包捕獲的新體系結構,McCanne和Jacobson”。它是由當時在勞倫斯伯克利國家實驗室工作的史蒂芬·麥卡納(Steven McCanne)和范雅各布森(Van Jacobson)撰寫的。在本文中,McCanne和Jacobson描述了BSD數據包過濾器(簡稱BPF),包括其在內核中的位置以及作為虛擬機的實現。

BPF與之前的產品(例如CMU / Stanford數據包過濾器(CSPF))的不同之處在於,它使用了經過深思熟慮的內存模型,然后通過內核內部的高效虛擬機將其公開。這樣,BPF篩選器可以有效地進行流量篩選,同時仍保持篩選器代碼和內核之間的邊界。

McCanne和Jacobson在他們的論文中提供了以下圖表以幫助形象化。重要的是,BPF在過濾器和用戶空間之間使用緩沖區,以避免必須為過濾器匹配的每個數據包在用戶空間和內核空間之間進行昂貴的上下文切換。

 

McCanne和Jacobson所做的最重要的事情也許就是通過以下五個語句來定義虛擬機的設計:

  1. “它必須與協議無關。不必修改內核即可添加新的協議支持。”
  2. “必須是一般性的。指令集應足夠豐富以處理意外的使用。”
  3. “數據包數據引用應最小化。”
  4. “對一條指令進行解碼應包含一個C開關語句。”
  5. “抽象機寄存器[ 1 ]應該駐留在物理寄存器中。”

這種對可擴展性,通用性和性能的強調可能是現代形式的eBPF所包含的功能遠遠超過BPF最初的實現的原因。但是BPF虛擬機非常簡單明了,它“由一個累加器,一個索引寄存器,一個暫存存儲器和一個隱式程序計數器組成”。[McCanne和Jacobson]可以從示例程序中看到,該程序在注冊碼,下面匹配所有IP數據包。每個操作的說明均在其右側。

    ldh [12]                    // load ethertype field info into register

    jeq #ETHERTYPE_IP, L1, L2   // compare register to ethertype for IP

L1: ret #TRUE                   // if comparison is true, return true

L2: ret #0                      // if comparison is false, return 0

僅使用4條虛擬機指令,BPF就能提供非常有用的IP數據包過濾器!為了說明該設計的效率,最初的BPF實現能夠拒絕最少184CPU指令的數據包。這是從bpf_tap調用開始到結束的指令計數,這意味着它可以測量BPF實現和拒絕過濾器所完成的工作。[ 2 ]通過這種方式,BPF使處理器具有了與新型圖形計算器相當的功能。通過安全的內核虛擬機處理理論上最大的2.6 Gbps網絡流量。[ 3可以通過將其與上下文切換性能進行比較來強調其效率。在SPARCstation 2上,McCanne和Jacobson用來進行這些測量的硬件,進行上下文切換可能需要2840條指令和16000+條指令(相當於71微秒和400+微秒)之間的任意時間,具體取決於爭用資源的進程數量和上下文大小的交換。[ 4 ]

最后,在McCanne和Jacobson論文的末尾有兩點值得注意。首先,當他們的論文發表時,BPF大約有兩年的歷史。這是值得注意的,因為它表明BPF的發展是一個漸進的過程,並隨着其成功技術的發展而不斷發展。其次,在撰寫本文時,它提到tcpdump是使用BPF的最廣泛使用的程序。[ 5]這意味着tcpdump是當今使用最廣泛的網絡調試工具之一,已經使用BPF技術至少24年了!我之所以這么說是因為沒有其他著作提到BPF技術家族已經使用了多長時間了。當McCanne和Jacobson的論文發表時,BPF並不是一個具有alpha級別實現的好主意。它已經過測試和使用了兩年,並且已經在多種工具中找到了應用。

對於那些感興趣的人,McCanne和Jacobson的論文只有11頁,值得一讀。可以在此處找到原始文件的掃描結果(/ pdfs / BSD數據包過濾器-一種用於用戶級數據包捕獲的新體系結構,McCanne和Jacobson,scan.pdf),並且可以找到草稿的PDF渲染[此處](/ pdfs / BSD數據包過濾器-一種用於用戶級數據包捕獲的新架構,McCanne和Jacobson,draft.pdf)。[ 6 ] [ 7 ]

eBPFLinux:現在

2014年12月發布Linux內核版本3.18時,它包含擴展BPF(eBPF)的第一個實現。[ 8簡而言之,eBPF提供的是內核內虛擬機,如BPF,但有一些關鍵的改進。第一,eBPF比原始BPF虛擬機更高效,這要歸功於eBPF代碼的JIT編譯。第二,它設計用於內核中的常規事件處理。這使內核開發人員可以將eBPF集成到他們認為合適的用途的內核組件中。第三,它包括eBPF稱為“地圖”的高效全局數據存儲。這種允許狀態在事件之間持續存在,因此可以匯總使用,包括統計信息和上下文感知行為。值得注意的是,自eBPF創建以來,數據存儲的類型很多,但並非全部都是地圖。但是,術語“映射”一直用於指代不同的數據存儲類型,本文通過將它們稱為“ eBPF映射”做出了妥協。

憑借這些功能,內核開發人員已在各種內核系統中迅速利用了eBPF。在不到兩年半的時間里,這些用途已增長到包括網絡監視,網絡流量操縱和系統監視。因此,eBPF程序可用於交換網絡流量,測量磁盤讀取的延遲或跟蹤CPU緩存未命中。

在繼續本文之前,有必要快速澄清一下。Linux社區習慣將eBPF簡稱為“ BPF”。官方文檔通常在遠離代碼的情況下以“高級”方式將eBPF稱為“ eBPF”。但是,許多實現級別的命名約定和文檔都將其稱為“ BPF”。為了消除任何困惑,在繼續之前,截至本文撰寫之時,Linux僅具有eBPF,因此對BPF的任何引用實際上都是對eBPF的引用。[ 9 ]與Linux有關的某些文檔也使用“ cBPF”,這是“經典BPF”的縮寫,引用BPF,使兩者之間的區別更加清晰。

了解eBPF當前實施重點的最快方法是逐步了解使用eBPF的要求。eBPF程序所經歷的過程可以分為三個不同的部分。

  1. 創建eBPF程序作為字節碼。 當前,創建eBPF程序的標准方法是將它們編寫為C代碼,然后讓LLVM將其編譯為駐留在ELF文件中的eBPF字節代碼。但是,eBPF虛擬機的設計已被很好地記錄下來,其代碼以及圍繞它的許多工具都是開源的。因此,對於發起,完全有可能手工制作eBPF程序的注冊碼,或者編寫eBPF的自定義編譯器。由於eBPF的設計極為簡單,因此必須內聯eBPF程序的所有功能(入口點功能除外),以便LLVM進行編譯。本系列文章的第三部分(尚未發布)將對此進行更詳細的介紹。對於那些同時尋求更多信息的人,請參閱本文的“ 進一步閱讀”部分
  2. 將程序加載到內核並創建必要的eBPF映射。 這是使用bpfLinux中的syscall 完成的。此syscall允許加載字節碼以及正在加載的eBPF程序類型的聲明。在撰寫本文時,eBPF具有用作套接字過濾器,kprobe處理程序,流量控制調度程序,流量控制操作,跟蹤點處理程序,eXpress數據路徑(XDP),性能監視器,cgroup限制和輕量級隧道的程序類型。syscall也用於初始化eBPF映射。本系列的第二部分通過 eBPF2部分:Syscall和映射類型”一文解釋了此syscall的選項和實現細節。第三批致力於通過使用當前的Linux工具,主要是tc和ip從iproute2開始,出於此目的,下面的內容將詳細介紹該操作的底層操作。對於那些同時尋求更多信息的人,請參閱本文的“ 進一步閱讀”部分
  3. 將加載的程序附加到系統。 由於eBPF的不同用法用於Linux內核中的不同系統,因此每種eBPF程序類型都有不同的過程來附加到其相應的系統。附加程序后,程序將變為活動狀態,並開始過濾,分析或捕獲信息,具體取決於創建該程序的目的。用戶空間程序可以從此處管理正在運行的eBPF程序,包括從其eBPF映射中讀取狀態;如果以這種方式構造程序,則可以操縱eBPF映射以更改程序的行為。對於那些同時尋求更多信息的人,請參閱本文的“ 進一步閱讀”部分

這三個步驟在概念上很簡單,但在使用上卻非常細微。以后的文章將對此進行更詳細的介紹,當它們完成時,我將在本文中鏈接到它們。同時,要知道當前的工具確實在使用eBPF方面提供了很多幫助,即使可能與使用它們的經驗背道而馳。像Linux中的許多東西一樣,在沒有其他工具幫助的情況下,從內核內部使用eBPF可能比從內核外部使用eBPF更好。重要的是要記住,eBPF的通用性既導致了其驚人的靈活性,又使其使用變得復雜。對於那些希望圍繞eBPF構建新功能的人,當前的Linux內核提供了更多的框架,而不是開箱即用的解決方案。[ 10 ]

為了快速回顧一下,eBPF自2014年以來一直位於Linux內核中,但已經在內核中用於多種不同用途,以進行有效的事件處理。借助eBPF映射,用eBPF編寫的程序可以維護狀態,從而跨事件聚合信息,並具有動態行為。eBPF的使用由於其極簡的實現方式和輕快的速度性能而繼續得到擴展。現在介紹eBPF的未來期望。

智能網卡和內核空間程序:未來

在短短幾年內,eBPF已集成到許多Linux內核組件中。這使得eBPF的未來前景既有趣,但方向也不明確。這是因為確實存在兩個未來的問題:eBPF的使用的未來和eBPF作為技術的未來。

eBPF的使用的近期可能是最確定的。在Linux內核中使用eBPF進行安全,高效,事件處理的趨勢很可能會繼續。由於eBPF是由運行它的簡單虛擬機定義的,因此eBPF也有可能在Linux內核以外的其他地方使用。在撰寫本文時,最有趣的示例是使用智能NIC。

智能NIC是網卡,它允許將網絡流量的處理在不同程度上轉移給NIC本身。這個想法自2000年代初就出現了,當時一些NIC開始支持卸載校驗和和分段,但是直到最近才用於部分或全部數據平面卸載。這種新型的智能NIC有多種名稱,包括“智能服務器適配器”,但通常具有可編程功能和用於存儲狀態的大量內存。Netronome的Agilio CX SmartNIC系列產品就是一個例子,該產品目前具有10Gbps至40Gbps端口,ARM11處理器,2GB DDR3 RAM和一百多個專用處理內核。[ 11 ]

由於其中的大量處理能力,最近的智能NIC已成為eBPF的目標。這樣,它們構成了多種用途的主要方法,包括減輕DoS攻擊並提供動態網絡路由,交換,負載平衡等。在2016年10月的NetDev 1.2大會上,Netronome的Jakub Kicinski和Nic Viljoen作了演講。標題為“將eBPF / XDP硬件卸載到SmartNICNic Viljoen在其中指出了一些非常粗糙的早期基准,即在Netronome SmartNIC上為每個FPC每秒實現300萬個數據包的基准。正如Viljoen繼續指出的那樣,每個SmartNIC都有72至120個此類FPC,給出了一個假設的(盡管可能不現實的)最大eBPF吞吐量4.3 Tbps![ 12 ]

最后,eBPF作為技術將有未來。由於eBPF的限制和簡單實現,它提供了一種高度可移植且高效的方式來處理事件。然而,更重要的是,eBPF要求改變解決問題的方式。它刪除了對象和有狀態代碼,而是僅選擇功能和有效的數據結構來存儲狀態。這種范例極大地縮小了程序設計的可能性,但是這樣做卻使其幾乎可以與任何程序設計方法兼容。因此,eBPF可以同步,異步,並行,分布式(取決於與數據存儲的協調需求)以及所有其他方式的程序設計來使用。考慮到這一事實,我認為eBPF的更合適的名稱是功能虛擬機,簡稱FVM。

eBPF可能會為將來的軟件帶來的最大技術變化是由於eBPF容易被人們遺忘:它將字節碼JIT編譯為機器代碼以執行內核空間!因此,eBPF避免了內核由於硬件隔離而給用戶空間程序帶來的巨額成本,即25%到33%之間的性能下降。[ 13 ]這意味着用戶程序可能會運行通過在內核空間虛擬機上運行, 速度提高了50%![ 14 ]實際上,這不是一個新想法。2014年,加里·伯恩哈特(Gary Bernhardt)在PyCon上做了題為 JavaScript的誕生與死亡”的有趣而有趣的演講。。Bernhardt在其中引用了相同的硬件隔離成本統計信息,他解釋說,在虛擬的將來,所有軟件中的大多數都如何在內核Javascipt虛擬機上運行。在這樣的未來中,軟件可移植性將不再是問題,因為軟件不是編譯為硬件體系結構,而是編譯為Javascript。他甚至繼續說,文檔對象模型(DOM)的實現(已保存在瀏覽器中的數據存儲,用於保存呈現網頁的狀態)也已移入內核,該內核現在在其中運行窗口系統。這在概念上與eBPF映射非常相似,eBPF映射在理論上可以在將來用於此類情況。雖然有些輕松,不可否認的是,伯恩哈特的演講是建立在可靠的事實之上的,並且對於未來由內核空間虛擬機而非硬件完成計算機程序隔離的未來可能是正確的。我們只需要等待,看看eBPF是否成為這一改變的支持者。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM