【收藏】BPF 技術介紹及學習路線分享

來自【分布式實驗室】


一個新的虛擬機(VM)設計,可以有效地工作在基于寄存器結構的CPU之上;
應用程序使用緩存只復制與過濾數(shù)據(jù)包相關的數(shù)據(jù),不會復制數(shù)據(jù)包的所有信息,最大程度地減少BPF 處理的數(shù)據(jù),提高處理效率。



強安全,即不能允許不可信的代碼運行在內核中,這是頭等重要的事情
高性能,作為承載千百萬服務的操作系統(tǒng)內核,如果沒有高性能的保障,互聯(lián)網(wǎng)蓬勃發(fā)展將收到嚴重影響
持續(xù)交付,在越來越多應用進入到云原生時代的今天,持續(xù)交付這個命題,一點都不陌生,而在內核開發(fā)領域,這點也至關重要,每次功能的升級,都需要你重新安裝新的系統(tǒng),大多數(shù)人都不會買賬。我們希望做到跟Chrome瀏覽器升級一樣,用戶都不會注意到升級完成了(除非有一些視覺上的變化),實現(xiàn)真正的無縫升級。
直接修改內核代碼進行開發(fā),通過API暴露能力,可能要等上n年用戶才能更新到這個版本來使用,而且每次的功能更新都可能需要重新編譯打包內核代碼。
開發(fā)新的可即時加載的內核模塊,用戶可以在運行時加載到Linux內核中,從而實現(xiàn)擴展內核功能的目的。然而每次內核版本的官方更新,可能會引起內核API的變化,因此你編寫的內核模塊可能會隨著每一個內核版本的發(fā)布而不可用,這樣就必須得為每次的內核版本更新調整你的模塊代碼,你得非常小心,不然就會讓內核直接崩潰。
強安全:BPF驗證器(verifier)會保證每個程序能夠安全運行,它會去檢查將要運行到內核空間的程序的每一行是否安全可靠,如果檢查不通過,它將拒絕這個程序被加載到內核中去,從而保證內核本身不會崩潰,這是不同于開發(fā)內核模塊的。比如以下幾種情況是無法通過的BPF驗證器的:
BPF驗證機制很像Chrome瀏覽器對于JavaScript腳本的沙盒機制。
沒有實際加載BPF程序所需的權限
訪問任意內核空間的內存數(shù)據(jù)
將任意內核空間的內存數(shù)據(jù)暴露給用戶空間
高性能:一旦通過了BPF驗證器,那么它就會進入JIT編譯階段,利用Just-In-Time編譯器,編譯生成的是通用的字節(jié)碼,它是完全可移植的,可以在x86和ARM等任意球CPU架構上加載這個字節(jié)碼,這樣我們能獲得本地編譯后的程序運行速度,而且是安全可靠的。
持續(xù)交付:通過JIT編譯后,就會把編譯后的程序附加到內核中各種系統(tǒng)調用的鉤子(hook)上,而且可以在不影響系統(tǒng)運行的情況下,實時在線地替換這些運行在Linux內核中的BPF程序。舉個例子,拿一個處理網(wǎng)絡數(shù)據(jù)包的應用程序來說,在每秒都要處理幾十萬個數(shù)據(jù)包的情況下,在一個數(shù)據(jù)包和下一個數(shù)據(jù)包之間,加載到網(wǎng)絡系統(tǒng)調用hook上的BPF程序是可以自動替換的,可以預見到的結果是,上一個數(shù)據(jù)包是舊版本的程序在處理,而下一個數(shù)據(jù)包就會看到新版本的程序了,沒有任何的中斷。這就是無縫升級,從而實現(xiàn)持續(xù)交付的能力。

kernel functions(kprobes)
userspace functions(uprobes)
system calls
fentry/fexit
Tracepoints
network devices(tc/xdp)
network routes
TCP congestion algorithms
sockets(data level)

