P4 程序设计语法学习

  • Post author:
  • Post category:其他




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)
    • 其他体系结构可以定义(并提供实现)额外的匹配类型

  • 定义针对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 版权协议,转载请附上原文出处链接和本声明。