【收藏】BPF 技術(shù)介紹及學(xué)習(xí)路線分享

來自【分布式實(shí)驗(yàn)室】


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



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


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











https://ebpf.io,最全BPF學(xué)習(xí)資源網(wǎng)站,主要由Cilium團(tuán)隊(duì)維護(hù),上面會(huì)及時(shí)更新BPF技術(shù)的文檔和視頻。
https://lwn.net/Kernel/Index/#Berkeley_Packet_Filter,LWN是學(xué)習(xí)Linux內(nèi)核技術(shù)的最好的網(wǎng)站,這個(gè)BPF分類文章集合,記錄了很多BPF里程碑事件的前前后后,既學(xué)會(huì)了知識(shí),又明白了背景。
https://cilium.readthedocs.io/en/stable/bpf/,Cilium提供的BPF文檔,是我看到過的最具實(shí)戰(zhàn)價(jià)值的BPF手冊,值得好好閱讀。
https://www.kernel.org/doc/html/latest/bpf/bpf_devel_QA.html,開發(fā)BPF必讀Q&A,里面是維護(hù)BPF內(nèi)核代碼的大佬給出的代碼開發(fā)建議,讀了能明白社區(qū)是如何運(yùn)作BPF的。
https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git/,這個(gè)repo是Linux社區(qū)官方維護(hù)的獨(dú)立BPF代碼倉庫,一旦發(fā)布新版本后,代碼就不會(huì)大改,只接受bug fix,相當(dāng)于master repo,最終會(huì)merge到Linux內(nèi)核代碼主干中。
https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/,這個(gè)repo也是Linux社區(qū)官方維護(hù)的BPF代碼倉庫,更新頻繁,用于引入新功能或現(xiàn)有功能優(yōu)化,穩(wěn)定后merge到上面的master repo,相當(dāng)于feature repo。
https://cilium.slack.com/archives/C4XCTGYEM,為Cilium提供的關(guān)于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最強(qiáng)BPF布道師,他的博客都是關(guān)于Linux系統(tǒng)優(yōu)化的,觀點(diǎn)獨(dú)到,每一篇都值得一讀;
Alexei Starovoitov,eBPF創(chuàng)造者,目前在Facebook就職,經(jīng)常能在內(nèi)核代碼commit中看到他的蹤跡;
Daniel Borkmann,eBPF kernel co-maintainer,目前在Cilium所在的公司Isovalent就職,是給eBPF增加feature的能力者;
Thomas Graf,Cilium之父,Isovalent的CTO,他也是eBPF和Cilium的強(qiáng)力布道師,能說會(huì)道,各種大會(huì)上都有他的風(fēng)采;
Quentin Monnet,BPFTool co-maintainer,Quentin是在stackoverflow上bpf問題的killer,Twitter有關(guān)于eBPF的系列實(shí)戰(zhàn)短文,值得細(xì)品。
《Linux Observability with BPF》,作者David Calavera和Lorenzo Fontana, 這本書篇幅不長,是來自sysdig的兩位大佬寫的BPF手冊書,推薦入門閱讀
《Linux內(nèi)核觀測技術(shù)BPF》,是最近剛出版的第一本BPF中文書籍,為上面英文書的翻譯版本,由范彬和狄衛(wèi)華兩位翻譯
《BPF Performance Tools》,這是Brendan Gregg大神對于BPF技術(shù)如何做系統(tǒng)性能優(yōu)化的一本集大成者的秘籍,BPF學(xué)習(xí)者必備。
《Systems Performance: Enterprise and the Cloud, 2nd Edition》,這是Brendan Gregg大神系統(tǒng)優(yōu)化書籍的第二版,篇幅較長,但是值得一啃。
繞過conntrack,使用eBPF增強(qiáng) IPVS優(yōu)化k8s網(wǎng)絡(luò)性能:https://v.qq.com/x/page/s3137ehoq8i.html
深入了解服務(wù)網(wǎng)格數(shù)據(jù)平面性能和調(diào)優(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)絡(luò)優(yōu)化方案
Kernel Chaos With BPF by PingCAP
網(wǎng)易輕舟做系統(tǒng)檢測和網(wǎng)絡(luò)優(yōu)化
字節(jié)跳動(dòng)做高性能網(wǎng)絡(luò)ACL管理



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

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

有收獲,點(diǎn)個(gè)在看?