Hash tables,Arrays
LRU(Least Recently Used)
Ring Buffer
Stack Trace
LPM(Longest Prefix match)

BPF Map是可以被用戶空間訪問并操作的
BPF Map是可以與BPF程序分離的,即當創(chuàng)建一個BPF Map的BPF程序運行結束后,該BPF Map還能存在,而不是隨著程序一起消亡


eBPF程序不能調用任意的內核參數(shù),只限于內核模塊中列出的BPF Helper函數(shù),函數(shù)支持列表也隨著內核的演進在不斷增加
eBPF程序不允許包含無法到達的指令,防止加載無效代碼,延遲程序的終止
eBPF程序中循環(huán)次數(shù)限制且必須在有限時間內結束
eBPF堆棧大小被限制在MAX_BPF_STACK,截止到內核Linux 5.8版本,被設置為512。目前沒有計劃增加這個限制,解決方法是改用BPF Map,它的大小是無限的。
eBPF字節(jié)碼大小最初被限制為4096條指令,截止到內核Linux 5.8版本, 當前已將放寬至100萬指令(BPF_COMPLEXITY_LIMIT_INSNS),對于無權限的BPF程序,仍然保留4096條限制(BPF_MAXINSNS)











https://ebpf.io,最全BPF學習資源網(wǎng)站,主要由Cilium團隊維護,上面會及時更新BPF技術的文檔和視頻。
https://lwn.net/Kernel/Index/#Berkeley_Packet_Filter,LWN是學習Linux內核技術的最好的網(wǎng)站,這個BPF分類文章集合,記錄了很多BPF里程碑事件的前前后后,既學會了知識,又明白了背景。
https://cilium.readthedocs.io/en/stable/bpf/,Cilium提供的BPF文檔,是我看到過的最具實戰(zhàn)價值的BPF手冊,值得好好閱讀。
https://www.kernel.org/doc/html/latest/bpf/bpf_devel_QA.html,開發(fā)BPF必讀Q&A,里面是維護BPF內核代碼的大佬給出的代碼開發(fā)建議,讀了能明白社區(qū)是如何運作BPF的。
https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git/,這個repo是Linux社區(qū)官方維護的獨立BPF代碼倉庫,一旦發(fā)布新版本后,代碼就不會大改,只接受bug fix,相當于master repo,最終會merge到Linux內核代碼主干中。
https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/,這個repo也是Linux社區(qū)官方維護的BPF代碼倉庫,更新頻繁,用于引入新功能或現(xiàn)有功能優(yōu)化,穩(wěn)定后merge到上面的master repo,相當于feature repo。
https://cilium.slack.com/archives/C4XCTGYEM,為Cilium提供的關于eBPF的thread,有什么疑問都可以去問
https://github.com/DavadDi/bpf_study,狄衛(wèi)華老師的收集的BPF文章和教程,有問題可以去提issue
https://github.com/nevermosby/linux-bpf-learning,本人編寫的BPF教程,歡迎來提issue和PR
Brendan Gregg,來自Netflix最強BPF布道師,他的博客都是關于Linux系統(tǒng)優(yōu)化的,觀點獨到,每一篇都值得一讀;
Alexei Starovoitov,eBPF創(chuàng)造者,目前在Facebook就職,經(jīng)常能在內核代碼commit中看到他的蹤跡;
Daniel Borkmann,eBPF kernel co-maintainer,目前在Cilium所在的公司Isovalent就職,是給eBPF增加feature的能力者;
Thomas Graf,Cilium之父,Isovalent的CTO,他也是eBPF和Cilium的強力布道師,能說會道,各種大會上都有他的風采;
Quentin Monnet,BPFTool co-maintainer,Quentin是在stackoverflow上bpf問題的killer,Twitter有關于eBPF的系列實戰(zhàn)短文,值得細品。
《Linux Observability with BPF》,作者David Calavera和Lorenzo Fontana, 這本書篇幅不長,是來自sysdig的兩位大佬寫的BPF手冊書,推薦入門閱讀
《Linux內核觀測技術BPF》,是最近剛出版的第一本BPF中文書籍,為上面英文書的翻譯版本,由范彬和狄衛(wèi)華兩位翻譯
《BPF Performance Tools》,這是Brendan Gregg大神對于BPF技術如何做系統(tǒng)性能優(yōu)化的一本集大成者的秘籍,BPF學習者必備。
《Systems Performance: Enterprise and the Cloud, 2nd Edition》,這是Brendan Gregg大神系統(tǒng)優(yōu)化書籍的第二版,篇幅較長,但是值得一啃。
繞過conntrack,使用eBPF增強 IPVS優(yōu)化k8s網(wǎng)絡性能:https://v.qq.com/x/page/s3137ehoq8i.html
深入了解服務網(wǎng)格數(shù)據(jù)平面性能和調優(yōu):https://v.qq.com/x/page/v3137ax6zss.html
Kubernetes中用于混沌與跟蹤的BPF:https://v.qq.com/x/page/f3130lpe0iv.html
https://kccnceu20.sched.com/event/ZejN/tutorial-using-bpf-in-cloud-native-environments-alban-crequy-marga-manterola-kinvolk
https://kccnceu20.sched.com/event/Zeoz/hubble-ebpf-based-observability-for-kubernetes-sebastian-wicki-isovalent
https://kccnceu20.sched.com/event/Zexb/designing-a-grpc-interface-for-kernel-tracing-with-ebpf-leonardo-di-donato-sysdig
https://kccnceu20.sched.com/event/ZemQ/ebpf-and-kubernetes-little-helper-minions-for-scaling-microservices-daniel-borkmann-cilium
https://kccnceu20.sched.com/event/Zewd/intro-to-falco-intrusion-detection-for-containers-shane-lawrence-shopify
https://kccnceu20.sched.com/event/ZetL/seccomp-security-profiles-and-you-a-practical-guide-duffie-cooley-vmware
https://kccnceu20.sched.com/event/ZeqL/k8s-in-the-datacenter-integrating-with-preexisting-bare-metal-environments-max-stritzinger-bloomberg
Tcpdump
BCC,BPFTrace,kubectl-trace from IOVisor
Cilium from Isovalent
Falco from Sysdig
Katran from Facebook
Bottlerocket from Amazon
騰訊云IPVS-BPF K8S網(wǎng)絡優(yōu)化方案
Kernel Chaos With BPF by PingCAP
網(wǎng)易輕舟做系統(tǒng)檢測和網(wǎng)絡優(yōu)化
字節(jié)跳動做高性能網(wǎng)絡ACL管理



r0保存了調用一次輔助函數(shù)后的返回值
r1 – r5 保存了從BPF程序到輔助函數(shù)的參數(shù)列表
r6 – r9 是用來保存中間值的寄存器,它可以被多個輔助函數(shù)調用
r10 是唯一的只讀寄存器,包含訪問BPF stack的指針
在線閱讀Linux內核代碼的好去處:https://elixir.bootlin.com/linux/v5.8.7/source
快速定位函數(shù)的定義和引用
下載Linux內核代碼,編譯運行BPF示例程序
參見博文: https://davidlovezoe.club/compile-bpf-examples
根據(jù)示例程序,寫自己的BPF程序,并跑起來

能夠靜下心來看Linux內核代碼,這件事聽起來簡單,做起來不易,因為有了學習興趣有學習目標,我開始習慣于閱讀那些看起來冗長晦澀的代碼
理解Linux系統(tǒng)調用、文件系統(tǒng)等功能模塊的工作原理,正式由于能靜下心來讀代碼,所以那些原本認為這輩子都看不懂的東西,竟然慢慢變得清晰起來
寫文章可以鍛煉很多其他軟技能,比如畫圖,錄視頻,做視頻等等,寫技術博客就是這么一件痛并快樂著的事情

有收獲,點個在看?


