智匯華云 | eBPF介紹與使用

Linux在日常的使用中已經(jīng)無(wú)處不在了,從人們的手機(jī),到電視機(jī),再到路由器,都運(yùn)行在linux內(nèi)核之上,而eBPF就是Linux內(nèi)核的一把瑞士軍刀,通過(guò)eBPF可以在linux內(nèi)核中運(yùn)行程序,運(yùn)維人員可以使用它對(duì)linux內(nèi)核進(jìn)行監(jiān)控,開發(fā)者可以使用它對(duì)linux內(nèi)核功能進(jìn)行定制修改,做到很多以前無(wú)法實(shí)現(xiàn)的功能。

官方的說(shuō)法: eBPF is a revolutionary technology with origins in the Linux kernel that can run sandboxed programs in an operating system kernel.

個(gè)人認(rèn)為,簡(jiǎn)單的說(shuō),eBPF可以理解為一個(gè)框架,通過(guò)這個(gè)框架,我們可以在內(nèi)核中執(zhí)行自己編寫的程序代碼。

eBPF基本概念

eBPF的前身是BPF(extended Berkeley Packet Filter),BPF是內(nèi)核中用來(lái)做高效過(guò)濾網(wǎng)絡(luò)報(bào)文的,tcpdump里面就是用的BPF技術(shù)過(guò)濾報(bào)文。2014年內(nèi)核3.18中eBPF第一次出現(xiàn),此時(shí)的eBPF已經(jīng)成為內(nèi)核的頂級(jí)子系統(tǒng),演進(jìn)為一個(gè)通用執(zhí)行引擎,允許用戶在內(nèi)核中運(yùn)行自己的程序。

掛載點(diǎn)(Hook)eBPF程序基于事件觸發(fā),當(dāng)內(nèi)核代碼走到對(duì)應(yīng)的掛載點(diǎn)就會(huì)執(zhí)行掛載在此處的eBPF程序。常見的掛載點(diǎn)有:系統(tǒng)調(diào)用,內(nèi)核函數(shù)進(jìn)入/退出,內(nèi)核跟蹤點(diǎn),網(wǎng)絡(luò)數(shù)據(jù)包等等。

映射(Maps)eBPF程序中用來(lái)存儲(chǔ)數(shù)據(jù),共享數(shù)據(jù)的結(jié)構(gòu)體就是Maps,內(nèi)核內(nèi)置了多種類型的Maps給開發(fā)者使用,常見的有哈希表,數(shù)組,LRU,Ring buffer等等。

幫助函數(shù)(Helper Calls)內(nèi)核為了保證安全,運(yùn)行在內(nèi)核中的eBPF程序只能調(diào)用當(dāng)前內(nèi)核版本預(yù)定義好的函數(shù),不能隨意調(diào)用其他內(nèi)核函數(shù),函數(shù)名稱都是以bpf_開頭命名。例如u32 bpf_get_smp_processor_id(void),可以獲取當(dāng)前eBPF程序運(yùn)行在哪個(gè)cpu上。

加載與驗(yàn)證(Loader & Verification)編寫好的eBPF程序需要先通過(guò)編譯,生成字節(jié)碼,之后通過(guò)調(diào)用bpf系統(tǒng)調(diào)用將字節(jié)碼加載到內(nèi)核,此時(shí)內(nèi)核會(huì)運(yùn)行自己的驗(yàn)證器來(lái)檢驗(yàn)eBPF程序,確保程序是安全的,有限循環(huán)的,不會(huì)把linux系統(tǒng)搞壞。

eBPF特點(diǎn)

強(qiáng)大的內(nèi)核可編程性。隨著內(nèi)核版本的升級(jí),內(nèi)核中可以運(yùn)行eBPF程序的地方越來(lái)越多,eBPF可以做的事情也越來(lái)越多。不同內(nèi)核功能加入eBPF版本列表:


SW$_QNP1$ZK}PDKKZR@Y_WH.png

開發(fā)方便開發(fā)者不需要自己定義數(shù)據(jù)結(jié)構(gòu),直接使用現(xiàn)成的Maps進(jìn)行存儲(chǔ)共享數(shù)據(jù),只需要關(guān)注具體的業(yè)務(wù)實(shí)現(xiàn)代碼。由于eBPF程序先編譯成字節(jié)碼,之后內(nèi)核自己校驗(yàn)通過(guò)之后再生成可用的內(nèi)核代碼,所以可以一次編譯處處運(yùn)行,不需要像內(nèi)核模塊一樣,每次更新內(nèi)核之后都要重新編譯。

可以在x86上編譯mips架構(gòu)上運(yùn)行的eBPF字節(jié)碼。免去交叉編譯的痛苦。

安全數(shù)據(jù)操作都是通過(guò)Maps,操作Maps的函數(shù)也是預(yù)先定義好的,不存在訪問空指針。

eBPF使用

介紹了這么多eBPF的概念,接下來(lái)實(shí)際操作一下,看看eBPF程序如何編譯和使用,這里采用原汁原味的linux源代碼編譯演示。

使用最新的archlinux系統(tǒng),其他系統(tǒng)也差不多,稍微按照實(shí)際情況改一下。

