1 Linux 实现说明¶
本文档提供了有关 eBPF 指令集 Linux 内核实现的更多具体细节。
1.1 字节交换指令¶
BPF_FROM_LE
和 BPF_FROM_BE
分别是 BPF_TO_LE
和 BPF_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”字段中存储的某个整数对应的变量地址
操作码构造 |
操作码 |
src |
伪代码 |
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_LD
和 BPF_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))