2.1.1 cBPF指令集

本小节先对cBPF指令集进行介绍,随后探讨eBPF指令架构的关键组成部分。通过逐一分析这些要素,我们可以更好地理解eBPF指令集的设计原理和它在内核编程中的应用。

cBPF指令集用于在内核级别快速评估网络数据包,从而决定是否需要将这些数据包传递给用户空间的程序进行进一步处理。

cBPF指令集是相对简单的,由一系列固定长度(通常为32位)的指令组成。cBPF虚拟机是一个基于寄存器的处理器模型,拥有一个累加器(用于计算和存储结果),一个索引寄存器(用于数组和内存访问),一个程序计数器(用于控制指令流程),以及一个数据内存存储区域。

1.寄存器

cBPF使用两个主要的寄存器,一个累加器(A寄存器)和一个索引寄存器(X寄存器)。累加器用于执行算术和逻辑运算,而X寄存器主要用于内存访问。

2.指令编码

cBPF指令编码如表2-2所示。

表2-2 cBPF指令编码

表2-2中的各个字段的含义如下。

❑操作码:指示要执行的操作类型,包括加载、存储、逻辑运算(如加、减、乘、除、与、或、非、左移、右移等)、跳转等。

❑jt(跳转真):当条件判断为真时,指示程序要跳转到下一条指令的偏移量。

❑jf(跳转假):当条件判断为假时,指示程序要跳转到下一条指令的偏移量。

❑k(常量):根据操作码的不同而具有不同的含义,一般用来作为偏移量。

使用网络抓包工具tcpdump的-d参数可以显示捕获数据包的原始指令,比如要抓取IPv4的数据包且TCP源端口是80,可使用命令tcpdump-d 'ip and tcp src port 80,执行结果如下所示:

tcpdump的-dd参数,可以将cBPF的指令助记符转换成具体的指令数值,命令为tcpdump-dd 'ip and tcp src port 80,执行结果如下所示:

在第9行的指令中,0x15是操作码,表示这是一个条件相等(JEQ)跳转指令;0x00000050是k字段,存储了需要比较的值80。0是JT字段数值,如果为真(寄存器A内容与80数值相等)则执行偏移量为0的指令(即下一条指令,此例为第10行);1是JF字段,如果为假则跳转到偏移量为1的指令执行(此例为第11行)。

3.指令类型

cBPF支持以下几种指令类型。

1)加载指令(LD/LDX):用于从数据包或寄存器中加载数据。

2)存储指令(ST/STX):用于将数据存储到寄存器或内存位置。

3)算术指令:包括加法(ADD)、减法(SUB)、乘法(MUL)、除法(DIV)等。

4)位操作指令:包括AND、OR、左移(LSH)、右移(RSH)等。

5)跳转指令:用于基于条件的程序执行流控制。