1 Linux 實現注意事項

本文件提供了 eBPF 指令集在 Linux 核心中實現的更多具體細節。

1.1 位元組交換指令

BPF_FROM_LEBPF_FROM_BE 分別作為 BPF_TO_LEBPF_TO_BE 的別名存在。

1.2 跳轉指令

BPF_CALL | BPF_X | BPF_JMP (0x8d),其中輔助函式整數將從指定暫存器中讀取,目前不受驗證器支援。任何包含此指令的程式都將無法載入,直到新增此類支援為止。

1.3 對映

Linux 只支援對包含單個元素的陣列對映執行 'map_val(map)' 操作。

Linux 使用 fd_array 來儲存與 BPF 程式關聯的對映。因此,map_by_idx(imm) 使用該陣列中該索引處的 fd。

1.4 變數

以下 64 位即時指令指定應載入一個變數地址,該地址對應於 ‘imm’ 欄位中儲存的某個整數

操作碼結構

操作碼

虛擬碼

imm 型別

dst 型別

BPF_IMM | BPF_DW | BPF_LD

0x18

0x3

dst = var_addr(imm)

變數 ID

資料指標

在 Linux 上,此整數是一個 BTF ID。

1.5 傳統 BPF 資料包訪問指令

ISA 標準文件中所述,Linux 具有特殊的 eBPF 指令,用於訪問資料包資料,這些指令是從經典 BPF 繼承而來的,旨在保留在 eBPF 直譯器中執行的傳統套接字過濾器的效能。

這些指令有兩種形式:BPF_ABS | <size> | BPF_LDBPF_IND | <size> | BPF_LD

這些指令用於訪問資料包資料,並且只能在程式上下文是指向網路資料包的指標時使用。BPF_ABS 訪問由立即資料指定的絕對偏移處的資料包資料,而 BPF_IND 訪問資料包資料時,其偏移量除了立即資料外還包括一個暫存器的值。

這些指令有七個隱式運算元

  • 暫存器 R6 是一個隱式輸入,它必須包含指向 struct sk_buff 的指標。

  • 暫存器 R0 是一個隱式輸出,其中包含從資料包中獲取的資料。

  • 暫存器 R1-R5 是被指令覆蓋的暫存暫存器。

這些指令也帶有一個隱式的程式退出條件。如果 eBPF 程式試圖訪問超出資料包邊界的資料,程式執行將被中止。

BPF_ABS | BPF_W | BPF_LD (0x20) 意味著

R0 = ntohl(*(u32 *) ((struct sk_buff *) R6->data + imm))

其中 ntohl() 將 32 位值從網路位元組序轉換為主機位元組序。

BPF_IND | BPF_W | BPF_LD (0x40) 意味著

R0 = ntohl(*(u32 *) ((struct sk_buff *) R6->data + src + imm))