歡迎光臨
每天分享高質量文章

深入理解 BPF:一個閱讀清單 | Linux 中國

我收集了非常多的關於 BPF 的閱讀材料:介紹、檔案,也有教程或者示例。這裡有很多的材料可以去閱讀
— Quentin Monnet


致謝
編譯自 | https://qmonnet.github.io/whirl-offload/2016/09/01/dive-into-bpf/ 
 作者 | Quentin Monnet
 譯者 | qhwdw ? ? ? ? ? 共計翻譯:102 篇 貢獻時間:154 天

更新於[1] 2017-11-02 ~

什麼是 BPF?

BPF,及伯克利包過濾器Berkeley Packet Filter,最初構想提出於 1992 年,其目的是為了提供一種過濾包的方法,並且要避免從核心空間到使用者空間的無用的資料包複製行為。它最初是由從使用者空間註入到內核的一個簡單的位元組碼構成,它在那個位置利用一個校驗器進行檢查 —— 以避免核心崩潰或者安全問題 —— 並附著到一個套接字上,接著在每個接收到的包上執行。幾年後它被移植到 Linux 上,並且應用於一小部分應用程式上(例如,tcpdump)。其簡化的語言以及存在於核心中的即時編譯器(JIT),使 BPF 成為一個效能卓越的工具。

然後,在 2013 年,Alexei Starovoitov 對 BPF 進行徹底地改造,並增加了新的功能,改善了它的效能。這個新版本被命名為 eBPF (意思是 “extended BPF”),與此同時,將以前的 BPF 變成 cBPF(意思是 “classic” BPF)。新版本出現瞭如對映和尾呼叫tail call這樣的新特性,並且 JIT 編譯器也被重寫了。新的語言比 cBPF 更接近於原生機器語言。並且,在核心中建立了新的附著點。

感謝那些新的鉤子,eBPF 程式才可以被設計用於各種各樣的情形下,其分為兩個應用領域。其中一個應用領域是核心跟蹤和事件監控。BPF 程式可以被附著到探針(kprobe),而且它與其它跟蹤樣式相比,有很多的優點(有時也有一些缺點)。

另外一個應用領域是網路程式設計。除了套接字過濾器外,eBPF 程式還可以附加到 tc(Linux 流量控制工具)的入站或者出站介面上,以一種很高效的方式去執行各種包處理任務。這種使用方式在這個領域開創了一個新的天地。

並且 eBPF 透過使用為 IO Visor 專案開發的技術,使它的效能進一步得到提升:也為 XDP(“eXpress Data Path”)添加了新的鉤子,XDP 是不久前新增到核心中的一種新式快速路徑。XDP 與 Linux 棧組合,然後使用 BPF ,使包處理的速度更快。

甚至一些專案,如 P4、Open vSwitch,考慮[2] 或者開始去接洽使用 BPF。其它的一些,如 CETH、Cilium,則是完全基於它的。BPF 是如此流行,因此,我們可以預計,不久之後,將圍繞它有更多工具和專案出現 …

深入理解位元組碼

就像我一樣:我的一些工作(包括 BEBA[3])是非常依賴 eBPF 的,並且在這個網站上以後的幾篇文章將關註於這個主題。按理說,在深入到細節之前,我應該以某種方式去介紹 BPF —— 我的意思是,真正的介紹,在第一節所提供的簡要介紹上更多地介紹在 BPF 上開發的新功能:什麼是 BPF 對映?尾呼叫?內部結構是什麼樣子?等等。但是,在這個網站上已經有很多這個主題的介紹了,而且,我也不希望去寫另一篇 “BPF 介紹” 的重覆文章。

畢竟,我花費了很多的時間去閱讀和學習關於 BPF 的知識,因此,在這裡我們將要做什麼呢,我收集了非常多的關於 BPF 的閱讀材料:介紹、檔案,也有教程或者示例。這裡有很多的材料可以去閱讀,但是,為了去閱讀它,首先要去 找到 它。因此,為了能夠幫助更多想去學習和使用 BPF 的人,現在的這篇文章給出了一個資源清單。這裡有各種閱讀材料,它可以幫你深入理解核心位元組碼的機制。

資源

簡介

這篇文章中下麵的連結提供了 BPF 的基本概述,或者,一些與它密切相關的一些主題。如果你對 BPF 非常陌生,你可以在這些介紹文章中挑選出一篇你喜歡的文章去閱讀。如果你已經理解了 BPF,你可以針對特定的主題去閱讀,下麵是閱讀清單。

關於 BPF

關於 eBPF 的常規介紹

◈ 全面介紹 eBPF[4](Matt Flemming,on LWN.net,December 2017):

一篇寫的很好的,並且易於理解的,介紹 eBPF 子系統元件的概述文章。

◈ 利用 BPF 和 XDP 實現可程式設計的核心網路資料路徑[5]  (Daniel Borkmann, OSSNA17, Los Angeles, September 2017):

快速理解所有的關於 eBPF 和 XDP 的基礎概念的最好講稿中的一篇(主要是關於網路處理的)

◈ BSD 包過濾器[6] (Suchakra Sharma, June 2017): 

一篇非常好的介紹文章,主要是關於跟蹤方面的。

◈ BPF:跟蹤及更多[7](Brendan Gregg, January 2017):

主要內容是跟蹤使用案例相關的。

◈ Linux BPF 的超強功能[8] (Brendan Gregg, March 2016):

第一部分是關於火焰圖flame graph的使用。

◈ IO Visor[9](Brenden Blanco, SCaLE 14x, January 2016):

