1 BPF 指令集架構 (ISA)¶
eBPF,通常也稱為 BPF,是一項起源於 Linux 核心的技術,可以在特權上下文中(例如作業系統核心)執行不受信任的程式。本文件規定了 BPF 指令集架構 (ISA)。
作為歷史註釋,BPF 最初代表伯克利資料包過濾器,但現在它可以做的資料包過濾之外的事情太多了,這個首字母縮略詞不再有意義。 BPF 現在被認為是一個獨立術語,不代表任何東西。原始 BPF 有時被稱為 cBPF(經典 BPF),以區別於現在廣泛部署的 eBPF(擴充套件 BPF)。
1.1 文件約定¶
本文件中的關鍵詞“必須 (MUST)”、“不得 (MUST NOT)”、“必需 (REQUIRED)”、“應該 (SHALL)”、“不應該 (SHALL NOT)”、“應當 (SHOULD)”、“不應當 (SHOULD NOT)”、“推薦 (RECOMMENDED)”、“不推薦 (NOT RECOMMENDED)”、“可以 (MAY)”和“可選 (OPTIONAL)”應按照 BCP 14 https://www.rfc-editor.org/info/rfc2119 https://www.rfc-editor.org/info/rfc8174 中的描述進行解釋,當且僅當它們全部以大寫形式出現時,如此處所示。
為了簡潔和一致,本文件使用簡寫語法來引用型別族,並在描述指令的語義時引用幾個說明性的助記函式。這些型別的有效值範圍和這些函式的語義在以下小節中定義。
1.1.1 型別¶
本文件使用符號 SN 來引用整數型別,以分別指定型別的符號 (S) 和位寬 (N)。
S |
含義 |
|---|---|
u |
無符號 |
s |
有符號 |
N |
位寬 |
|---|---|
8 |
8 位 |
16 |
16 位 |
32 |
32 位 |
64 |
64 位 |
128 |
128 位 |
例如,u32 是一種型別,其有效值是所有 32 位無符號數,而 s16 是一種型別,其有效值是所有 16 位有符號數。
1.1.2 函式¶
以下位元組交換函式與方向無關。也就是說,對於下面討論的任一方向的轉換,都使用相同的函式。
be16:接受一個無符號 16 位數字,並在主機位元組順序和大端 (IEN137) 位元組順序之間進行轉換。
be32:接受一個無符號 32 位數字,並在主機位元組順序和大端位元組順序之間進行轉換。
be64:接受一個無符號 64 位數字,並在主機位元組順序和大端位元組順序之間進行轉換。
bswap16:接受一個大端或小端格式的無符號 16 位數字,並返回等效的數字,但位寬相同,但位元組序相反。
bswap32:接受一個大端或小端格式的無符號 32 位數字,並返回等效的數字,但位寬相同,但位元組序相反。
bswap64:接受一個大端或小端格式的無符號 64 位數字,並返回等效的數字,但位寬相同,但位元組序相反。
le16:接受一個無符號 16 位數字,並在主機位元組順序和小端位元組順序之間進行轉換。
le32:接受一個無符號 32 位數字,並在主機位元組順序和小端位元組順序之間進行轉換。
le64:接受一個無符號 64 位數字,並在主機位元組順序和小端位元組順序之間進行轉換。
1.1.3 定義¶
- 符號擴充套件¶
要將 X 位數字 A 符號擴充套件為 Y 位數字 B,表示
將 A 中的所有
X位複製到 B 的較低X位。將 B 的剩餘
Y-X位的值設定為 A 的最高有效位的值。
示例
在大端平臺上將 8 位數字 A 符號擴充套件為 16 位數字 B
A: 10000110
B: 11111111 10000110
1.1.4 一致性組¶
實現不需要支援本文件中指定的所有指令(例如,已棄用的指令)。相反,指定了多個一致性組。實現必須支援 base32 一致性組,並且可以支援其他一致性組,其中支援一致性組意味著它必須支援該一致性組中的所有指令。
命名一致性組的使用實現了執行指令的執行時與生成執行時指令的工具(如編譯器)之間的互操作性。因此,對一致性組的能力發現可能由使用者手動完成,也可能由工具自動完成。
每個一致性組都有一個簡短的 ASCII 標籤(例如,“base32”),對應於一組強制性指令。也就是說,每個指令都有一個或多個它所屬的一致性組。
本文件定義了以下一致性組
base32:包括本規範中定義的所有指令,除非另有說明。
base64:包括 base32,以及明確指出屬於 base64 一致性組的指令。
atomic32:包括 32 位原子操作指令(參見原子操作)。
atomic64:包括 atomic32,以及 64 位原子操作指令。
divmul32:包括 32 位除法、乘法和模數指令。
divmul64:包括 divmul32,以及 64 位除法、乘法和模數指令。
packet:已棄用的資料包訪問指令。
1.2 指令編碼¶
BPF 有兩種指令編碼
基本指令編碼,使用 64 位來編碼指令
寬指令編碼,在基本指令之後附加第二個 64 位,總共 128 位。
1.2.1 基本指令編碼¶
基本指令編碼如下
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| opcode | regs | offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| imm |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- 操作碼
要執行的操作,編碼如下
+-+-+-+-+-+-+-+-+ |specific |class| +-+-+-+-+-+-+-+-+
- 特定的
這些位的格式因指令類而異
- 類
指令類(參見指令類)
- 暫存器
源暫存器和目標暫存器號,在小端主機上編碼如下
+-+-+-+-+-+-+-+-+ |src_reg|dst_reg| +-+-+-+-+-+-+-+-+
在大端主機上編碼如下
+-+-+-+-+-+-+-+-+ |dst_reg|src_reg| +-+-+-+-+-+-+-+-+
- src_reg
源暫存器號 (0-10),除非另有說明(64 位立即數指令將此欄位重用於其他目的)
- dst_reg
目標暫存器號 (0-10),除非另有說明(未來的指令可能會將此欄位重用於其他目的)
- 偏移量
與指標運算一起使用的有符號整數偏移量,除非另有說明(某些算術指令將此欄位重用於其他目的)
- imm
有符號整數立即數值
請注意,多位元組欄位(“offset”和“imm”)的內容在使用大端位元組順序的主機上使用大端位元組順序儲存,而在使用小端位元組順序的主機上使用小端位元組順序儲存。
例如
opcode offset imm assembly
src_reg dst_reg
07 0 1 00 00 44 33 22 11 r1 += 0x11223344 // little
dst_reg src_reg
07 1 0 00 00 11 22 33 44 r1 += 0x11223344 // big
請注意,大多數指令不使用所有欄位。未使用的欄位應清除為零。
1.2.2 寬指令編碼¶
某些指令被定義為使用寬指令編碼,它使用兩個 32 位立即數值。基本指令格式之後的 64 位包含一個偽指令,其中 “opcode”、“dst_reg”、“src_reg” 和 “offset” 全部設定為零。
這在下圖中描述
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| opcode | regs | offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| imm |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| next_imm |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- 操作碼
要執行的操作,如上所述編碼
- 暫存器
源暫存器號和目標暫存器號(除非另有說明),如上所述編碼
- 偏移量
與指標運算一起使用的有符號整數偏移量,除非另有說明
- imm
有符號整數立即數值
- 保留
未使用,設定為零
- next_imm
第二個有符號整數立即數值
1.2.3 指令類¶
“opcode” 欄位的三個最低有效位儲存指令類
類 |
值 |
描述 |
參考 |
|---|---|---|---|
LD |
0x0 |
非標準載入操作 |
|
LDX |
0x1 |
載入到暫存器操作 |
|
ST |
0x2 |
從立即數儲存操作 |
|
STX |
0x3 |
從暫存器儲存操作 |
|
ALU |
0x4 |
32 位算術運算 |
|
JMP |
0x5 |
64 位跳轉操作 |
|
JMP32 |
0x6 |
32 位跳轉操作 |
|
ALU64 |
0x7 |
64 位算術運算 |
1.3 算術和跳轉指令¶
對於算術和跳轉指令 (ALU、ALU64、JMP 和 JMP32),8 位 “opcode” 欄位分為三個部分
+-+-+-+-+-+-+-+-+
| code |s|class|
+-+-+-+-+-+-+-+-+
- 程式碼
操作碼,其含義因指令類而異
- s(源)
源運算元位置,除非另有說明,否則為以下之一
源運算元位置¶ 來源
值
描述
K
0
使用 32 位 “imm” 值作為源運算元
X
1
使用 “src_reg” 暫存器值作為源運算元
- 指令類
指令類(參見指令類)
1.3.1 算術指令¶
ALU 使用 32 位寬運算元,而 ALU64 使用 64 位寬運算元進行其他相同的操作。ALU64 指令屬於 base64 一致性組,除非另有說明。“code” 欄位編碼如下操作,其中 “src” 指的是源運算元,“dst” 指的是目標暫存器的值。
名稱 |
程式碼 |
偏移量 |
描述 |
|---|---|---|---|
ADD |
0x0 |
0 |
dst += src |
SUB |
0x1 |
0 |
dst -= src |
MUL |
0x2 |
0 |
dst *= src |
DIV |
0x3 |
0 |
dst = (src != 0) ? (dst / src) : 0 |
SDIV |
0x3 |
1 |
dst = (src == 0) ? 0 : ((src == -1 && dst == LLONG_MIN) ? LLONG_MIN : (dst s/ src)) |
OR |
0x4 |
0 |
dst |= src |
AND |
0x5 |
0 |
dst &= src |
LSH |
0x6 |
0 |
dst <<= (src & mask) |
RSH |
0x7 |
0 |
dst >>= (src & mask) |
NEG |
0x8 |
0 |
dst = -dst |
MOD |
0x9 |
0 |
dst = (src != 0) ? (dst % src) : dst |
SMOD |
0x9 |
1 |
dst = (src == 0) ? dst : ((src == -1 && dst == LLONG_MIN) ? 0: (dst s% src)) |
XOR |
0xa |
0 |
dst ^= src |
MOV |
0xb |
0 |
dst = src |
MOVSX |
0xb |
8/16/32 |
dst = (s8,s16,s32)src |
ARSH |
0xc |
0 |
符號擴充套件 dst >>= (src & mask) |
END |
0xd |
0 |
位元組交換操作(參見下面的位元組交換指令) |
算術運算期間允許下溢和溢位,這意味著 64 位或 32 位值將環繞。如果 BPF 程式執行導致除以零,則目標暫存器將設定為零。否則,對於 ALU64,如果執行將導致 LLONG_MIN 除以 -1,則目標暫存器將設定為 LLONG_MIN。對於 ALU,如果執行將導致 INT_MIN 除以 -1,則目標暫存器將設定為 INT_MIN。
如果執行將導致模數為零,則對於 ALU64,目標暫存器的值不變,而對於 ALU,目標暫存器的較高 32 位將清零。否則,對於 ALU64,如果執行將導致 LLONG_MIN 模數 -1,則目標暫存器將設定為 0。對於 ALU,如果執行將導致 INT_MIN 模數 -1,則目標暫存器將設定為 0。
{ADD, X, ALU},其中 “code” = ADD,“source” = X 並且 “class” = ALU 表示
dst = (u32) ((u32) dst + (u32) src)
其中 “(u32)” 表示較高 32 位已清零。
{ADD, X, ALU64} 表示
dst = dst + src
{XOR, K, ALU} 表示
dst = (u32) dst ^ (u32) imm
{XOR, K, ALU64} 表示
dst = dst ^ imm
請注意,大多數算術指令的 “offset” 設定為 0。只有三個指令 (SDIV、SMOD、MOVSX) 具有非零 “offset”。
對於 ALU 的除法、乘法和模數運算是 “divmul32” 一致性組的一部分,對於 ALU64 的除法、乘法和模數運算是 “divmul64” 一致性組的一部分。除法和模數運算支援無符號和有符號形式。
對於無符號運算 (DIV 和 MOD),對於 ALU,“imm” 被解釋為 32 位無符號值。對於 ALU64,“imm” 首先從 32 位符號擴充套件到 64 位,然後被解釋為 64 位無符號值。
對於有符號運算 (SDIV 和 SMOD),對於 ALU,“imm” 被解釋為 32 位有符號值。對於 ALU64,“imm” 首先從 32 位符號擴充套件到 64 位,然後被解釋為 64 位有符號值。
請注意,當被除數或除數為負數時,有符號模數運算有不同的定義,其中實現通常因語言而異,因此 Python、Ruby 等與 C、Go、Java 等不同。此規範要求有符號模數必須使用截斷除法(其中 -13 % 3 == -1),如 C、Go 等中實現的那樣。
a % n = a - n * trunc(a / n)
MOVSX 指令執行帶有符號擴充套件的移動操作。{MOVSX, X, ALU} 將 8 位和 16 位運算元符號擴充套件為 32 位運算元,並將剩餘的較高 32 位清零。{MOVSX, X, ALU64} 將 8 位、16 位和 32 位運算元符號擴充套件為 64 位運算元。與其他算術指令不同,MOVSX 僅為暫存器源運算元 (X) 定義。
{MOV, K, ALU64} 表示
dst = (s64)imm
{MOV, X, ALU} 表示
dst = (u32)src
{MOVSX, X, ALU} 且 “offset” 為 8 表示
dst = (u32)(s32)(s8)src
NEG 指令僅在源位清除 (K) 時定義。
移位操作對於 64 位操作使用 0x3F (63) 的掩碼,對於 32 位操作使用 0x1F (31) 的掩碼。
1.3.2 位元組交換指令¶
位元組交換指令使用 ALU 和 ALU64 的指令類,以及 END 的 4 位 “code” 欄位。
位元組交換指令僅對目標暫存器進行操作,不使用單獨的源暫存器或立即數值。
對於 ALU,操作碼中的 1 位源運算元欄位用於選擇操作轉換自或轉換到的位元組順序。對於 ALU64,操作碼中的 1 位源運算元欄位保留,必須設定為 0。
類 |
來源 |
值 |
描述 |
|---|---|---|---|
ALU |
LE |
0 |
在主機位元組順序和小端之間轉換 |
ALU |
BE |
1 |
在主機位元組順序和大端之間轉換 |
ALU64 |
保留 |
0 |
無條件地進行位元組交換 |
“imm” 欄位編碼交換操作的寬度。支援以下寬度:16、32 和 64。寬度 64 操作屬於 base64 一致性組,其他交換操作屬於 base32 一致性組。
示例
{END, LE, ALU} 且 “imm” = 16/32/64 表示
dst = le16(dst)
dst = le32(dst)
dst = le64(dst)
{END, BE, ALU} 且 “imm” = 16/32/64 表示
dst = be16(dst)
dst = be32(dst)
dst = be64(dst)
{END, TO, ALU64} 且 “imm” = 16/32/64 表示
dst = bswap16(dst)
dst = bswap32(dst)
dst = bswap64(dst)
1.3.3 跳轉指令¶
JMP32 使用 32 位寬運算元並指示 base32 一致性組,而 JMP 使用 64 位寬運算元進行其他相同的操作,並指示 base64 一致性組,除非另有說明。“code” 欄位編碼如下操作
程式碼 |
值 |
src_reg |
描述 |
備註 |
|---|---|---|---|---|
JA |
0x0 |
0x0 |
PC += 偏移量 |
僅限 {JA, K, JMP} |
JA |
0x0 |
0x0 |
PC += imm |
僅限 {JA, K, JMP32} |
JEQ |
0x1 |
任何 |
如果 dst == src,則 PC += 偏移量 |
|
JGT |
0x2 |
任何 |
如果 dst > src,則 PC += 偏移量 |
無符號 |
JGE |
0x3 |
任何 |
如果 dst >= src,則 PC += 偏移量 |
無符號 |
JSET |
0x4 |
任何 |
如果 dst & src,則 PC += 偏移量 |
|
JNE |
0x5 |
任何 |
如果 dst != src,則 PC += 偏移量 |
|
JSGT |
0x6 |
任何 |
如果 dst > src,則 PC += 偏移量 |
有符號 |
JSGE |
0x7 |
任何 |
如果 dst >= src,則 PC += 偏移量 |
有符號 |
CALL |
0x8 |
0x0 |
按靜態 ID 呼叫輔助函式 |
僅限 {CALL, K, JMP},請參見輔助函式 |
CALL |
0x8 |
0x1 |
呼叫 PC += imm |
僅限 {CALL, K, JMP},請參見程式本地函式 |
CALL |
0x8 |
0x2 |
按 BTF ID 呼叫輔助函式 |
僅限 {CALL, K, JMP},請參見輔助函式 |
EXIT |
0x9 |
0x0 |
返回 |
僅限 {CALL, K, JMP} |
JLT |
0xa |
任何 |
如果 dst < src,則 PC += 偏移量 |
無符號 |
JLE |
0xb |
任何 |
如果 dst <= src,則 PC += 偏移量 |
無符號 |
JSLT |
0xc |
任何 |
如果 dst < src,則 PC += 偏移量 |
有符號 |
JSLE |
0xd |
任何 |
如果 dst <= src,則 PC += 偏移量 |
有符號 |
其中 “PC” 表示程式計數器,要遞增的偏移量以 64 位指令為單位,相對於跳轉指令之後的指令。因此,“PC += 1” 會跳過下一條指令的執行(如果它是基本指令),如果下一條指令是 128 位寬指令,則會導致未定義的行為。
示例
{JSGE, X, JMP32} 表示
if (s32)dst s>= (s32)src goto +offset
其中 “s>=” 表示有符號 “>=” 比較。
{JLE, K, JMP} 表示
if dst <= (u64)(s64)imm goto +offset
{JA, K, JMP32} 表示
gotol +imm
其中 “imm” 表示分支偏移量來自 “imm” 欄位。
請注意,JA 指令有兩種形式。JMP 類允許由 “offset” 欄位指定的 16 位跳轉偏移量,而 JMP32 類允許由 “imm” 欄位指定的 32 位跳轉偏移量。大於 16 位的條件跳轉可以轉換為小於 16 位的條件跳轉加上 32 位無條件跳轉。
所有 CALL 和 JA 指令都屬於 base32 一致性組。
1.3.3.1 輔助函式¶
輔助函式是一個概念,BPF 程式可以透過它呼叫底層平臺公開的一組函式呼叫。
從歷史上看,每個輔助函式都由 “imm” 欄位中編碼的靜態 ID 標識。輔助函式的進一步文件不在本文件的範圍內,標準化留給未來的工作,但使用已廣泛部署,更多資訊可以在特定於平臺的文件中找到(例如,Linux 核心文件)。
支援 BPF 型別格式 (BTF) 的平臺支援透過編碼在 ‘imm’ 欄位中的 BTF ID 來識別輔助函式,其中 BTF ID 標識輔助函式的名稱和型別。BTF 的進一步文件不在本文件的範圍內,標準化留待未來進行,但其使用已得到廣泛部署,更多資訊可以在特定於平臺的文件中找到 (例如,Linux 核心文件)。
1.3.3.2 程式本地函式¶
程式本地函式是由與呼叫者相同的 BPF 程式公開的函式,並透過相對於呼叫指令後一條指令的偏移量來引用,類似於 JA。偏移量編碼在呼叫指令的 ‘imm’ 欄位中。程式本地函式中的 EXIT 將返回到呼叫者。
1.4 載入和儲存指令¶
對於載入和儲存指令 (LD、LDX、ST 和 STX),8 位 ‘opcode’ 欄位的劃分如下
+-+-+-+-+-+-+-+-+
|mode |sz |class|
+-+-+-+-+-+-+-+-+
- 模式
模式修飾符是以下之一
模式修飾符¶ 模式修飾符
值
描述
參考
IMM
0
64 位立即數指令
ABS
1
傳統 BPF 資料包訪問(絕對)
IND
2
傳統 BPF 資料包訪問(間接)
MEM
3
常規載入和儲存操作
MEMSX
4
符號擴充套件載入操作
ATOMIC
6
原子操作
- sz(大小)
大小修飾符是以下之一
大小修飾符¶ 大小
值
描述
W
0
字(4 位元組)
H
1
半字(2 位元組)
B
2
位元組
DW
3
雙字(8 位元組)
使用
DW的指令屬於 base64 一致性組。- 類
指令類(參見指令類)
1.4.1 常規載入和儲存操作¶
MEM 模式修飾符用於編碼在暫存器和記憶體之間傳輸資料的常規載入和儲存指令。
{MEM, <size>, STX} 表示
*(size *) (dst + offset) = src
{MEM, <size>, ST} 表示
*(size *) (dst + offset) = imm
{MEM, <size>, LDX} 表示
dst = *(unsigned size *) (src + offset)
其中 ‘<size>’ 是以下之一:B、H、W 或 DW,並且 ‘無符號大小’ 是以下之一:u8、u16、u32 或 u64。
1.4.2 符號擴充套件載入操作¶
MEMSX 模式修飾符用於編碼在暫存器和記憶體之間傳輸資料的符號擴充套件載入指令。
{MEMSX, <size>, LDX} 表示
dst = *(signed size *) (src + offset)
其中 ‘<size>’ 是以下之一:B、H 或 W,並且 ‘有符號大小’ 是以下之一:s8、s16 或 s32。
1.4.3 原子操作¶
原子操作是對記憶體進行操作的操作,不會被其他 BPF 程式或本規範之外的其他方式對同一記憶體區域的訪問中斷或破壞。
BPF 支援的所有原子操作都編碼為使用 ATOMIC 模式修飾符的儲存操作,如下所示
對於 32 位操作,
{ATOMIC, W, STX},它是 “atomic32” 一致性組的一部分。對於 64 位操作,
{ATOMIC, DW, STX},它是 “atomic64” 一致性組的一部分。不支援 8 位和 16 位寬的原子操作。
‘imm’ 欄位用於編碼實際的原子操作。簡單的原子操作使用在 ‘imm’ 欄位中定義的用於編碼算術操作的值的子集來編碼原子操作
imm |
值 |
描述 |
|---|---|---|
ADD |
0x00 |
原子加 |
OR |
0x40 |
原子或 |
AND |
0x50 |
原子與 |
XOR |
0xa0 |
原子異或 |
帶有 ‘imm’ = ADD 的 {ATOMIC, W, STX} 表示
*(u32 *)(dst + offset) += src
帶有 ‘imm’ = ADD 的 {ATOMIC, DW, STX} 表示
*(u64 *)(dst + offset) += src
除了簡單的原子操作之外,還有一個修飾符和兩個複雜的原子操作
imm |
值 |
描述 |
|---|---|---|
FETCH |
0x01 |
修飾符:返回舊值 |
XCHG |
0xe0 | FETCH |
原子交換 |
CMPXCHG |
0xf0 | FETCH |
原子比較和交換 |
對於簡單的原子操作,FETCH 修飾符是可選的,對於複雜的原子操作始終設定。如果設定了 FETCH 標誌,則該操作也會使用修改之前記憶體中的值覆蓋 src。
XCHG 操作原子地將 src 與 dst + offset 定址的值交換。
CMPXCHG 操作原子地將 dst + offset 定址的值與 R0 比較。如果它們匹配,則 dst + offset 定址的值將替換為 src。在任何情況下,操作之前 dst + offset 處的值都會被零擴充套件並載入回 R0。
1.4.4 64 位立即數指令¶
帶有 IMM ‘模式’ 修飾符的指令使用 指令編碼中定義的寬指令編碼,並使用基本指令的 ‘src_reg’ 欄位來儲存操作碼子型別。
下表定義了一組帶有 ‘src_reg’ 欄位中操作碼子型別的 {IMM, DW, LD} 指令,使用新的術語,如 “map”,在下面進一步定義
src_reg |
虛擬碼 |
imm 型別 |
dst 型別 |
|---|---|---|---|
0x0 |
dst = (next_imm << 32) | imm |
整數 |
整數 |
0x1 |
dst = map_by_fd(imm) |
map fd |
map |
0x2 |
dst = map_val(map_by_fd(imm)) + next_imm |
map fd |
資料地址 |
0x3 |
dst = var_addr(imm) |
變數 ID |
資料地址 |
0x4 |
dst = code_addr(imm) |
整數 |
程式碼地址 |
0x5 |
dst = map_by_idx(imm) |
map 索引 |
map |
0x6 |
dst = map_val(map_by_idx(imm)) + next_imm |
map 索引 |
資料地址 |
其中
map_by_fd(imm) 表示將 32 位檔案描述符轉換為 map 的地址(請參閱 Maps)
map_by_idx(imm) 表示將 32 位索引轉換為 map 的地址
map_val(map) 獲取給定 map 中第一個值的地址
var_addr(imm) 獲取具有給定 id 的平臺變數(請參閱 平臺變數)的地址
code_addr(imm) 獲取指定相對偏移量的指令地址,以(64 位)指令數為單位
反彙編程式可以使用 ‘imm type’ 進行顯示
驗證和 JIT 編譯可以使用 ‘dst type’
1.4.4.1 Maps¶
Map 是某些平臺上 BPF 程式可訪問的共享記憶體區域。Map 可以具有各種語義,如單獨的文件中所定義,並且可能具有也可能沒有單個連續的記憶體區域,但 ‘map_val(map)’ 目前僅為具有單個連續記憶體區域的 map 定義。
如果平臺支援,每個 map 都可以具有檔案描述符 (fd),其中 ‘map_by_fd(imm)’ 表示獲取具有指定檔案描述符的 map。每個 BPF 程式也可以定義為使用載入時與程式關聯的一組 map,並且 ‘map_by_idx(imm)’ 表示獲取具有 BPF 程式包含指令的集合中給定索引的 map。
1.4.4.2 平臺變數¶
平臺變數是由執行時公開並透過整數 id 標識的記憶體區域,某些平臺上的 BPF 程式可以訪問這些記憶體區域。‘var_addr(imm)’ 操作表示獲取由給定 id 標識的記憶體區域的地址。
1.4.5 傳統 BPF 資料包訪問指令¶
BPF 之前引入了特殊的指令來訪問資料包資料,這些指令是從經典 BPF 繼承而來的。這些指令使用了 LD 的指令類,W、H 或 B 的大小修飾符,以及 ABS 或 IND 的模式修飾符。‘dst_reg’ 和 ‘offset’ 欄位設定為零,對於 ABS,‘src_reg’ 設定為零。但是,這些指令已被棄用,不應再使用。所有傳統資料包訪問指令都屬於 “packet” 一致性組。