BTF:實踐指南

本文地址:BTF:實踐指南 | 深入淺出 eBPF

  • 1. BPF 的常見限制
    • 1.1 調試限制
    • 1.2 可移植性
  • 2. BTF 是什么?
  • 3. BTF 快速入門
    • 3.1 BPF 快速入門
    • 3.1 BTF 和 CO-RE
  • 4. 結論

BPF 是 Linux 內核中基于寄存器的虛擬機,可安全、高效和事件驅動的方式執行加載至內核的字節碼。與內核模塊不同,BPF 程序經過驗證以確保它們終止并且不包含任何可能鎖定內核的循環。BPF 程序允許調用的內核函數也受到限制,以確保最大的安全性以防止非法的訪問。

盡管 BPF 為編寫事件驅動的內核空間代碼提供了一種有效的解決方案,但開發人員的體驗仍無法與其他編程語言或框架相提并論。BPF 開發的兩個最重要的問題是缺乏簡單的調試和可移植性。

為了緩解這些問題,我們轉向?BTF。BTF 是針對 BPF 程序的類型信息進行編碼文件格式,通過 BPF 程序的類型信息進行編碼,為程序提供更好的內省(introspection)和可見性。本文我們將介紹 BPF 的典型局限性以及如何使用 BTF 來克服。

請注意,本文使用術語 BPF 來表示?eBPF(擴展的 Berkeley 數據包過濾器),eBPF 擴展 “ 經典 ” cBPF。

1. BPF 的常見限制

在 BPF 程序的開發和運行過程中,我們會經常會面臨調試限制和可移植性問題,如前所述。

1.1 調試限制

幾乎所有現代編程語言都有對應的調試器,通過調試器可以幫助我們更好了解正在運行的程序。例如,GDB?是 C 和 C++ 的常用調試器,除其他外,基于 GDB 我們可以打印正在運行的程序中的變量值。

GDB 漂亮打印變量的屏幕截圖

? 圖 GDB 變量打印

但是很不幸,BPF 程序并沒有類似的這樣的工具。盡管檢查數據只是調試的一小部分,但為 BPF 實現類似的結果可以為未來的廣泛調試工具打開一扇門。為了實現這一點,BPF 需要知道關于程序的相關的部分元數據。

這類關于類型信息的元數據,正是 BTF 封裝的內容。

1.2 可移植性

BPF 程序在內核空間中運行,可以訪問內部內核狀態和數據結構。但是,并沒有辦法保證內核數據結構和類型在不同內核版本是相同的,甚至相同內核版本的不同機器之間也可能不同(這可能取決于內核編譯選項)。這意味著在一臺機器上編譯的 BPF 程序并不能保證在另一臺機器上正確運行。

假設 BPF 程序正在從內核結構中讀取一個字段,該字段位于距結構開頭的偏移量 8 處。現在在更高版本的內核中,在該變量之前添加了其他字段,導致訪問的字段的偏移量變成了 24,這會導致 BPF 程序在偏移量 8 讀取的數據可能為垃圾數據。類似情況,也可能會發生某些字段最終得到在后續內核版本中的重命名。例如,在內核版本 4.6 和 4.7 之間,thread_struct 的 fs 字段可能會重命名為 fsbase 。最后,還可能是因為配置禁用了某些功能并編譯了部分結構,導致可能 BPF 程序在不同的內核配置上運行。

所有上述這些場景的存在,意味著你不能在當前機器上編譯 BPF 程序并將二進制文件分發到其他系統。

一個標準的解決方案是使用?BPF Compiler Collection (BCC)。使用 BCC,你通常將 BPF 程序作為純字符串嵌入到用戶空間程序(例如,Python 程序)中。在目標機器上執行期間,BCC 使用其嵌入式 Clang/LLVM 組合并使用本地安裝的內核頭文件動態編譯程序。

然而,這種方法引入了更多問題。首先,Clang/LLVM 組合非常龐大,將其嵌入到應用程序中會導致二進制文件大小過大。它還占用大量資源,并且會在編譯期間耗盡大量資源。最后,這種方法需要在目標機器上安裝內核頭文件,但情況可能并非總是如此。