介紹了 IO Visor 專案

◈ 大型機上的 eBPF[10](Michael Holzheu, LinuxCon, Dubin, October 2015)
◈ 在 Linux 上新的(令人激動的)跟蹤新產品[11](Elena Zannoni, LinuxCon, Japan, 2015)
◈ BPF — 核心中的虛擬機器[12](Alexei Starovoitov, February 2015):

eBPF 的作者寫的一篇講稿。

◈ 擴充套件 extended BPF[13] (Jonathan Corbet, July 2014)

BPF 內部結構

◈ Daniel Borkmann 正在做的一項令人稱奇的工作,它用於去展現 eBPF 的 內部結構,尤其是,它的關於 隨同 tc 使用 的幾次演講和論文。

◈ 使用 tc 的 cls_bpf 的高階可程式設計和它的最新更新[14](netdev 1.2, Tokyo, October 2016):

Daniel 介紹了 eBPF 的細節,及其用於隧道和封裝、直接包訪問和其它特性。

◈ 自 netdev 1.1 以來的 cls_bpf/eBPF 更新[15]  (netdev 1.2, Tokyo, October 2016, part of this tc workshop[16]
◈ 使用 cls_bpf 實現完全可程式設計的 tc 分類器[17]  (netdev 1.1, Sevilla, February 2016):

介紹 eBPF 之後,它提供了許多 BPF 內部機制(對映管理、尾呼叫、校驗器)的見解。對於大多數有志於 BPF 的人來說,這是必讀的!全文在這裡[18]

◈ Linux tc 和 eBPF[19] (fosdem16, Brussels, Belgium, January 2016)
◈ eBPF 和 XDP 攻略和最新更新[20] (fosdem17, Brussels, Belgium, February 2017)

這些介紹可能是理解 eBPF 內部機制設計與實現的最佳檔案資源之一。

IO Visor 部落格[21] 有一些關於 BPF 的值得關註技術文章。它們中的一些包含了一點營銷討論。

核心跟蹤:總結了所有的已有的方法,包括 BPF:

◈ 邂逅 eBPF 和核心跟蹤[22] (Viller Hsiao, July 2016):

Kprobes、uprobes、ftrace

◈ Linux 核心跟蹤[23](Viller Hsiao, July 2016):

Systemtap、Kernelshark、trace-cmd、LTTng、perf-tool、ftrace、hist-trigger、perf、function tracer、tracepoint、kprobe/uprobe …

關於 事件跟蹤和監視,Brendan Gregg 大量使用了 eBPF,並且就其使用 eBPFR 的一些案例寫了極好的檔案。如果你正在做一些核心跟蹤方面的工作,你應該去看一下他的關於 eBPF 和火焰圖相關的部落格文章。其中的大多數都可以 從這篇文章中[24] 訪問,或者瀏覽他的部落格。

介紹 BPF,也介紹 Linux 網路的一般概念

◈ Linux 網路詳解[25] (Thomas Graf, LinuxCon, Toronto, August 2016)
◈ 核心網路攻略[26]  (Thomas Graf, LinuxCon, Seattle, August 2015)

硬體解除安裝offload(LCTT 譯註:“解除安裝”是指原本由軟體來處理的一些操作交由硬體來完成,以提升吞吐量,降低 CPU 負荷。):

◈ eBPF 與 tc 或者 XDP 一起支援硬體解除安裝,開始於 Linux 核心版本 4.9,是由 Netronome 提出的。這裡是關於這個特性的介紹:eBPF/XDP 硬體解除安裝到 SmartNICs[27](Jakub Kicinski 和 Nic Viljoen, netdev 1.2, Tokyo, October 2016)
◈ 一年後出現的更新版:

綜合 XDP 解除安裝——處理邊界案例[28](Jakub Kicinski 和 Nic Viljoen,netdev 2.2 ,Seoul,November 2017)

◈ 我現在有一個簡短的,但是在 2018 年的 FOSDEM 上有一個更新版:

XDP 硬體解除安裝的挑戰[29](Quentin Monnet,FOSDEM 2018,Brussels,February 2018)

關於 cBPF

◈ BSD 包過濾器:一個使用者級包捕獲的新架構[30] (Steven McCanne 和 Van Jacobson, 1992):

它是關於(經典)BPF 的最早的論文。

◈ BPF 的 FreeBSD 手冊[31] 是理解 cBPF 程式有用的資源。
◈ 關於 cBPF,Daniel Borkmann 做至少兩個演講,一是,在 2013 年 mmap 中,BPF 和 Netsniff-NG[32],以及 在 2014 中關於 tc 和 cls_bpf 的的一個非常完整的演講[33]
◈ 在 Cloudflare 的部落格上,Marek Majkowski 提出的他的 與 iptables 的 xt_bpf 模組一起使用 BPF 位元組碼[34]。值得一提的是,從 Linux 核心 4.10 開始,eBPF 也是透過這個模組支援的。(雖然,我並不知道關於這件事的任何討論或者文章)
◈ Libpcap 過濾器語法[35]

關於 XDP

◈ 在 IO Visor 網站上的 XDP 概述[36]
◈ eXpress Data Path (XDP)[37]  (Tom Herbert, Alexei Starovoitov, March 2016):

這是第一個關於 XDP 的演講。

◈ BoF – BPF 能為你做什麼?[38]  (Brenden Blanco, LinuxCon, Toronto, August 2016)。
◈ eXpress Data Path[39] (Brenden Blanco, Linux Meetup at Santa Clara, July 2016):

包含一些(有點營銷的意思?)基準測試結果!使用單一核心:

◈ ip 路由丟棄: ~3.6 百萬包每秒(Mpps)
◈ 使用 BPF,tc(使用 clsact qdisc)丟棄: ~4.2 Mpps
◈ 使用 BPF,XDP 丟棄:20 Mpps (CPU 利用率 < 10%)
◈ XDP 重寫轉發(在埠上它接收到的包):10 Mpps

(測試是用 mlx4 驅動程式執行的)。

◈ Jesper Dangaard Brouer 有幾個非常好的幻燈片,它可以從本質上去理解 XDP 的內部結構。

◈ XDP − eXpress Data Path,介紹及將來的用法[40] (September 2016):

“Linux 核心與 DPDK 的鬥爭” 。未來的計劃(在寫這篇文章時)它用 XDP 和 DPDK 進行比較。

◈ 網路效能研討[41]  (netdev 1.2, Tokyo, October 2016):

關於 XDP 內部結構和預期演化的附加提示。

◈ XDP – eXpress Data Path, 可用於 DDoS 防護[42] (OpenSourceDays, March 2017):

包含了關於 XDP 的詳細情況和使用案例,以及 效能測試 的 效能測試結果 和 程式碼片斷,以及使用 eBPF/XDP(基於一個 IP 黑名單樣式)的用於 基本的 DDoS 防護

◈ 記憶體 vs. 網路,激發和修複記憶體瓶頸[43] (LSF Memory Management Summit, March 2017):

提供了許多 XDP 開發者當前所面對 記憶體問題 的許多細節。不要從這一個開始,但如果你已經理解了 XDP,並且想去瞭解它在頁面分配方面的真實工作方式,這是一個非常有用的資源。

◈ XDP 能為其它人做什麼[44](netdev 2.1, Montreal, April 2017),及 Andy Gospodarek:

普通人怎麼開始使用 eBPF 和 XDP。這個演講也由 Julia Evans 在 她的部落格[45]上做了總結。

◈ XDP 能為其它人做什麼[46],第二版(netdev 2.2, Seoul, November 2017),同一個作者:

該演講的修訂版本,包含了新的內容。

(Jesper 也建立了並且嘗試去擴充套件了有關 eBPF 和 XDP 的一些檔案,檢視 相關節[47]。)

◈ XDP 研討 — 介紹、體驗和未來發展[48](Tom Herbert, netdev 1.2, Tokyo, October 2016)

在這篇文章中,只有影片可用,我不知道是否有幻燈片。

◈ 在 Linux 上進行高速包過濾[49] (Gilberto Bertin, DEF CON 25, Las Vegas, July 2017)

在 Linux 上的最先進的包過濾的介紹,面向 DDoS 的保護、討論了關於在核心中進行包處理、核心旁通、XDP 和 eBPF。

關於 基於 eBPF 或者 eBPF 相關的其它元件

◈ 在邊界上的 P4[50] (John Fastabend, May 2016):

提出了使用 P4,一個包處理的描述語言,使用 BPF 去建立一個高效能的可程式設計交換機。

◈ 如果你喜歡音訊的演講,這裡有一個相關的 OvS Orbit 片斷(#11),叫做 在邊界上的 P4[51],日期是 2016 年 8 月。OvS Orbit 是對 Ben Pfaff 的訪談,它是 Open vSwitch 的其中一個核心維護者。在這個場景中,John Fastabend 是被訪談者。
◈ P4, EBPF 和 Linux TC 解除安裝[52] (Dinan Gunawardena 和 Jakub Kicinski, August 2016):

另一個 P4 的演講,一些有關於 Netronome 的 NFP(網路流處理器)架構上的 eBPF 硬體解除安裝的因素。

◈ Cilium 是一個由 Cisco 最先發起的技術,它依賴 BPF 和 XDP 去提供 “基於 eBPF 程式即時生成的,用於容器的快速核心強制的網路和安全策略”。這個專案的程式碼[53] 在 GitHub 上可以訪問到。Thomas Graf 對這個主題做了很多的演講:

◈ Cilium:對容器利用 BPF & XDP 實現網路 & 安全[54],也特別展示了一個負載均衡的使用案例(Linux Plumbers conference, Santa Fe, November 2016)
◈ Cilium:對容器利用 BPF & XDP 實現網路 & 安全[55] (Docker Distributed Systems Summit, October 2016 — video[56]
◈ Cilium:使用 BPF 和 XDP 的快速 IPv6 容器網路[57] (LinuxCon, Toronto, August 2016)
◈ Cilium: 用於容器的 BPF & XDP[58] (fosdem17, Brussels, Belgium, February 2017)

在上述不同的演講中重覆了大量的內容;嫌麻煩就選最近的一個。Daniel Borkmann 作為 Google 開源部落格的特邀作者,也寫了 Cilium 簡介[59]

◈ 這裡也有一個關於 Cilium 的播客節目:一個是 OvS Orbit episode (#4)[60],它是 Ben Pfaff 訪談 Thomas Graf (2016 年 5 月),和 另外一個 Ivan Pepelnjak 的播客[61],仍然是 Thomas Graf 關於 eBPF、P4、XDP 和 Cilium 方面的(2016 年 10 月)。
◈ Open vSwitch (OvS),它是 Open Virtual Network(OVN,一個開源的網路虛擬化解決方案)相關的專案,正在考慮在不同的層次上使用 eBPF,它已經實現了幾個概念驗證原型:

◈ 使用 eBPF 解除安裝 OVS 流處理器[62] (William (Cheng-Chun) Tu, OvS conference, San Jose, November 2016)
◈ 將 OVN 的靈活性與 IOVisor 的高效率相結合[63] (Fulvio Risso, Matteo Bertrone 和 Mauricio Vasquez Bernal, OvS conference, San Jose, November 2016)

據我所知,這些 eBPF 的使用案例看上去僅處於提議階段(並沒有合併到 OvS 的主分支中),但是,看它帶來了什麼將是非常值得關註的事情。

◈ XDP 的設計對分散式拒絕訪問(DDoS)攻擊是非常有用的。越來越多的演講都關註於它。例如,在 2017 年 4 月加拿大蒙特利爾舉辦的 netdev 2.1 會議上,來自 Cloudflare 的人們的講話(XDP 實踐:將 XDP 整合到我們的 DDoS 緩解管道[64])或者來自 Facebook 的(Droplet:由 BPF + XDP 驅動的 DDoS 對策[65])都存在這樣的很多使用案例。
◈ Kubernetes 可以用很多種方式與 eBPF 互動。這裡有一篇關於 在 Kubernetes 中使用 eBPF[66] 的文章,它解釋了現有的產品(Cilium、Weave Scope)如何支援 eBPF 與 Kubernetes 一起工作,並且進一步描述了,在容器部署環境中,eBPF 感興趣的互動內容是什麼。
◈ CETH for XDP[67] (Yan Chan 和 Yunsong Lu、Linux Meetup、Santa Clara、July 2016):

CETH,是由 Mellanox 發起的,為實現更快的網路 I/O 而主張的通用乙太網驅動程式架構。

◈ VALE 交換機[68],另一個虛擬交換機,它可以與 netmap 框架結合,有 一個 BPF 擴充套件模組[69]
◈ Suricata,一個開源的入侵檢測系統,它的旁路捕獲旁特性依賴於 XDP。有一些關於它的資源:

◈ Suricate 檔案的 eBPF 和 XDP 部分[70]
◈ SEPTun-Mark-II[71] (Suricata Extreme 效能調優指南 — Mark II), Michal Purzynski 和 Peter Manev 釋出於 2018 年 3 月。
◈ 介紹這個特性的部落格文章[72] Éric Leblond 釋出於 2016 年 9 月。
◈ Suricate 的 eBPF 歷險記[73]  (Éric Leblond, netdev 1.2, Tokyo, October 2016)
◈ eBPF 和 XDP 一窺[74]  (Éric Leblond, Kernel Recipes, Paris, September 2017)

當使用原生驅動的 XDP 時,這個專案要求實現非常高的效能。

◈ InKeV:對於 DCN 的核心中分散式網路虛擬化[75] (Z. Ahmed, M. H. Alizai 和 A. A. Syed, SIGCOMM, August 2016):

InKeV 是一個基於 eBPF 的虛擬網路、標的資料中心網路的資料路徑架構。它最初由 PLUMgrid 提出,並且聲稱相比基於 OvS 的 OpenStack 解決方案可以獲得更好的效能。

◈ gobpf – 在 Go 中使用 eBPF[76] (Michael Schubert, fosdem17, Brussels, Belgium, February 2017):

“一個來自 Go 庫,可以去建立、載入和使用 eBPF 程式”

◈ ply[77] 是為 Linux 實現的一個小而靈活的開源動態 跟蹤器,它的一些特性非常類似於 bcc 工具,是受 awk 和 dtrace 啟發,但使用一個更簡單的語言。它是由 Tobias Waldekranz 寫的。
◈ 如果你讀過我以前的文章,你可能對我在這篇文章中的討論感興趣,使用 eBPF 實現 OpenState 介面[78],關於包狀態處理,在 fosdem17 中。

檔案

一旦你對 BPF 是做什麼的有一個大體的理解。你可以拋開一般的演講而深入到檔案中了。下麵是 BPF 的規範和功能的最全面的檔案,按你的需要挑一個開始閱讀吧!

關於 BPF

◈ BPF 的規範(包含 classic 和 extended 版本)可以在 Linux 內核的檔案中,和特定的檔案 linux/Documentation/networking/filter.txt[79] 中找到。BPF 使用以及它的內部結構也被記錄在那裡。此外,當載入 BPF 程式碼失敗時,在這裡可以找到 被校驗器丟擲的錯誤資訊,這有助於你排除不明確的錯誤資訊。
◈ 此外,在核心樹中,在 eBPF 那裡有一個關於 常見問答 的檔案,它在檔案 linux/Documentation/bpf/bpf_design_QA.txt[80] 中。
◈ … 但是,核心檔案是非常難懂的,並且非常不容易閱讀。如果你只是去查詢一個簡單的 eBPF 語言的描述,可以去 IO Visor 的 GitHub 倉庫,那兒有 它的概括性描述[81]
◈ 順便說一下,IO Visor 專案收集了許多 關於 BPF 的資源。大部分分別在 bcc 倉庫的 檔案目錄[82] 中,和 bpf-docs 倉庫[83] 的整個內容中,它們都在 GitHub 上。註意,這個非常好的 BPF 參考指南[84] 包含一個詳細的 BPF C 和 bcc Python 的 helper 的描述。
◈ 想深入到 BPF,那裡有一些必要的 Linux 手冊頁。第一個是 bpf(2) man 頁面[85] 關於 bpf() 系統呼叫,它用於從使用者空間去管理 BPF 程式和對映。它也包含一個 BPF 高階特性的描述(程式型別、對映等等)。第二個是主要是處理希望附加到 tc 介面的 BPF 程式:它是 tc-bpf(8) man 頁面[86],是 使用 BPF 和 tc 的一個參考,並且包含一些示例命令和參考程式碼。
◈ Jesper Dangaard Brouer 發起了一個 更新 eBPF Linux 檔案 的嘗試,包含 不同的對映他有一個草案[87],歡迎去貢獻。一旦完成,這個檔案將被合併進 man 頁面並且進入到核心檔案。
◈ Cilium 專案也有一個非常好的 BPF 和 XDP 參考指南[88],它是由核心的 eBPF 開發者寫的,它被證明對於 eBPF 開發者是極其有用的。
◈ David Miller 在 xdp-newbies[89] 郵件串列中發了幾封關於 eBPF/XDP 內部結構的富有啟發性的電子郵件。我找不到一個單獨的地方收集它們的連結,因此,這裡是一個串列:

◈ bpf.h 和你 …[90]
◈ 從語境上講…[91]
◈ BPF 校驗器概述[92]

最後一個可能是目前來說關於校驗器的最佳的總結。

◈ Ferris Ellis 釋出的 一個關於 eBPF 的系列部落格文章[93]。作為我寫的這個短文,第一篇文章是關於 eBPF 的歷史背景和未來期望。接下來的文章將更多的是技術方面,和前景展望。
◈ 每個核心版本的 BPF 特性串列[94] 在 bcc 倉庫中可以找到。如果你想去知道執行一個給定的特性所要求的最小的核心版本,它是非常有用的。我貢獻和添加了連結到提交中,它介紹了每個特性,因此,你也可以從那裡很容易地去訪問提交歷史。

關於 tc

當為了網路目的結合使用 BPF 與 tc (Linux 流量控制traffic control工具)時,它可用於收集 tc 的常規功能的資訊。這裡有幾個關於它的資源。

◈ 找到關於 Linux 上 QoS 的簡單教程是很困難的。這裡有兩個連結,它們很長而且很難懂,但是,如果你可以抽時間去閱讀它,你將學習到幾乎關於 tc 的任何東西(雖然,沒有什麼關於 BPF 的)。它們在這裡:怎麼去實現流量控制  (Martin A. Brown, 2006)[95],和 怎麼去實現 Linux 的高階路由 & 流量控制 (LARTC) (Bert Hubert & al., 2002)[96]
◈ 在你的系統上的 tc 手冊頁面 並不是最新的,因為它們中的幾個最近已經增加了內容。如果你沒有找到關於特定的佇列規則、分類或者過濾器的檔案,它可能在最新的 tc 元件的手冊頁面[97] 中。
◈ 一些額外的材料可以在 iproute2 包自已的檔案中找到:這個包中有 一些檔案[98],包括一些檔案,它可以幫你去理解 tc 的 action 的功能[99]

註意: 這些檔案在 2017 年 10 月 已經從 iproute2 中刪除,然而,從 Git 歷史中卻一直可用。

◈ 不完全是檔案:有一個關於 tc 的幾個特性的研討會[16](包含過濾、BPF、tc 解除安裝、…) 由 Jamal Hadi Salim 在 netdev 1.2 會議上組織的(October 2016)。
◈ 額外資訊 — 如果你使用 tc 較多,這裡有一些好訊息:我用這個工具 寫了一個 bash 補完功能[100],並且它被包 iproute2 帶到核心版本 4.6 和更高版中!

關於 XDP

◈ 對於 XDP 的一些 進展中的檔案(包括規範)[101] 已經由 Jesper Dangaard Brouer 啟動,並且意味著將成為一個協作工作。正在推進的(2016 年 9 月):你期望它去改變,並且或許在一些節點上移動(Jesper 稱為貢獻[102],如果你想去改善它)。
◈ 自來 Cilium 專案的 BPF 和 XDP 參考指南[88] … 好吧,這個名字已經說明瞭一切。

關於 P4 和 BPF

P4[103] 是一個用於指定交換機行為的語言。它可以為多種標的硬體或軟體編譯。因此,你可能猜到了,這些標的中的一個就是 BPF … 僅部分支援的:一些 P4 特性並不能被轉化到 BPF 中,並且,用類似的方法,BPF 可以做的事情,而使用 P4 卻不能表達出現。不過,P4 與 BPF 使用 的相關檔案,被隱藏在 bcc 倉庫中[104]。這個改變在 P4_16 版本中,p4c 取用的編輯器包含 一個 eBPF 後端[105]

教程

Brendan Gregg 為想要 使用 bcc 工具 跟蹤和監視核心中的事件的人製作了一個非常好的 教程第一個教程是關於如何使用 bcc 工具[84],它有許多章節,可以教你去理解怎麼去使用已有的工具,而 針對 Python 開發者的一篇[106] 專註於開發新工具,它總共有十七節 “課程”。

Sasha Goldshtein 也有一些 Linux 跟蹤研究材料[107] 涉及到使用幾個 BPF 工具進行跟蹤。

Jean-Tiare Le Bigot 的另一篇文章提供了一個詳細的(和有指導意義的)使用 perf 和 eBPF 去設定一個低階的跟蹤器[108] 的示例。

對於網路相關的 eBPF 使用案例也有幾個教程。有一些值得關註的檔案,包括一篇 eBPF 解除安裝入門指南,是關於在 Open NFP[109] 平臺上用 Netronome 操作的。其它的那些,來自 Jesper 的演講,XDP 能為其它人做什麼[44](及其第二版[46]),可能是 XDP 入門的最好的方法之一。

示例

有示例是非常好的。看看它們是如何工作的。但是 BPF 程式示例是分散在幾個專案中的,因此,我列出了我所知道的所有的示例。示例並不是總是使用相同的 helper(例如,tc 和 bcc 都有一套它們自己的 helper,使它可以很容易地去用 C 語言寫 BPF 程式)

來自內核的示例

核心中包含了大多數型別的程式:過濾器系結到套接字或者 tc 介面、事件跟蹤/監視、甚至是 XDP。你可以在 linux/samples/bpf/[110] 目錄中找到這些示例。

現在,更多的示例已經作為單元測試被新增到 linux/tools/testing/selftests/bpf[111] 目錄下,這裡麵包含對硬體解除安裝的測試或者對於 libbpf 的測試。

Jesper 的 Dangaard Brouer 在他的 prototype-kernel[112] 倉庫中也維護了一套專門的示例。 這些示例與那些核心中提供的示例非常類似,但是它們可以脫離核心架構(Makefile 和頭檔案)編譯。

也不要忘記去看一下 git 相關的提交歷史,它們介紹了一些特定的特性,也許包含了一些特性的詳細示例。

來自包 iproute2 的示例

iproute2 包也提供了幾個示例。它們都很明顯地偏向網路程式設計,因此,這個程式是附著到 tc 入站或者出站介面上。這些示例在 iproute2/examples/bpf/[113] 目錄中。

來自 bcc 工具集的示例

許多示例都是 與 bcc 一起提供的[114]

◈ 一些網路的示例放在相關的目錄下麵。它們包括套接字過濾器、tc 過濾器、和一個 XDP 程式。
◈ tracing 目錄包含許多 跟蹤程式設計 的示例。前面的教程中提到的都在那裡。那些程式涉及了很大部分的事件監視功能,並且,它們中的一些是面向生產系統的。註意,某些 Linux 發行版(至少是 Debian、Ubuntu、Fedora、Arch Linux)、這些程式已經被 打包了[115] 並且可以很 “容易地” 透過比如 # apt install bcc-tools 進行安裝。但是在寫這篇文章的時候(除了 Arch Linux),首先要求安裝 IO Visor 的包倉庫。
◈ 也有一些 使用 Lua 作為一個不同的 BPF 後端(那是因為 BPF 程式是用 Lua 寫的,它是 C 語言的一個子集,它允許為前端和後端使用相同的語言)的一些示例,它在第三個目錄中。
◈ 當然,bcc 工具[116] 自身就是 eBPF 程式使用案例的值得關註示例。

手冊頁面

雖然 bcc 一般很容易在核心中去註入和執行一個 BPF 程式,將程式附著到 tc 介面也能透過 tc 工具自己完成。因此,如果你打算將 BPF 與 tc 一起使用,你可以在 tc-bpf(8) 手冊頁面[86] 中找到一些呼叫示例。

程式碼

有時候,BPF 檔案或者示例並不夠,而且你只想在你喜歡的文字編輯器(它當然應該是 Vim)中去顯示程式碼並去閱讀它。或者,你可能想深入到程式碼中去做一個補丁程式或者為機器增加一些新特性。因此,這裡對有關的檔案的幾個建議,找到你想要的函式只取決於你自己!

在核心中的 BPF 程式碼

◈ 檔案 linux/include/linux/bpf.h[117] 及其相對的 linux/include/uapi/bpf.h[118] 包含有關 eBPF 的 定義,它們分別用在核心中和使用者空間程式的介面。
◈ 相同的方式,檔案 linux/include/linux/filter.h[119] 和 linux/include/uapi/filter.h[120] 包含了用於 執行 BPF 程式 的資訊。
◈ BPF 相關的 主要的程式碼片斷 在 linux/kernel/bpf/[121] 目錄下麵。系統呼叫的不同操作許可,比如,程式載入或者對映管理是在檔案 syscall.c 中實現,而 core.c 包含了 解析器。其它檔案的命名顯而易見:verifier.c 包含 校驗器(不是開玩笑的),arraymap.c 的程式碼用於與陣列型別的 對映 互動,等等。
◈ 有幾個與網路(及 tc、XDP )相關的函式和 helpers 是使用者可用,其實現在 linux/net/core/filter.c[122] 中。它也包含了移植 cBPF 位元組碼到 eBPF 的程式碼(因為在執行之前,核心中的所有的 cBPF 程式被轉換成 eBPF)。
◈ 相關於 事件跟蹤 的函式和 helpers 都在 linux/kernel/trace/bpf_trace.c[123] 中。
◈ JIT 編譯器 在它們各自的架構目錄下麵,比如,x86 架構的在 linux/arch/x86/net/bpfjitcomp.c[124] 中。例外是用於硬體解除安裝的 JIT 編譯器,它們放在它們的驅動程式下,例如 Netronome NFP 網絡卡的就放在 linux/drivers/net/ethernet/netronome/nfp/bpf/jit.c[125] 。
◈ 在 linux/net/sched/[126] 目錄下,你可以找到 tc 的 BPF 元件 相關的程式碼,尤其是在檔案 act_bpf.c (action)和 cls_bpf.c(filter)中。
◈ 我並沒有在 BPF 上深入到 事件跟蹤 中,因此,我並不真正瞭解這些程式的鉤子。在 linux/kernel/trace/bpf_trace.c[123] 那裡有一些東西。如果你對它感 興趣,並且想去瞭解更多,你可以在 Brendan Gregg 的演示或者部落格文章上去深入挖掘。
◈ 我也沒有使用過 seccomp-BPF,不過你能在 linux/kernel/seccomp.c[127] 找到它的程式碼,並且可以在 linux/tools/testing/selftests/seccomp/seccomp_bpf.c[128] 中找到一些它的使用示例。

XDP 鉤子程式碼

一旦裝載進內核的 BPF 虛擬機器,由一個 Netlink 命令將 XDP 程式從使用者空間鉤入到核心網路路徑中。接收它的是在 linux/net/core/dev.c[129] 檔案中的 dev_change_xdp_fd() 函式,它被呼叫並設定一個 XDP 鉤子。鉤子被放在支援的網絡卡的驅動程式中。例如,用於 Netronome 硬體鉤子的 ntp 驅動程式實現放在 drivers/net/ethernet/netronome/nfp/[130]中。檔案 nfp_net_common.c 接受 Netlink 命令,並呼叫 nfp_net_xdp_setup(),它會轉而呼叫 nfp_net_xdp_setup_drv() 實體來安裝該程式。

在 bcc 中的 BPF 邏輯

在 bcc 的 GitHub 倉庫[131] 能找到的 bcc 工具集的程式碼。其 Python 程式碼,包含在 BPF 類中,最初它在檔案 bcc/src/python/bcc/__init__.py[132] 中。但是許多我覺得有意思的東西,比如,載入 BPF 程式到核心中,出現在 libbcc 的 C 庫[133]中。

使用 tc 去管理 BPF 的程式碼

當然,這些程式碼與 iproute2 包中的 tc 中的 BPF 相關。其中的一些在 iproute2/tc/[134] 目錄中。檔案 f_bpf.c 和 m_bpf.c(和 e_bpf.c)各自用於處理 BPF 的過濾器和動作的(和 tc exec 命令,等等)。檔案 q_clsact.c 定義了為 BPF 特別建立的 clsactqdisc。但是,大多數的 BPF 使用者空間邏輯 是在 iproute2/lib/bpf.c[135] 庫中實現的,因此,如果你想去使用 BPF 和 tc,這裡可能是會將你搞混亂的地方(它是從檔案 iproute2/tc/tc_bpf.c 中移動而來的,你也可以在舊版本的包中找到相同的程式碼)。

BPF 實用工具

核心中也帶有 BPF 相關的三個工具的原始碼(bpf_asm.c、 bpf_dbg.c、 bpf_jit_disasm.c),根據你的版本不同,在 linux/tools/net/[136] (直到 Linux 4.14)或者 linux/tools/bpf/[137] 目錄下麵:

◈ bpf_asm 是一個極小的 cBPF 彙編程式。
◈ bpf_dbg 是一個很小的 cBPF 程式除錯器。
◈ bpf_jit_disasm 對於兩種 BPF 都是通用的,並且對於 JIT 除錯來說非常有用。
◈ bpftool 是由 Jakub Kicinski 寫的通用工具,它可以與 eBPF 程式互動並從使用者空間的對映,例如,去展示、轉儲、pin 程式、或者去展示、建立、pin、更新、刪除對映。

閱讀在源檔案頂部的註釋可以得到一個它們使用方法的概述。

與 eBPF 一起工作的其它必需的檔案是來自核心樹的兩個使用者空間庫,它們可以用於管理 eBPF 程式或者對映來自外部的程式。這個函式可以透過 linux/tools/lib/bpf/[138] 目錄中的頭檔案 bpf.h 和 libbpf.h(更高層面封裝)來訪問。比如,工具 bpftool 主要依賴這些庫。

其它值得關註的部分

如果你對關於 BPF 的不常見的語言的使用感興趣,bcc 包含 一個 BPF 標的的 P4 編譯器[139]以及 一個 Lua 前端[140],它可以被用以代替 C 的一個子集,並且(用 Lua )替代 Python 工具。

LLVM 後端

這個 BPF 後端用於 clang / LLVM 將 C 編譯到 eBPF ,是在 這個提交[141] 中新增到 LLVM 原始碼的(也可以在 這個 GitHub 映象[142] 上訪問)。

在使用者空間中執行

到目前為止,我知道那裡有至少兩種 eBPF 使用者空間實現。第一個是 uBPF[143],它是用 C 寫的。它包含一個解析器、一個 x86_64 架構的 JIT 編譯器、一個彙編器和一個反彙編器。

uBPF 的程式碼似乎被重用來產生了一個 通用實現[144],其聲稱支援 FreeBSD 核心、FreeBSD 使用者空間、Linux 核心、Linux 使用者空間和 Mac OSX 使用者空間。它被 VALE 交換機的 BPF 擴充套件模組[69]使用。

其它使用者空間的實現是我做的:rbpf[145],基於 uBPF,但是用 Rust 寫的。寫瞭解析器和 JIT 編譯器 (Linux 下兩個都有,Mac OSX 和 Windows 下僅有解析器),以後可能會有更多。

提交日誌

正如前面所說的,如果你希望得到更多的關於一些特定的 BPF 特性的資訊,不要猶豫,去看一些提交日誌。你可以在許多地方搜尋日誌,比如,在 git.kernel.org[146]在 GitHub 上[147]、或者如果你克隆過它還有你的本地倉庫中。如果你不熟悉 git,你可以嘗試像這些去做 git blame  去看看介紹特定程式碼行的提交內容,然後,git show  去看詳細情況(或者在 git log 的結果中按關鍵字搜尋,但是這樣做通常比較單調乏味)也可以看在 bcc 倉庫中的 按核心版本區分的 eBPF 特性串列[94],它連結到相關的提交上。

排錯

對 eBPF 的追捧是最近的事情,因此,到目前為止我還找不到許多關於怎麼去排錯的資源。所以這裡只有幾個,是我在使用 BPF 進行工作的時候,對自己遇到的問題進行的記錄。

編譯時的錯誤

◈ 確保你有一個最新的 Linux 核心版本(也可以看 這個檔案[94])。
◈ 如果你自己編譯核心:確保你安裝了所有正確的元件,包括核心映象、頭檔案和 libc。
◈ 當使用 tc-bpf(用於去編譯 C 程式碼到 BPF 中)的 man 頁面提供的 bcc shell 函式時:我曾經必須新增包含 clang 呼叫的頭檔案:

  1. __bcc() {

  2.        clang -O2 -I "/usr/src/linux-essay-headers-$(uname -r)/include/" \

  3.                  -I "/usr/src/linux-essay-headers-$(uname -r)/arch/x86/include/" \

  4.                -emit-llvm -c $1 -o - | \

  5.        llc -march=bpf -filetype=obj -o "`basename $1 .c`.o"

  6. }

(現在似乎修複了)。

◈ 對於使用 bcc 的其它問題,不要忘了去看一看這個工具集的 答疑[148]
◈ 如果你從一個並不精確匹配你的核心版本的 iproute2 包中下載了示例,可能會由於在檔案中包含的頭檔案觸發一些錯誤。這些示例片斷都假設安裝在你的系統中內核的頭檔案與 iproute2 包是相同版本的。如果不是這種情況,下載正確的 iproute2 版本,或者編輯示例中包含的檔案的路徑,指向到 iproute2 中包含的頭檔案上(在執行時一些問題可能或者不可能發生,取決於你使用的特性)。

在載入和執行時的錯誤

◈ 使用 tc 去載入一個程式,確保你使用了一個與使用中的核心版本等價的 iproute2 中的 tc 二進位制檔案。
◈ 使用 bcc 去載入一個程式,確保在你的系統上安裝了 bcc(僅下載原始碼去執行 Python 指令碼是不夠的)。
◈ 使用 tc,如果 BPF 程式不能傳回一個預期值,檢查呼叫它的方式:過濾器,或者動作,或者使用 “直傳” 樣式的過濾器。
◈ 還是 tc,註意不使用過濾器,動作不會直接附著到 qdiscs 或者介面。
◈ 透過核心校驗器丟擲錯誤到解析器可能很難。核心檔案[79]或許可以提供幫助,因此,可以 參考指南[84] 或者,萬不得一的情況下,可以去看原始碼(祝你好運!)。記住,校驗器 不執行 程式,對於這種型別的錯誤,記住這點是非常重要的。如果你得到一個關於無效記憶體訪問或者關於未初始化的資料的錯誤,它並不意味著那些問題真實發生了(或者有時候是,它們完全有可能發生)。它意味著你的程式是以校驗器預計可能發生錯誤的方式寫的,並且因此而拒絕這個程式。
◈ 註意 tc 工具有一個 verbose 樣式,它與 BPF 一起工作的很好:在你的命令列尾部嘗試追加一個 verbose
◈ bcc 也有一個 verbose 選項:BPF 類有一個 debug 引數,它可以帶 DEBUG_LLVM_IRDEBUG_BPF 和 DEBUG_PREPROCESSOR 三個標誌中任何組合(詳細情況在 源檔案[132]中)。 為除錯該程式碼,它甚至嵌入了 一些條件去列印輸出程式碼[149]
◈ LLVM v4.0+ 為 eBPF 程式 嵌入一個反彙編器[150]。因此,如果你用 clang 編譯你的程式,在編譯時新增 -g 標誌允許你透過核心校驗器去以人類可讀的格式去轉儲你的程式。處理轉儲檔案,使用:

  1. $ llvm-objdump -S -no-show-raw-insn bpf_program.o

◈ 使用對映?你應該去看看 bpf-map[151],這是一個為 Cilium 專案而用 Go 建立的非常有用的工具,它可以用於去轉儲核心中 eBPF 對映的內容。也有一個用 Rust 開發的 克隆[152]
◈ 在 StackOverflow 上有個舊的 bpf 標簽[153],但是,在這篇文章中從沒用過它(並且那裡幾乎沒有與新版本的 eBPF 相關的東西)。如果你是一位來自未來的閱讀者,你可能想去看看在這方面是否有更多的活動(LCTT 譯註:意即只有舊東西)。

更多!

◈ 如果你想輕鬆地 測試 XDP,有 一個配置好的 Vagrant [154] 可以使用。你也可以 在 Docker 容器中[155] 測試 bcc
◈ 想知道 BPF 的 開發和活動 在哪裡嗎?好吧,核心補丁總是出自於 netdev 上的郵件串列[156](相關 Linux 內核的網路棧開發):以關鍵字 “BPF” 或者 “XDP” 來搜尋。自 2017 年 4 月開始,那裡也有 一個專門用於 XDP 程式設計的郵件串列[89](是為了架構或者尋求幫助)。在 IO Visor 的郵件串列上[157]也有許多的討論和辨論,因為 BPF 是一個重要的專案。如果你只是想隨時瞭解情況,那裡也有一個 @IOVisor Twitter 帳戶[158]

請經常會回到這篇部落格[159]中,來看一看 關於 BPF[160] 有沒有新的文章!

特別感謝 Daniel Borkmann 指引我找到了 更多的檔案[161],因此我才完成了這個合集。


via: https://qmonnet.github.io/whirl-offload/2016/09/01/dive-into-bpf/

作者:Quentin Monnet[162] 譯者:qhwdw 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出

贊(0)

分享創造快樂