上一篇文章主要介绍了P4的一些前置知识,文章最后也介绍了P4的模版,本次主要着重介绍具体内容。
下面展示了一个标准的P4程序模板:
#include <tna.p4>
#include <core.p4>
struct my_ingress_header_t{}
struct my_ingress_metadata_t{}
parser MyIngressParser(){}
control MyIngress(){}
control MyIngressDeparser(){}
struct my_ingress_header_t{}
struct my_ingress_metadata_t{}
parser MyEgressParser(){}
control MyEgress(){}
control MyEgressDeparser(){}
上述程序包含了后缀为p4的头文件(这两个是必备的,缺一不可),之后是对结构体的定义(类似于C语言的形式),再之后是pipeline的解析函数编写以及control函数编写,后者决定了最核心的P4可编程逻辑。
上述流程可以结合pipeline示意图理解:
数据从ingress pipeline进入处理,通过PRE && TM引擎转给egress pipeline,对应上面两个parser函数及其后面流程。
从上面P4流程可以看出,该语言和C很相近,它使用C编译器进行预编译,头文件可以单独编写。所有的P4程序都可以按照下面的流程写:
编写header和metadata
解析器Parser
控制control函数(match-action)
deparser函数
最后编写主函数(这里面包含了你想要怎么设计逻辑处理顺序):
Pipeline(
MyIngressParser(),MyIngress(),MyIngressDeparser(),
MyEgressParser(),MyEgress(),MyEgressDeparser()
)
Switch(pipe) main;
除此之外,还需要编写对应的头文件(这里包含了对各个参数的定义,一定要对所使用的参数有明确理解):
...
header vlan_tag_h{
bit<1> pri;
bit<3> cri;
bit<12> vid;
bit<16> ether_type;
}
...
一般情况下,都会用bit<...>的形式来定义结构体这种变量的大小,这是为了充分利用有限的芯片资源,会把变量定义精确到位,冗余的定义会造成芯片资源的浪费,一般情况下都会对一些参数有约定俗成的定义,比如上面的vlan_tag_h为32位。
在p4交换机中,ingress各个部分都通过my_ingress_headers_h以及my_ingress_metadata_h这两个数据结构进行交换数据。
上述两个数据结构在各个部分真的很重要!很重要!很重要!
下一节再解析这两个数据结构。