解決方案是 BPF CO-RE(一次編譯 —— 隨處運行)。使用 BTF,我們可以消除在目標機器上安裝內核頭文件或將 Clang/LLVM 嵌入應用程序并在目標機器上編譯的需要。

2. BTF 是什么?

如前所述,BTF 是編碼 BPF 程序和 map 結構等相關的調試信息的元數據格式。BTF 可以將元數據數據類型、函數信息和行信息編碼成一種緊湊的格式。

在非 BPF 程序中,這些元數據通常使用?DWARF?格式存儲。但是,DWARF 格式的實現還是相當復雜和冗長,并且由于其在大小方面的開銷,使其不適合包含在內核中。而 BTF 是一種緊湊而簡單的格式,讓其可以包含在內核鏡像中。

BTF 使用少數類型描述?符之一表示每種數據類型:

  • BTF_KIND_INT
  • BTF_KIND_PTR
  • BTF_KIND_ARRAY
  • BTF_KIND_STRUCT
  • 等等

類型信息存儲在生成的 ELF 的 .BTF 部分中。除了類型描述符之外,此部分還對字符串進行編碼。函數和行信息存儲在 .BTF.ext 部分中。

關于 BTF 的詳細說明,可以查看?Linux Kernel 文檔。

3. BTF 快速入門

3.1 BPF 快速入門

現在讓我們通過使用 BTF 漂亮地打印?BPF map 的教程進行更多實踐,從而顯著改進調試。

要開始,我們需要在啟用 CONFIG_DEBUG_INFO_BTF 選項的情況下編譯 Linux 內核。大多數發行版都啟用了此選項,但你可以通過運行以下命令進行檢查:

$ zgrep CONFIG_DEBUG_INFO_BTF=y /proc/config.gz
# 可選: grep CONFIG_DEBUG_INFO_BTF=y  /boot/config*

當然,我們還需要在計算機上安裝 Clang 和 LLVM。

由于我們需要將編寫?XDP?程序來處理網絡設備上的數據包,因此創建一個虛擬網絡接口?是個好主意,這樣就不會最終失去物理接口中的互聯網連接。設置虛擬接口的最簡單方法是使用此 repo。

克隆 repo 并設置一個名為 test1 的虛擬接口:

$ git clone git@github.com:xdp-project/xdp-tutorial.git
$ cd xdp-tutorial/testenv
$ sudo ./testenv.sh setup --name=test1 --legacy-ip

