P4语法学习
P4程序模板
#include<core.p4>
#include<v1model.p4>
/* HEADERS */
struct metadata { ... }
struct headers {
ethernet_t ethernet;
ipv4_t ipv4;
}
/* PARSER */
parser MyParser(packet_in packet,
out headers hdr,
inout metadata meta,
inout standard_metadata_t smeta) {
...
}
/* CHECKSUM VERIFICATION */
control MyVerifyChecksum(in headers hdr,
inout metadata meta) {
...
}
/* INGRESS PROCESSING */
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t std_meta) {
...
}
/* EGRESS PROCESSING */
control MyEgress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t std_meta) {
...
}
/* CHECKSUM UPDATE */
control MyComputeChecksum(inout headers hdr,
inout metadata meta) {
...
}
/* DEPARSER */
control MyDeparser(inout headers hdr,
inout metadata meta) {
...
}
/* SWITCH */
V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main;
类型(Type)
基础类型(Basic Types)
- **bit< n >:**长度(size)为 n 的无符号整数或位字符串(bitstring)
-
bit :
等同于
bit<1>
-
int< n > :
长度(size)为 n (n>=2) 的有符号整数 - **varbit< n > : **可变长度的位字符串
报头类型(Header Types):有序的成员集合
-
可以包含
bit< n >
,
int< n >
, 和
varbit< n >
- 由字节校准的
- 可为有效可为无效
-
提供几个操作来测试和设置有效位:
isValid( ) , setValid( ) , setInvalid( )
其他有用的类型(Other useful types)
- **Struct : **无序的成员集合
- **Header Stack : **报头数组
- **Header Union : ** 几个报头中的一个
typedef bit<48> macAddr_t;//typedef就是c++的typedef
typedef bit<32> ip4Addr_t;
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;
ip4Addr_t srcAddr;
ip4Addr_t dstAddr;
}
/* Architecture */
struct standard_metadata_t {
bit<9> ingress_port;
bit<9> egress_spec;
bit<9> egress_port;
bit<32> clone_spec;
bit<32> instance_type;
bit<1> drop;
bit<16> recirculate_port;
bit<32> packet_length;
...
}
/* User program */
struct metadata {
...
}
struct headers {
ethernet_t ethernet;
ipv4_t ipv4;
}
实现基本转发(Basic Forwarding)
简易起见,本文实现一个基本的路由器来说明P4的主要特性
基本路由功能包括如下:
- 从数据包解析以太网和IPv报头
- 在IPv4路由表中查找目标
- 更新源和目标MAC地址
- 减少 IP 报头中的生存时间 (TTL)字段
- 设置出口端口
- 将报头解析回一个数据包中
解析器(Parsers)
- 解析器是一种将数据包映射到数据头和元数据中的函数
-
每个解析器有三种状态
-
start
-
accept
-
reject
- 其他状态可以有程序员自定义
-
-
在每个状态中,执行零或多条语句,然后利用
transition
转换到另一个状态
/* From core.p4 *//*来自于已经写好的头文件,无需自己写,仅用于查看相关变量*/
extern packet_in {
void extract<T>(out T hdr);
void extract<T>(out T variableSizeHeader,
in bit<32> variableFieldSizeInBits);
T lookahead<T>();
void advance(in bit<32> sizeInBits);
bit<32> length();
}
/* User Program *//*用户自行编写部分,一开始进入 start 状态,下一个状态即为 transition 后面的那个状态*/
parser MyParser(packet_in packet,
out headers hdr,
inout metadata meta,
inout standard_metadata_t std_meta) {
state start {
packet.extract(hdr.ethernet);
transition accept;
}
}
/*解析以太网部分*/
state start { //首先进入此 start 状态
transition parse_ethernet; //转换至 parse_ethernet 状态
}
state parse_ethernet {//由 start 状态转换而来
packet.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType) {//select 类似于 c 的 case
0x800: parse_ipv4;
default: accept;
}
}
select 语句类似于 c 的 case 语句,不过没有 break ;
匹配方式可以是文字也可以是简单计算(例:掩码)
控制器(Controls)
- 类似于C函数(没有循环),可以声明变量、创建表、实例化表达等等。
- 其功能由 apply 语句指定
-
各类处理过程可以表示为DAG
- 匹配-动作 管道
- 解析器
- 数据包处理的附加形式(例:更新校验和)
- 与其他块的接口由用户指定的和体系结构指定的类型进行管理(例:经典的包头和元数据)
例:**反射器(Reflector)**作用如下:
- 交换源地址和目标MAC地址
- 将数据包弹回进入交换机的物理端口
/*
反射器(Reflector)
*/
control MyIngress(inout headers hdr, inout metadata meta, inout standard_metadata_t std_meta) {
/* Declarations region */
bit<48> tmp;
apply { //apply 语句指定control的功能(类似函数的主体部分)
/* Control Flow */
tmp = hdr.ethernet.dstAddr;//交换源地址和目标MAC地址
hdr.ethernet.dstAddr = hdr.ethernet.srcAddr;
hdr.ethernet.srcAddr = tmp;
std_meta.egress_spec = std_meta.ingress_port;//将数据包弹回进入交换机的物理端口
}
}
动作(Actions):
- 类似函数(可以全局声明也可以在control内声明)
-
参数需包括其
类型(type)
和
方向(direction)
- 变量可以在其内部实例化
-
支持很多标准的算术和逻辑操作
- +, – , *
- ~ , & , |, ^ , >> , <<
- == , != , > , >= , < , <=
- 但是没有除法和求模
-
非标准操作
- (位切片)Bit-slicing: [m:l] (works as l-value too)
- (位连接)Bit Concatenation: ++
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t std_meta) {
action swap_mac(inout bit<48> src, inout bit<48> dst) {
bit<48> tmp = src;
src = dst;
dst = tmp;
}
apply {
swap_mac(hdr.ethernet.srcAddr, hdr.ethernet.dstAddr);
std_meta.egress_spec = std_meta.ingress_port;
}
}
表(Table)
-
匹配-动作 管道的基本单位:
- 匹配数据和匹配类型
- 可能的动作列表
-
可选择的多个表属性
- 大小(Size)
- 默认操作(Default action)
- 静态条目(Static entries)
- 其他(etc.)
- 每个表都包含一个或多个条目
-
一个条目包含:
- 待匹配的键(Key)
- 动作(Action):当数据包与当前条目匹配时执行的单个操作
- 动作数据(Action Data):可能为空
例:
IPv4_LPM Table
-
数据平面(P4)程序
-
定义该表的格式
- 键值字段(Key Field)
- 动作(Action)
- 动作数据(Action Data)
- 执行查找
- 执行所选中的操作
-
定义该表的格式
-
控制平面(IP堆栈、路由协议)
-
使用特定的信息填充表条目
- 基于配置
- 基于自动发现
- 基于协议计算
-
使用特定的信息填充表条目
table ipv4_lpm {
key = {
hdr.ipv4.dstAddr: lpm;
}
actions = {
ipv4_forward;
drop;
NoAction;
}
size = 1024;
default_action = NoAction();
}
-
匹配类型(Match Kinds)
:在P4中 match_kind 是一种特殊的类型-
标准库(core.p4)定义了三种标准match_kind:
- 精确匹配( Exact match )
- 三元匹配( Ternary match )
- 最长前缀匹配( LPM match )
-
体系结构(v1model.p4)定义了两种额外的match_kind:
- 范围匹配(range)
- 选择器匹配(selector)
- 其他体系结构可以定义(并提供实现)额外的匹配类型
-
标准库(core.p4)定义了三种标准match_kind:
-
定义针对L3转发的操作(Defining Actions for L3 forwarding)
-
操作包含两种不同类型的参数:
- 有向(来自数据平面)
- 无向(来自控制平面)
-
被直接调用的操作:
- 仅使用有向参数
-
表中使用的操作:
- 通常使用无向参数(有时也可以使用有向参数)
-
操作包含两种不同类型的参数:
-
在 Controls 中应用表(Applying Tables in Controls)如下:
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
table ipv4_lpm {
...
}
apply {
...
ipv![请添加图片描述](https://img-blog.csdnimg.cn/f5285423277441ab9b379f97874a67bb.png)
4_lpm.apply();
...
}
}
数据包重组(Deparsing)
- 将报头组装回数据包内,表示为一个 control 函数:
- extern 类型的 packet_out 变量定义在 core.p4 中:emit(hdr):如果头有效则将其串行化
- 优势:使重组更易于理解,且与解析器解耦开
版权声明:本文为HeyKith原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。