智匯華云 | eBPF介紹與使用

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

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

個人認為,簡單的說,eBPF可以理解為一個框架,通過這個框架,我們可以在內核中執(zhí)行自己編寫的程序代碼。

eBPF基本概念

eBPF的前身是BPF(extended Berkeley Packet Filter),BPF是內核中用來做高效過濾網絡報文的,tcpdump里面就是用的BPF技術過濾報文。2014年內核3.18中eBPF第一次出現,此時的eBPF已經成為內核的頂級子系統(tǒng),演進為一個通用執(zhí)行引擎,允許用戶在內核中運行自己的程序。

掛載點(Hook)eBPF程序基于事件觸發(fā),當內核代碼走到對應的掛載點就會執(zhí)行掛載在此處的eBPF程序。常見的掛載點有:系統(tǒng)調用,內核函數進入/退出,內核跟蹤點,網絡數據包等等。

映射(Maps)eBPF程序中用來存儲數據,共享數據的結構體就是Maps,內核內置了多種類型的Maps給開發(fā)者使用,常見的有哈希表,數組,LRU,Ring buffer等等。

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

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

eBPF特點

強大的內核可編程性。隨著內核版本的升級,內核中可以運行eBPF程序的地方越來越多,eBPF可以做的事情也越來越多。不同內核功能加入eBPF版本列表:


SW$_QNP1$ZK}PDKKZR@Y_WH.png

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

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

安全數據操作都是通過Maps,操作Maps的函數也是預先定義好的,不存在訪問空指針。

eBPF使用

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

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

ORGBGN7M8OMUTEO%3}[)9}Y.png

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

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

直接上代碼:

智匯華云.jpg

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

之后定義了一個do_sample函數,函數參數類型是bpf_perf_event_data,里面有當前內核IP指令指針寄存器的內容。通過調用bpf_map_lookup_elem函數來更新ip_map。

運行內核編譯好的sampleip程序,默認是采樣5秒,每秒采樣99次,程序結束后會把ip_map采集到的信息打印出來。

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

eBPF使用場景

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

eBPF介紹與使用.jpg

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

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

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

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