ORGBGN7M8OMUTEO%3}[)9}Y.png

這里把內(nèi)核自帶的bpf示例程序都編譯出來(lái)了,在目錄samples/bpf下面。

這里我們具體看一個(gè)sampleip的eBPF程序,看看eBPF程序是如何編寫的

直接上代碼:

智匯華云.jpg

首先17到23行定義了一個(gè)maps,叫ip_map,類型是哈希,鍵是u64,值是u32,最大長(zhǎng)度8192。

之后定義了一個(gè)do_sample函數(shù),函數(shù)參數(shù)類型是bpf_perf_event_data,里面有當(dāng)前內(nèi)核IP指令指針寄存器的內(nèi)容。通過(guò)調(diào)用bpf_map_lookup_elem函數(shù)來(lái)更新ip_map。

運(yùn)行內(nèi)核編譯好的sampleip程序,默認(rèn)是采樣5秒,每秒采樣99次,程序結(jié)束后會(huì)把ip_map采集到的信息打印出來(lái)。

從這個(gè)實(shí)例中可以看出,開發(fā)的eBPF程序比傳統(tǒng)的內(nèi)核開發(fā)方便了很多,數(shù)據(jù)結(jié)構(gòu)不用操心,可以調(diào)用的函數(shù)也不用操心,都是預(yù)先定義好的,只需要實(shí)現(xiàn)自己的業(yè)務(wù)邏輯即可。

eBPF使用場(chǎng)景

linux性能分析,性能調(diào)優(yōu)上面的sampleip就是簡(jiǎn)單的內(nèi)核性能分析,可以看出當(dāng)前內(nèi)核經(jīng)常調(diào)用的函數(shù)。eBPF對(duì)于內(nèi)核開銷很小,可以在生產(chǎn)環(huán)境排查問題的時(shí)候進(jìn)行精確定位,同時(shí)由于eBPF的安全性,不用擔(dān)心會(huì)把內(nèi)核搞掛。有興趣的可以去看一下bcc,里面對(duì)于內(nèi)核每個(gè)子系統(tǒng)都有對(duì)應(yīng)的eBPF監(jiān)控程序,非常方便。

eBPF介紹與使用.jpg

linux網(wǎng)絡(luò)加速eBPF在這個(gè)領(lǐng)域中也是牛的很,底層有XDP快速數(shù)據(jù)路徑,可以直接在網(wǎng)卡收到數(shù)據(jù)包的同時(shí)進(jìn)行處理,避免內(nèi)核分配skb開銷,可以用來(lái)實(shí)現(xiàn)DDos,負(fù)載均衡,性能媲美DPDK。再往上一點(diǎn)內(nèi)核的tc也可以hook eBPF程序?qū)崿F(xiàn)自定義流量分類,再向上的socket層還可以調(diào)用eBPF實(shí)現(xiàn)動(dòng)態(tài)修改socket選項(xiàng),甚至tcp的擁塞算法內(nèi)核也提供了eBPF掛載的地方,可以自己實(shí)現(xiàn)一套新的擁塞算法。

安全管理systemd中使用eBPF控制服務(wù)可以監(jiān)聽的端口,libvirtd也使用eBPF進(jìn)行設(shè)備的訪問控制,社區(qū)還有eBPF控制進(jìn)程允許訪問的文件,允許讀寫哪些/sys文件。

eBPF的出現(xiàn)讓Linux內(nèi)核開發(fā)變得簡(jiǎn)單,降低了內(nèi)核開發(fā)門檻,為普通人了解深入linux內(nèi)核提供了途徑,真的是一個(gè)革命性的發(fā)明,有l(wèi)inux的地方就有ebpf ^^。

(免責(zé)聲明:本網(wǎng)站內(nèi)容主要來(lái)自原創(chuàng)、合作伙伴供稿和第三方自媒體作者投稿,凡在本網(wǎng)站出現(xiàn)的信息,均僅供參考。本網(wǎng)站將盡力確保所提供信息的準(zhǔn)確性及可靠性,但不保證有關(guān)資料的準(zhǔn)確性及可靠性,讀者在使用前請(qǐng)進(jìn)一步核實(shí),并對(duì)任何自主決定的行為負(fù)責(zé)。本網(wǎng)站對(duì)有關(guān)資料所引致的錯(cuò)誤、不確或遺漏,概不負(fù)任何法律責(zé)任。
任何單位或個(gè)人認(rèn)為本網(wǎng)站中的網(wǎng)頁(yè)或鏈接內(nèi)容可能涉嫌侵犯其知識(shí)產(chǎn)權(quán)或存在不實(shí)內(nèi)容時(shí),應(yīng)及時(shí)向本網(wǎng)站提出書面權(quán)利通知或不實(shí)情況說(shuō)明,并提供身份證明、權(quán)屬證明及詳細(xì)侵權(quán)或不實(shí)情況證明。本網(wǎng)站在收到上述法律文件后,將會(huì)依法盡快聯(lián)系相關(guān)文章源頭核實(shí),溝通刪除相關(guān)內(nèi)容或斷開相關(guān)鏈接。 )