LWN: 實現(xiàn)針對Windows的eBPF!
關(guān)注了就能看到更多這么棒的文章哦~
Implementing eBPF for Windows
June 10, 2021
This article was contributed by Quentin Monnet
DeepL assisted translation
https://lwn.net/Articles/857215/
Extended BPF(eBPF)是 Linux 內(nèi)核中的一個通用執(zhí)行引擎(general-purpose execution engine),有助于追蹤和監(jiān)控系統(tǒng)行為、處理網(wǎng)絡(luò)數(shù)據(jù)包、或者其他一些有助于擴展內(nèi)核功能的行為。事實上,它是如此有用,以至于連其他操作系統(tǒng)上的開發(fā)者都在關(guān)注它。Dave Thaler 和 Poorna Gaddehosur,最近代表微軟發(fā)表了一個 Windows 中的 eBPF 實現(xiàn)版本。一個 Linux 功能進入了 Windows,這本身就值得關(guān)注。尤其是該功能在過去幾年中給 Linux 內(nèi)核增加了新的編程可能性,這使得我們特別有興趣看看這個新項目能做些什么,并思考當(dāng) eBPF 開始向 Windows 進軍時,當(dāng)前的生態(tài)系統(tǒng)會如何發(fā)展。
Gearing up with open-source components(開源組件的準備工作)
該項目直接命名為 "eBPF for Windows",希望用于 Windows 10 和 Windows Server 2016(及更高版本)。它不是從 Linux 代碼直接 fork 出來的,可能是為了避免 GPL 相關(guān)擔(dān)憂。因此 Windows 版本實際上是另一個不同的實現(xiàn)。不過并不是從頭開始,而是依賴于已經(jīng)存在的一些開源組件,然后增加了缺失的部分,以及必要的銜接邏輯以使這些組件相互配合并與 Windows 底層集成起來。它的代碼在 GitHub 上以 Ebpf-for-windows 的名字提供了出來,采用的是 MIT 許可。
這些組件之一是 uBPF,這是一個獨立的用戶空間 eBPF 解釋器以及 x86_64 版本的 eBPF 即時編譯器(JIT,just-in-time)。在 2015 年,也就是 eBPF 初期,uBPF 作為該技術(shù)的一個非 GPL 實現(xiàn)被創(chuàng)造出來。在那之后它的開發(fā)進展很少。但還是有幾個項目(包括 DPDK),重用了它的代碼。Windows 項目則將 uBPF 作為一個 Git submodule,并直接用 #include 方式使用了它的代碼來把解釋器和 JIT 編譯器嵌入進來。uBPF 只支持基本的 BPF program,ebpf-for-windows 增加的代碼對其進行了擴展,例如實現(xiàn) eBPF maps 以及相關(guān)的 helper 函數(shù)。
在 Windows 上處理 eBPF program 的相關(guān)工具對于 Linux 用戶來說應(yīng)該會感到很熟悉。Clang/LLVM 這些后端仍然被用來將 C 語言編寫的代碼編譯為 eBPF 字節(jié)碼指令。netsh 命令行工具提供了程序管理和內(nèi)?。╬rogram management and introspection)在某種程度上類似于 bpftool,它依賴一個提供了與 libbpf 兼容 API 的共享庫,從而確保 loader applications 可以移植。
該項目還使用的最后一個組成部分是 PREVAIL verifier,是另一個被拉入 ebpf-for-windows 項目中的 Git submodule。PREVAIL 是作為 VMware Research 參與的研究項目的一部分而開發(fā)的,在隨附文檔中有很好的介紹(注意,有些內(nèi)容現(xiàn)在已經(jīng)過時了)。與 Linux 的 verifier 不同,它依賴于形式化方法(formal method)來確定程序的安全性。它使用了一個抽象的解釋層,在幾個執(zhí)行 stream 的 rejoin 之后來聚合狀態(tài),舉例來說,if/else 塊的不同分支的寄存器的狀態(tài)在該塊的最后被合并在一起,以避免產(chǎn)生太多的執(zhí)行路徑組合。
而 Linux verifier 則獨立檢查所有的路徑:兩個連續(xù)的 if/else 代碼塊會產(chǎn)生四條路徑,從而迅速導(dǎo)致 "路徑爆炸"。但 Linux 驗證器會通過 "修剪(pruning)" 已知的安全路徑的某些部分來緩解這個問題,假如這條路徑已經(jīng)完成并從另一個分支驗證過了的話。
據(jù)稱,PREVAIL 在識別有效程序方面比 Linux verifier 更好,也包括對帶有循環(huán)語句的程序的處理。它還能更好地隨著復(fù)雜性地增加來相應(yīng)擴展(scale),并能驗證一些 Linux 因為其超過 100 萬個驗證狀態(tài)而導(dǎo)致無法驗證的 program。然而,當(dāng) Linux verifier 收到一個 BPF program 時,它能更快地完成驗證,而且消耗的內(nèi)存也更少。而且它還經(jīng)過精心定制以支持 BPF program 可以使用到的所有功能和 corner case 的,PREVAIL 則還缺乏對幾種情況的檢查,比如 eBPF-to-eBPF function call、數(shù)據(jù)包重新分配(當(dāng)數(shù)據(jù)包的 size 改變時)、以及 32-bit subregister tracking。PREVAIL 還正在積極開發(fā)中,Thaler 目前在跟 PREVAIL 的創(chuàng)建者和維護者 Elazar Gershuni 一起在進行改進。他們打算共同來解決其中的一些缺陷,比如最近就支持了 eBPF program 的 termination(終止)的檢查。
Taking marks(打分)
有了這些組件之后,eBPF for Windows 就具有了一個可以正常工作的 eBPF runtime。但該項目還處于起步階段。目前只支持兩個 eBPF hook,也就是 XDP(用于 fast packet processing)和 socket binding(相當(dāng)于 Linux 中的 BPF_CGROUP_INET4_BIND 等相關(guān)掛載點)。它也實現(xiàn)了最基本的 map type:array 以及 hash maps。
代碼倉庫中也存儲庫包含一些例子。其中的 Getting Started guide 介紹了如何設(shè)置 XDP program 實現(xiàn)把不帶有有效 payload 的 UDP 數(shù)據(jù)包丟棄從而保護 DNS 服務(wù)器免受 UDP flood 攻擊。另一個示例程序是連接到 socket binding 相關(guān)的 hook 上,可以被配置為對進程可以 bind 的 socket 數(shù)量進行限制。該 program 會在 bind 和 unbind 操作過程中來對每個進程的 counter(存放在一個 map 中)進行加一或者減一操作。
Picking a direction
這些例子都很簡單,不過這個項目也才剛剛開始。它的后續(xù)方向是什么?作者在他們的博文中明確表示,目標是能提供與 Linux eBPF 的良好兼容:"目的是為適用于各種操作系統(tǒng)生態(tài)的 common hooks 和 helper 函數(shù)的代碼提供源代碼兼容性。"
當(dāng)然,一些現(xiàn)有 hook 和 helper 函數(shù)是與 Linux 底層代碼緊密相關(guān)的。有些功能(如直接調(diào)用內(nèi)核函數(shù))也會是完全依賴于操作系統(tǒng)的。但是對于其他的功能,目標則是與 Linux 在某種程度上實現(xiàn)相同的功能,包括通過重用代碼來實現(xiàn)跟蹤 kernel 和 user-space 的函數(shù),比如 Windows 的 Event Tracing 或 DTrace。而追蹤(tracing)用戶應(yīng)用程序可能就跟 Linux 一樣能支持 Windows 了。
關(guān)于 kernel tracing,畢竟 Linux 和 Windows 系統(tǒng)底層功能并不相同,但至少通過 eBPF,它們應(yīng)該能夠共享一個共同的工作流程來安裝 probe。有趣的是,項目的作者已經(jīng)有了一個新的 hook,是在 Windows 上用 eBPF 實現(xiàn)文件系統(tǒng)的 "mini-filters"??磥硭麄兾磥砜赡軙黾痈嗟膬?nèi)容。在定義對內(nèi)核進行 probing 的通用方法時,如果 eBPF 的工作流程、工具和 runtime 在所有系統(tǒng)上都具有相同的功能,從而構(gòu)成該 "接口" 的核心部分,那么也許 program hok 本身最終就變成了一個實現(xiàn)細節(jié)而已。
目前,功能上的差異已經(jīng)被作為 GitHub 上的一些 issue 而管理了起來。也還需要對不同組件的貢獻和修改。作者已經(jīng)將他們的一些改動推送到了 uBPF,并且已經(jīng)為 PREVAIL 進行了幾個月的修改。值得注意的是他們打算如何處理 map:他們希望重用 generic-ebpf 的代碼,這是另一個基于 uBPF 的 runtime,主要是針對 FreeBSD。
來自微軟的 Alan Jowett 將這個項目的動機總結(jié)為:"任何可以通用的代碼都應(yīng)該被移動到一個更通用的項目中,然后作為 sub-module 加入進來。" 這看起來表明一個方向,就是把一切可能的代碼都上移到 uBPF、PREVAIL、以及未來可能的其他項目,以便只保留 ebpf-for-windows 中盡量少的支持代碼,并且使通用組件可以被其他項目重用。
The road ahead
理想情況下,大多數(shù) eBPF program 在 Linux 和 Windows 上的行為需要是一樣的。要達到這一點則需要工程上的許多努力。通過重新實現(xiàn)一項現(xiàn)有的技術(shù),微軟節(jié)省了設(shè)計過程,但它將不得不補上許多具體功能。eBPF 不僅僅是一個簡單的指令集:它帶有許多 hook、map、helper、用戶空間的操作、以及 tail calls、function calls、BPF type format(BTF)信息等等功能,其中的大部分在 uBPF 中都尚未支持。也許會在今后一段時間內(nèi)獲得支持,其中相當(dāng)一部分應(yīng)該是通用的,才能使得 eBPF 程序可以跨平臺使用。為新架構(gòu)添加 JIT 編譯器不應(yīng)該是一個大問題,DPDK 已經(jīng)有了一個用于 arm64 的編譯器。不過,任何依賴于內(nèi)核 BTF 信息的功能都有可能是與特定操作系統(tǒng)綁定起來的。
verifier 的兼容性是另一個問題。在 Windows 實現(xiàn)方案的所有設(shè)計決策中,最有意思的一點是使用 PREVAIL,因為它比起 Linux 的方案來說已經(jīng)有了某些優(yōu)勢。它可以接受更多的有效程序,并且受 path explosion 的影響較小,有利于性能和詳盡性的檢查。因此,一些程序可能只被 Linux 判定為可用的,而另一些則只在 Windows 上被判定為可用。這應(yīng)該會激勵我們改進 Linux verifier,使其在復(fù)雜的代碼序列上能效率更高,也許也要讓它能驗收更多的 program。要想完全對等,肯定會有很多挑戰(zhàn)等著我們。
人們可能會問,確保 eBPF 的跨操作系統(tǒng)兼容性很重要嗎?首先,如果微軟不能支持現(xiàn)有的 BPF program,那么它對該技術(shù)的興趣可能就會變小。該公司也可以開發(fā)自己的解決方案,而不必費心去整合這些外部功能組件。可移植性對于避免生態(tài)系統(tǒng)分裂是很有必要的,并且更加有利于 Windows 上的采用。當(dāng) generic-ebpf 項目在曝光后得到更多關(guān)注以及開發(fā)貢獻之后,就顯得尤為重要了。這將能支持更多的系統(tǒng),而且由于 libbpf 中正在引入靜態(tài)鏈接(static linking),這也為創(chuàng)建 eBPF libraries 函數(shù)庫鋪平了道路。
然而,這些工作不能僅僅依靠微軟。非常重要的是要與現(xiàn)有的 eBPF 社區(qū)保持同步,從而使這個技術(shù)能以所有系統(tǒng)都能支持的方式來發(fā)展。在 Linux 上,eBPF 已經(jīng)在 Facebook、Google 和 Netflix 等大公司的生產(chǎn)系統(tǒng)中大規(guī)模地應(yīng)用了一段時間了。在 Kubernetes 生態(tài)系統(tǒng)中,得益于 Cilium 等項目,它已經(jīng)在網(wǎng)絡(luò)、可觀察性和安全性方面推廣了更多應(yīng)用場景。Linux 開發(fā)者不可能將 eBPF "擱置" 起來從而等待 Windows 趕上。Thaler 和 Gaddehosur 也知道這里需要大量的溝通工作:
我們現(xiàn)在宣布這個項目時,它還處于相對早期的開發(fā)階段,因為我們的目標是與強大的 eBPF 社區(qū)合作,以確保 eBPF 在 Windows 和其他地方都能很好地工作。
該項目有一個專門的 Slack 頻道,名為#ebpf-for-windows,位于在https://ebpf.io/slack 。至少在 7 月前會開始有定期會議來分發(fā)以及解決 GitHub 上的問題。隨后會有一個專門的郵件列表。
Linux 開發(fā)者的參與程度對于這個項目將是決定性的,但目前還很難預(yù)測會有多大程度的參與熱情。Windows 版 eBPF 也才剛剛宣布:社交網(wǎng)絡(luò)上有一些評論(總體上很歡迎,也有一些提及了微軟之前歷史上出現(xiàn)過的 "擁抱、擴展并消滅" 做法),但目前在 Linux 世界里反響還是很小。
The journey is just starting
eBPF for Windows 項目是很有雄心的,但在這個早期階段,它還缺乏許多在 Linux 上已經(jīng)支持的功能,首先需要對于 program type、map type、helper 等方向達到跟 Linux 的同等支持程度,才能使其變得真正可行。這可以解釋為什么 Linux 開發(fā)者現(xiàn)在還沒有明顯的反應(yīng)了,他們可能在等著看這些實現(xiàn)最終是否能兌現(xiàn)承諾。為了證明它確實可以兌現(xiàn),項目作者們需要抓緊追上開發(fā)進度,能支持 Windows 上更復(fù)雜的使用場景。如果他們想確保項目成功的話,還必須要吸引到更多微軟以外的貢獻者的興趣和參與。
如果他們成功了,開發(fā)者最終可能會從 eBPF 組件中受益,這些組件會作為兩個系統(tǒng)共同使用的庫。用戶空間的函數(shù)庫、工具、應(yīng)用程序、以及兼容性測試套件就都可以擴展到能支持在多種環(huán)境下運行。然后,eBPF 生態(tài)系統(tǒng)也將從來自 Windows 世界的這種另一個角度的思考中獲益,而友好的競爭將有望驅(qū)動兩邊的性能改進。長期來說比較樂觀的想法是,假設(shè)可以找到一個共同的基礎(chǔ)來將兩個系統(tǒng)中對等的 probe 統(tǒng)一表達出來,那么 eBPF 程序可能最終會成為某種形式的控制面(control-plane) API,用來管理不同類型節(jié)點上的網(wǎng)絡(luò)和可觀察性。這樣的接口已經(jīng)開始在云原生計算中出現(xiàn),而支持多種不同環(huán)境的 eBPF 則在這種情況下會更有價值。
當(dāng)然,在此之前還有很多事情需要完成,畢竟這個項目才剛剛開始。然而,就目前的情況來看,這已經(jīng)是對當(dāng)前 eBPF 給 Linux 帶來的好處及未來潛在好處的一種強烈的認可。要想將這個潛力變?yōu)楝F(xiàn)實,很大程度上會取決于不同社區(qū)之間的對話和同步。eBPF 剛剛走出它的 Linux 家園,進入了全新的世界。
全文完
LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。
長按下面二維碼關(guān)注,關(guān)注 LWN 深度文章以及開源社區(qū)的各種新近言論~