現在編寫一個 BPF 程序來計算接口上接收到的 IPv4 和 IPv6 數據包的數量。文件 xdp_count.c 的文件內容如下:

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <arpa/inet.h>struct bpf_map_def SEC("maps") cnt = {.type = BPF_MAP_TYPE_ARRAY,.key_size = sizeof(__u32),.value_size = sizeof(long),.max_entries = 2,
};SEC("xdp_count")
int xdp_count_prog(struct xdp_md *ctx)
{void *data_end = (void *)(long)ctx->data_end;void *data = (void *)(long)ctx->data;__u32 ipv6_key = 0;__u32 ipv4_key = 1;long *value;__u16 h_proto;struct ethhdr *eth = data;if (data + sizeof(struct ethhdr) > data_end) // This check is necessary to pass verificationreturn XDP_DROP;h_proto = eth->h_proto;if (h_proto == htons(ETH_P_IPV6)) { // Check if IPv6 packetvalue = bpf_map_lookup_elem(&cnt, &ipv6_key);if (value)*value += 1;return XDP_PASS;}value = bpf_map_lookup_elem(&cnt, &ipv4_key);if (value)*value += 1;return XDP_PASS;}char _license[] SEC("license") = "GPL";

在前面的代碼中,名為 cnt 的 BPF map 存儲數據包的數量。cnt 是兩個元素的數組。IPv6 數據包的數量存儲在 key 0 中,IPv4 數據包的數量存儲在 key 1 中。

使用 Clang 編譯代碼:

$ clang -O2 -Wall -g -target bpf -c xdp_count.c -o xdp_count.o

接下來,使用 bpftool 加載程序:

$ sudo bpftool prog load xdp_count.o /sys/fs/bpf/xdp_count type xdp

運行以下命令并記下我們剛加載的程序的 ID 和程序正在使用的 map 的 ID:

$ sudo bpftool prog list

Output of bpftool prog list

? 圖 bpftool prog 列表的輸出

我們還可以通過運行 sudo bpftool map list 來獲取 map ID。

Output of the bpftool map list command

? 圖 bpftool map list 的內容輸出

此命令為我們提供 map 的名稱、類型、鍵大小、值大小和最大條目數。

現在,將 BPF 程序附加到網絡設備。

$ sudo bpftool net attach xdpgeneric id <program_id> dev test1

將 program_id 替換為程序的 ID,并將 device_name 替換為程序附加到的網絡設備的名稱(例如 enp34s0)。

現在,向該設備發送一些數據包。測試環境腳本已經提供了一個方便的 ping 命令來執行此操作:

$ sudo ./testenv.sh ping # For IPv6
$ sudo ./testenv.sh ping --legacy-ip # For IPv4

打印 map 并檢查處理的數據包情況:

$ sudo bpftool map dump id <map_id>

The dumped value of the map

? 圖 map 的打印值

如圖所示,map 中有兩個預期的元素。這些值采用十六進制格式,并且還取決于運行機器的字節順序。在截圖中,它是小端格式,這意味著已經處理了 22 個 IPv6 和 4 個 IPv4 數據包。

很明顯,結果是十六進制的,小端格式,一看就不好調試。因此,我們需要使用 BTF 對 map 進行注釋,以便更好地展示。

如下更改 cnt 的聲明并將新代碼保存在 xdp_count_btf.c 中 -

...
struct {__uint(type, BPF_MAP_TYPE_ARRAY);__type(key, __u32);__type(value, long);__uint(max_entries, 2);
} cnt SEC(".maps");
...

請注意,部分名稱現在為 .maps,并且地圖本身已使用啟用 BTF 的宏?__uint?和?__type?進行了注釋。

使用 Clang 編譯代碼:

clang -O2 -Wall -g -target bpf -c xdp_count_btf.c -o xdp_count_btf.o

使用 -g 標志將創建調試信息并生成 BTF。請注意,之前也使用了 -g 標志,因為 libbpf需要它?來加載程序;然而,以前 map 沒有被 BTF 注釋,所以 bpftool 不能夠優雅地進行打印。

驗證 BTF 部分是否存在于生成的目標文件中。

$ llvm-objdump -h xdp_count_btf.o

Output of llvm-objdump

? 圖 llvm-objdump 的輸出

如前所述,.BTF 部分包含類型和字符串數據,.BTF.ext 部分對 func_info 和 line_info 數據進行編碼。

首先,卸載前面的 BPF 程序。

1
$ sudo bpftool net detach xdpgeneric dev test1

然后按照類似的過程加載新程序并將其附加到接口,然后對接口發送一些數據:

$ sudo bpftool prog load xdp_count_btf.o /sys/fs/bpf/xdp_count_btf type xdp
$ sudo bpftool prog list
$ sudo bpftool net attach xdpgeneric id <program_id> dev test1
$ sudo ./testenv.sh ping
$ sudo ./testenv.sh ping --legacy-ip

最后,打印新程序對應的 map 。如果一切順利,這一次的輸出會有很大的不同。

映射的轉儲值

? 圖 map 的結構的打印值

它不僅以 JSON 格式打印得很漂亮,而且值也是十進制的,使其更具可讀性和易懂性。

3.1 BTF 和 CO-RE

如前所述,BTF 可以啟用 CO-RE 使 BPF 程序可移植到不同的內核版本或用戶配置。我們也可以通過生成內核本身的 BTF 信息來消除對本地內核頭文件的需求:

$ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

上述命令將創建一個巨大的 vmlinux.h 文件,其中包含所有內核類型,包括作為 UAPI 的一部分公開的類型、內部類型和通過 kernel-devel 可用的類型,以及一些其他地方不可用的更多內部類型。在 BPF 程序中,我們可以只?#include "vmlinux.h"?并刪除其他內核頭文件,如 <linux/fs.h>、<linux/sched.h>等。

擺脫內核頭文件依賴性只是 BTF 可以實現的目標的冰山一角。如需 BTF 和 CO-RE 的詳盡解釋,可以閱讀這篇文章。

4. 結論

BTF 是一個非常強大的工具,可以使 BPF 程序更易于調試和移植。由于它是一項相對較新的技術,因此開發仍在進行中,你可以期待在未來看到大量改進。

本文讓你大致了解 BTF 可以實現什么。你可能已經了解了 BPF 的缺點、BPF 是什么以及如何使用 BTF 注解 map 和打印 map 結構。最后,你還了解了 BTF 如何充當通過 CO-RE 增強可移植性的起點。

原文地址:https://www.containiq.com/post/btf-bpf-type-format

作者:Aniket Bhattacharyea

時間: July 13, 2022

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275140.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275140.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275140.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python 混入類MixIn

寫在前面 能把一件事情說的那么清楚明白&#xff0c;感謝廖雪峰的官方網站。 1.為什么要用混入類&#xff1f;&#xff08;小白入門&#xff09; 繼承是面向對象編程的一個重要的方式&#xff0c;因為通過繼承&#xff0c;子類就可以擴展父類的功能。 step1: 回憶一下Animal類層…

關于字符串流的學習(c++)

/* 字符串流 在字符數組中可以存放字符,也可以存放整數、浮點數以及其他類型的數據。在向字符數組存入數據之前,要先將數據從二進制形式轉換為ASCII代碼,然后存放在緩沖區,再從緩沖區送到字符數組。從字符數組讀數據時,先將字符數組中的數據送到緩沖區,在賦給變量前要先將ASCII…

估計很多前端都沒學過單元測試~

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。已進行四個月了&#xff0c;很多小伙伴表示收獲頗豐。想學源碼&#xff0c;極力推薦訂閱我寫的《學習…

xd可以用ui動效效果嗎_通過動畫使UI設計栩栩如生:Adobe XD和After Effects

xd可以用ui動效效果嗎Note — If you don’t fancy splashing out on an Adobe license, you can trial their products for 14 days each. That should give you more than enough time to play, check it out.注意—如果您不愿意花錢購買Adobe許可證&#xff0c;則可以分別試…

BookMarklet:瑞士軍刀你用了嗎?

Bookmarklet 是一段隱藏在鏈接后面的js代碼&#xff0c;可以收藏在收藏夾。通過這段代碼&#xff0c;我們可以跨瀏覽器&#xff08;當然&#xff0c;也跨平臺&#xff09;實現一些工具。比起瀏覽器插件來說&#xff0c;使用更加方便。典型的&#xff0c;dict.cn 網站的工具和有…

第十二周編程總結

這個作業屬于那個課程C語言程序設計II這個作業要求在哪里https://pintia.cn/problem-sets/1127748174659035136/problems/1127749414029729792我在這個課程的目標是更好的學習函數這個作業在那個具體方面幫助我實現目鍛煉了我的編程能力參考文獻c語言程序設計26-1 計算最長的字…

可能是全網首個前端源碼共讀活動,誠邀加入學習

大家好&#xff0c;我是若川。從8月份到現在11月結束了。每周一期&#xff0c;一起讀200行左右的源碼&#xff0c;撰寫輔助文章&#xff0c;截止到現在整整4個月了。由寫有《學習源碼整體架構系列》20余篇的若川【若川視野公眾號號主】傾力組織&#xff0c;召集了各大廠對于源碼…

現代游戲中的UX趨勢

ux設計中的各種地圖游戲UX (GAMES UX) Even though websites and games have matured side-by-side over the past few decades, games have a long and detailed history of user experience. Sure, it was scrappy and fairly rudimentary initially, but the only way you c…

SQL Server 2008 安裝過程中遇到“性能計數器注冊表”..

Windows 2008 系統 SQL Server 2008 性能計數器注冊表作者&#xff1a; 來源&#xff1a; 時間&#xff1a;2010-6-13 完美集成、增強 KindEditor HTML 編輯器今天跟隨部門老大去現場學習&#xff0c;安裝 Windows208 下 SQL Server2008&#xff0c…

你提交代碼前沒有校驗?巧用gitHooks解決

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。已進行四個月了&#xff0c;很多小伙伴表示收獲頗豐。想學源碼&#xff0c;極力推薦訂閱我寫的《學習…

Linux下自動化測試環境的搭建

1.安裝Linux虛擬機&#xff0c;詳情參考 https://blog.csdn.net/qq_22770715/article/details/78558374 https://www.cnblogs.com/Q277227/p/8176564.html 1.1 需要確定IP &#xff0c;使用 ifconfig 1.2 linux的用戶名跟密碼&#xff1b; 1.3 確定可以遠程ssh登錄&…

code craft_以Craft.io為先—關于我們行業的實踐職業道路的系列

code craft重點 (Top highlight)For the past two decades, digital product design / UX has been shifting to become a more strategic discipline within organizations. Partially because business leaders have started to pay attention to how design-driven companie…

Nginx+httpd反代實現動靜分離

什么是動靜分離為了提高網站的響應速度&#xff0c;減輕程序服務器&#xff08;apachephp&#xff0c;nginxphp等&#xff09;的負載&#xff0c;對于靜態資源比如圖片&#xff0c;js&#xff0c;css&#xff0c;html等靜態文件&#xff0c;我們可以在反向代理服務器中設置&…

(建議收藏)前端面試必問的十六條HTTP網絡知識體系

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。已進行四個月了&#xff0c;很多小伙伴表示收獲頗豐。想學源碼&#xff0c;極力推薦訂閱我寫的《學習…

了解 DB2 Version 9.5 中的全局變量(轉)

轉自&#xff1a;http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0711zubiri/ 簡介 在關系數據庫系統內部&#xff0c;應用程序和實際數據庫之間的主要交互都是以會話或連接的 SQL 語句形式來實現的。過去&#xff0c;為了在相同會話中實現不同 SQL 語句之…

jQuery新版本加載json注意事項。

jQuery在1.4版本后&#xff0c;采用了更為嚴格的json解析方式&#xff0c;所以所有內容都必須要有雙引號。比如以前{key:”28CATEGORY”,status:”0″}是沒問題的。但升級成1.4后&#xff0c;都必須加上雙引號&#xff1a;{“key” : “28CATEGORY”,“status” : “0″}如果你…

多邊形的時針方向與法線方向

從相反的法線方向觀察&#xff0c;順時針還是逆時針是相反的。 多邊形的時針方向與法線方向的關系呈右手法則關系。 GoogleEarth中的面具有時針方向&#xff0c;法線方向為正向&#xff0c;反之為負向 GoogleEarth的垂面在法線方向為亮色&#xff0c;反向為暗色 GoogleEarth的水…

裂墻推薦!再也不用求后端給接口了...

大家好&#xff0c;我是若川。今天咱們來介紹一款強大的云服務平臺&#xff01;MemFire Cloud注冊即享5GB存儲空間、每月100萬讀額度和每月10萬寫額度。平臺入口&#xff1a;https://memfiredb.com/今天&#xff08;12月10號&#xff09;還有限時的送書活動&#xff01;感興趣的…

1.今日標簽:視頻價值一千字

I love the App Store. It looks and works better than ever. But also, I love tricky design challenges. How do you improve something that already works great?我喜歡App Store。 它的外觀和工作比以往更好。 但是我也很棘手 設計挑戰。 您如何改善已經很好的工作&a…

Android service 小研究

最近同學搞起了Android開發&#xff0c;自己也撿起來這個玩意來看看。這里先研究一下service Service是安卓系統提供的四種組件之一&#xff0c;功能與activity類似&#xff0c;只不過沒有activity 的使用頻率高。顧名思義Service就是運行在后臺的一種服務程序一般很少與用戶交…