bpf 指令用于过滤逻辑 (filter program) 是有一个指令数组表示。
只有向前跳转
ret指令结束过滤
每一个指令操作 bpf虚拟机的内部状态
包括
累加器:accumulator,
指示器:index register,
bpf内存:memory store,
pc 程序指针: program counter.
指令格式
/*
* The instruction data structure.
*/
struct bpf_insn {
u_short code; /* 16bit 这条指令做什么 */
u_char jt; /* jump if true 如果为真 跳转的位置 */
u_char jf; /* jump if false 如果为假 跳转的位置 */
bpf_int32 k; // int
};
所有的指令分为8类:
BPF_LD, BPF_LDX加载指令
BPF_ST, BPF_STX存储指令
BPF_ALU, 计算指令
BPF_JMP, 跳转指令
BPF_RET, 返回指令 (结束指令)
BPF_MISC, 其他指令
内存大小: BPF_MEMWORDS ==> 16
1) load指令
BPF_LD 9条指令
BPF_LD+BPF_W+BPF_ABS
A <- P[k:4] (p是报文首地址, k是一个立即数, A 是累计器)
BPF_LD+BPF_H+BPF_ABS
A <- P[k:2]
BPF_LD+BPF_B+BPF_ABS
ldh [12] ===> 标识加载报文的偏移12个字节的 hardword(也就是16bit) 以太网报文头 6bytes的源mac+6位目的mac 之后就是ethetype 上层协议
ethetype: ip #800
9c 21 6a 95 3f ac 84 34 97 94 03 ef 【08 00】 45 00 (ip 协议)
BPF_LD+BPF_W+BPF_IND
A <- P[X+k:4] (X 是指示器)
BPF_LD+BPF_H+BPF_IND
A <- P[X+k:2]
BPF_LD+BPF_B+BPF_IND
A <- P[X+k:1]
BPF_LD+BPF_W+BPF_LEN
A <- len (len是报文的长度)
BPF_LD+BPF_IMM
A <- k (器存器的值是 k)
BPF_LD+BPF_MEM
A <- M[k] (把内存的第k个字(word 4byte) 的值赋值到累加器中 )
LDX(X = index :指示器) 4 调指令
BPF_LDX+BPF_W+BPF_IMM
X <- k (把k值加载到指示器)
BPF_LDX+BPF_W+BPF_MEM
X <- M[k] (加载内存值到指示器)
BPF_LDX+BPF_W+BPF_LEN
X <- len (加载报文长度到 指示器中)
BPF_LDX+BPF_B+BPF_MSH
X <- 4*(P[k:1]&0xf) (加载ip头部长度到指示器中)
45 00 00 3c 47 c0 40 00 40 06 0a 95 c0 a8 01 0b 其中0x5 表示ip头长度字段 实际长度是 5*4=20byte的ip头
BPF_ST 保存指令
BPF_ST
M[k] <- A 所有保存值到内存都通过 累加器 所有很简单的指令
BPF_STX (保存指示器的值到内存中)
M[k] <- X
BPF_ALU
操作数 累加器, 指示器, 常量
BPF_ALU+BPF_ADD+BPF_K 操作立即数 k
A <- A + k
BPF_ALU+BPF_SUB+BPF_K
A <- A - k
BPF_ALU+BPF_MUL+BPF_K
A <- A * k
BPF_ALU+BPF_DIV+BPF_K
A <- A / k
BPF_ALU+BPF_AND+BPF_K
A <- A & k
BPF_ALU+BPF_OR+BPF_K
A <- A | k
BPF_ALU+BPF_LSH+BPF_K
A <- A << k
BPF_ALU+BPF_RSH+BPF_K
A <- A >> k
BPF_ALU+BPF_ADD+BPF_X 操作指示器X
A <- A + X
BPF_ALU+BPF_SUB+BPF_X
A <- A - X
BPF_ALU+BPF_MUL+BPF_X
A <- A * X
BPF_ALU+BPF_DIV+BPF_X
A <- A / X
BPF_ALU+BPF_AND+BPF_X
A <- A & X
BPF_ALU+BPF_OR+BPF_X
A <- A | X
BPF_ALU+BPF_LSH+BPF_X
A <- A << X
BPF_ALU+BPF_RSH+BPF_X
A <- A >> X
BPF_ALU+BPF_NEG 取负指令
A <- -A
BPF_JMP 跳转指令
操作数是无符号的
条件跳转 jt jf 只有8bit 最远是255的偏移
无条件跳转可跳32bit的数
BPF_JMP+BPF_JA
pc += k (跳转到下k调指令处)
BPF_JMP+BPF_JA
pc += k
BPF_JMP+BPF_JGT+BPF_K
pc += (A > k) ? jt : jf
BPF_JMP+BPF_JGE+BPF_K
pc += (A >= k) ? jt : jf
BPF_JMP+BPF_JEQ+BPF_K
pc += (A == k) ? jt : jf
BPF_JMP+BPF_JSET+BPF_K
pc += (A & k) ? jt : jf
BPF_JMP+BPF_JGT+BPF_X
pc += (A > X) ? jt : jf
BPF_JMP+BPF_JGE+BPF_X
pc += (A >= X) ? jt : jf
BPF_JMP+BPF_JEQ+BPF_X
pc += (A == X) ? jt : jf
BPF_JMP+BPF_JSET+BPF_X
pc += (A & X) ? jt : jf
返回指令
如果返回0 表示忽略此报文
BPF_RET+BPF_A
accept A bytes
BPF_RET+BPF_K
accept k bytes
BPF_MISC+BPF_TAX (t = transfer)
X <- A (累加器的值 赋给 指示器)
BPF_MISC+BPF_TXA
A <- X