我们在所有的P4程序中(.p4文件),都可以发现其拥有5个基本组件:
- 首部(Headers):定义报文头部格式
- 解析器(Parsers):定义数据包解析流程的有限状态机
- 表(Tables):定义匹配域以及对应的执行动作
- 动作(Action):动作指令集,包括构造查找键(Construct lookup keys)、根据查找键查表、执行动作等
- 流控制程序(Controller):控制程序,决定了数据包处理的流程,比如如何在不同表之间跳转等
接下来将就这5个方面进行简要介绍。
首部(Headers)
首部分为两种,一种是包头(Packet Header),一种是元数据(Metadata)。在首部区域除了定义这些结构,还需要进行实例化操作。
- 包头
以ipv4的包头为例,根据下图所示的ipv4结构,

header ethernet_t {
macAddr_t dstAddr;
macAddr_t srcAddr;
bit<16> etherType;
}
header ipv4_t
{
bit<4> version;
bit<4> ihl;
bit<8> diffserv;
bit<16> totallen;
bit<16> identification;
bit<3> flags;
bit<13> fragoffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrchecksum;
bit<32> srcaddr;
bit<32> dstaddr;
}
- 元数据
元数据用来携带数据和配置信息,元数据的声明与包头类似,但在实例化时不同,而且包头和元数据在字段值的约束上存在一定的差别。
元数据分为两种,一种是用来携带P4程序运行过程中产生的数据的用户自定义元数据(User-Defined Metadata),如首部字段的运算结果等。另一种是固有元数据(Intrinsic Metadata),用于携带交换机自身的配置信息,如数据包进入交换机时的端口号等。
关于V1Modeld的元数据如下图所示,其中常见的:ingress_port
表示数据包的入端口;egress_spec
表示指定数据包的出端口(在入口流水线中设置);egress_port
表示数据包离开的端口(在出口流水线中设置)。在使用时,可以直接使用,无需提前自定义。

- 实例化
具体的实例化例子如下所示:
struct headers {
ethernet_t ethernet; //ethernet_t 和 ipv4_t 都是之前定义的包头
ipv4_t ipv4;
}
解析器(Parsers)
一个P4程序中往往定义了大量的首部和首部实例,但并不是所有的首部实例都会对数据包进行操作。解析器工作时会生成描述数据包进行哪些匹配+动作操作的中间表示,在P4中称之为解析后表示,这些解析后表示规定了对数据包生效的实例,是一组对数据包生效的实例的集合。
P4语言中解析器采用有限状态机的设计思路,每个解析器方法视为一种状态。当解析器工作时,会将当前处理的数据包头字节的偏移量记录在首部实例中,并在状态迁移(调用另一个解析器)时指向包头中下一个待处理的有效字节。
针对上述的以太网和ipv4的头部定义,对应解析过程如下,其中transition
即表示状态转移过程。
parser MyParser(packet_in packet,
out headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
state start {
transition parse_ethernet;
}
state parse_ethernet {
packet.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType) {
TYPE_IPV4: parse_ipv4;
default: accept;
}
}
state parse_ipv4 {
packet.extract(hdr.ipv4);
transition accept;
}
}
表(Tables)
定义了匹配字段(key)、可选的动作(action)和一些其他相关属性。
table ipv4_lpm {
key = {
hdr.ipv4.dstAddr: lpm;
}
actions = {
ipv4_forward;
drop;
NoAction;
}
size = 1024;
default_action = drop();
}
在上述例子中,对于匹配字段的匹配方式,有如下几种:
- lpm:最长前缀匹配
- exact:精确匹配
- ternary:三元匹配
除了匹配字段和对应可选动作以外,表中还可以定义了一些其他属性,例如上述例子中的default_action
等,相关属性与功能如下表。
其他属性 | 功能 |
---|---|
default_action | 当table miss的时候执行的动作 |
counters | 计数器 |
implementation | 指定表实际运作方式,这部分通常取决于架构,例如v1model中action profile提供了通过hash的方式随机选择一个action profile member去执行。 |
size | 表的大小 |
const entries | 预设的table entry,在编译阶段会写到编译好的档案中 |
动作(Action)
动作会在表中被引用,可以读取控制平面提供的数据,指导数据平面的工作。
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port)
{
standard_metadata.egress_spec = port;
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
hdr.ethernet.dstAddr = dstAddr;
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
}
流控制程序(Controller)
可以把control block认为是流水线操作的一个模板,v1model中就是ingress和egress,其主要的功能就是知道每一个封包经过的table顺序以及采用的规则(触发条件等)。还能放置一些其他的功能部件,例如计数器counter等。