p4-specification

P416语言规范
版本1.0.0
P4语言联盟
2017年5月22日

abstract

P4是用于编程网络设备的数据平面的语言。 本文档提供了P416语言的精确定义,这是P4版本的版本http:// p4。org。 本文档的目标受众包括希望为P4程序编写编译器,模拟器,IDE和调试器的开发人员。 对于有兴趣了解更深层次语言语法和语义的P4程序员而言,本文档也可能引起关注。

1.范围

本规范文件定义了P416语言程序的结构和解释。 它定义语言,语义规则和语言一致实现的要求。

它没有定义:

  • 在程序包处理系统上编译,加载和执行P4程序的机制,
  • 通过一个分组处理系统接收数据并传递给另一个系统的机制,
  • 控制平面管理由P4程序定义的匹配动作表和其他有状态对象的机制,
  • P4程序的大小或复杂性,
  • 能够提供一致性实现的分组处理系统的最低要求。

2. 术语,定义和符号

在本文档中,将使用以下术语:

  • 架构(Architecture):一组P4可编程组件及其间的数据平面接口
  • 控制平面:涉及数据平面的配置和配置的一类算法和相应的输入和输出数据。
  • 数据平面:一类描述数据包处理系统转换的算法。
  • 元数据(metadata):在执行P4程序时生成的中间数据
  • 分组(packet):网络分组是由分组交换网络携带的数据的格式化单元
  • 数据包头(header):数据包开头的格式化数据。给定的分组可以包含表示不同网络协议的分组报头序列。
  • 数据包有效载荷(payload):数据包头之后的数据包数据
  • 分组处理系统(packet-process system):用于处理网络数据包的数据处理系统。通常,分组处理系统实现控制平面和数据平面算法。
  • 目标(Target):能够执行P4程序的分组处理系统

本文件中明确定义的所有术语不应被理解为隐含地涉及其他地方定义的类似术语。相反,本文档中未明确定义的任何术语应根据一般可识别的来源(例如IETF RFC)进行解释。

3. 概述

P4是用于表示分组如何由诸如硬件或软件交换机,网络接口卡,路由器或网络设备的可编程转发元件的数据平面处理的语言。 名称P4:“编程协议无关的数据包处理器”,“Programming Protocol-independent Packet Processors,” 虽然P4最初是为可编程交换机设计的,但其范围已经扩大到涵盖了各种各样的设备。 在本文的其余部分中,我们对所有这些设备使用通用术语目标。

许多目标都实现了控制平面和数据平面。 P4旨在仅指定目标的数据平面功能。 P4程序还部分定义了控制平面和数据平面通信的接口,但P4不能用于描述目标的控制平面功能。 在本文的其余部分中,当我们将P4称为“编程目标”时,我们的意思是“编程目标的数据平面”。

作为目标的具体示例,图1示出了传统的固定功能交换机和P4可编程交换机之间的区别。 在传统的交换机中,制造商定义了数据平面功能。 控制平面通过管理表中的条目(例如路由表),配置专用对象(如 meter)以及处理控制包(例如路由协议包)或异步事件(如链路状态更改或学习)来控制数据平面。

P4编程交换机与传统交换机的不同之处在于两种基本方式:

  1. 数据平面功能不是预先固定的,而是由P4程序定义的。 数据平面在初始化时被配置,以实现由P4程序描述的功能(由长的红色箭头所示),并且没有内置的现有网络协议知识。

  2. 控制平面使用与固定功能设备相同的通道与数据平面进行通信,但是数据平面中的一组表和其他对象不再固定,因为它们由P4程序定义。 P4编译器生成控制平面用于与数据平面通信的API。

因此,P4可以说是与协议无关的,但它使程序员能够表达一组丰富的协议和其他数据平面行为。

结论:话是说的协议无关,但还是离不开吧?

P4语言提供的核心抽象是:

  • 报头类型(header type) 描述数据包中每个标题的格式(字段集及其大小)。
  • 解析器(Parser)描述接收到的分组中的 header 的允许序列(permitted sequences),定义如何识别那些报头序列,以及从分组中提取的报头和字段。
  • 表(table) 将用户定义的键(key)与操作(action)相关联。 P4表是推广自传统交换机表; 它们可用于实现路由表,流查询表,访问控制列表和其他用户定义的表类型,包括复杂的多变量决策。表是执行数据包处理的机制,P4程序定义了在表内可以匹配的字段和可以执行的操作。
  • 动作(Action)描述数据包头域和元数据如何被操纵的代码片段。 操作可以包括在运行时由控制平面提供的数据。
  • 匹配动作单元(match-action units)执行以下操作序列:
    • 从分组字段或计算的元数据构造查找密钥
    • 使用构造的键执行表查找,选择要执行的操作(包括相关数据)
    • 最后,执行所选的操作。
  • 控制流(Control Flow) 表达了一个命令性程序,用于描述目标上的分组处理,包括匹配动作单元调用的数据相关顺序。 分离(分组重组)也可以使用控制流来执行。
  • 外部对象(Extern objects)是可以由P4程序通过定义良好的API来操作的体系结构,但内部行为是硬连线(involving or achieved by permanently connected circuits.)的(例如,校验和单元),因此不能使用P4进行编程。
  • 元数据(metadata)
    • 用户定义(user define)的元数据:与每个数据包相关联的用户定义的数据结构。
    • 内在(Intrinsic)元数据:由与每个分组相关联的架构提供的元数据,例如 接受 packet的输入端口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/********** 报头类型 ************/ 
// 以太网
header_type ethernet_t {
fields {
dst_addr : 48;
src_addr : 48;
ethertype : 16;
}
}
header ethernet_t ethernet;

/********** 解析过程 ************/
// 以太网包头的解析逻辑

parser start
{
return parse_ethernet;
}

parser parse_ethernet
{
extract(ethernet)
return switch(latest.ethertype) {
case 0x8100: parse_vlan; case 0x0800: parse_ipv4;
// Other cases
}
}

/*********** “匹配 - 动作” **********/
#define IPV4_LPM_TABLE_SIZE 65536
table ipv4_fib_lpm {
reads {
metadata.vrf : exact;
ipv4.dstAddr :lpm;
}
actions {
on_miss;
fib_hit_nexthop;
}
size : IPV4_LPM_TABLE_SIZE;
}
action on_miss() {
// no op
}

// 一旦定义好包头、解析器、表和动作,剩下的任务则是指定从一个表到下一个表的控制流。

// example: 数据包首先经过L2转发表(12_fwd),然后可能经过L3路由表(ipv4_fib_lpm和ipv6_fib_lpm)

control ingress {
// L2 forwarding apply(l2_fwd);
// L3 routing apply(router_mac) {
hit
{
if (valid(ipv4))
{
apply(ipv4_fib_lpm);
}
else
{
if (valid(ipv6))
{
apply(ipv6_fib_lpm)
}
}
}
// ACL apply(acl);
}

编译 P4 程序

P4编译器本质上是将在P4程序中表达的数据平面的逻辑翻译成一个在特定可编程数据包处理硬件上的具体物理配置。因此,编译器后端部分自然与其支持的硬件目标紧密结合,而其前端部分则可以在各个P4可编程目标之间通用。这就意味着一个P4程序的具体实现可根据被编译的目标而改变。PISA编译器可以从P4程序的包头和解析器定义中导出解析器和重组器的配置。P4采用的状态机概念使得此映射变得相对容易。PISA编译器可以从表、动作和控制流的定义中导出“匹配 - 动作”阶 段的配置。编译器首先分析每个包头字段、元数据和状态对象在表和动作之间的所有依赖关系。基于这个结果,识别出可放置在相同阶段同时运行的表和动作,以及那些由于依赖性而必须顺序执行的表和动作。同时编译器还应考虑到其他由特定目标带来的相关限制,如可用的表内存、计算逻辑单元和携带数据包包头的寄存器等。

目标制造商提供硬件或软件实现框架,架构定义和该目标的P4编译器。 P4编程人员针对特定架构编写程序,其中定义了目标系统上的一组P4可编程组件以及其外部数据平面接口。

编译一组P4程序会产生两个工件:

  1. 实现在输入程序中描述的转发逻辑的数据平面配置
  2. 用于从控制平面管理数据平面对象的状态的API

P4语言旨在实现多种目标(target),包括可编程网络接口卡,FPGA,软件交换机和硬件ASIC。 因此,语言仅限于可以在所有这些平台上高效实现的构造。

3.1 P4的优点

与最先进的分组处理系统(例如,基于在定制硬件之上编写微代码)相比,P4提供了许多显着的优点:

  • 灵活性(Flexibility):与传统交换机相比,P4使许多数据包转发策略可以表达为程序,这些传统交换机将固定功能的转发引擎暴露给用户。
  • 表现力(Expressiveness):P4可以使用通用操作和表查找来表达复杂的,与硬件无关的数据包处理算法。 这些程序在实现相同体系结构的硬件目标(假设有足够的资源可用)上是可移植的。
  • 资源映射和管理(Resource mapping and management):P4程序抽象地描述存储资源(例如,IPv4源地址); 编译器将这些用户定义的字段映射到可用的硬件资源,并管理诸如分配和调度的低级细节。
  • 软件工程(Software engineering):P4程序提供重要的好处,如类型检查,信息隐藏和软件重用。
  • 组件库(Component libraries):制造商提供的组件库可用于将硬件特定功能包装到便携式高级P4结构中。
  • 解耦硬件和软件演进(Decoupling hardware and software evolution):目标制造商可能会使用抽象架构来进一步将低级架构细节的演进与高级处理分离。
  • 调试(Debugging):制造商可以提供架构的软件模型,以帮助开发和调试P4程序。

3.2。 P4语言演变:与以前版本的比较(P4 v1.0 / v1.1)

与P414相比,早期版本的语言P416对语言的语法和语义进行了许多重大的,向后不兼容的更改。 从前一版本(P414)到当前版本(P416)的演进如图3所示。特别是,语言中已经消除了大量的语言特性,并将其转移到库中,包括计数器,校验和单元,仪表等。

因此,语言已经从复杂语言(超过70个关键字)转变为相对较小的核心语言(少于40个关键字,如A部分所示),并附有一个基本构造库,用于编写大多数P4。

P4的v1.1版本引入了一种称为extern的语言结构,可用于描述库元素。 因此,在v1.1语言规范中定义的许多结构将被转换成这样的库元素(包括从语言中消除的结构,例如计数器和计量表)。 这些外部对象中的一些预期将被标准化,并且它们将在将来描述P4元素标准库的文档的范围内。 在本文中,我们提供了几个extern结构的例子。 P416还介绍并重新使用了一些v1.1语言结构来描述架构的可编程部分。 这些语言结构是:解析器,状态,控件和包。

外部对象描述了一组由对象实现的方法,但不描述这些方法的实现(即它类似于面向对象语言中的抽象类)。 例如,以下构造可用于描述增量校验和单元提供的操作:

1
2
3
4
5
6
7
extern Checksum16 {
Checksum16(); // constructor
void clear(); // prepare unit for computation
void update<T>(in T data); // add data to checksum
void remove<T>(in T data); // remove data from existing checksum
bit<16> get(); // get the checksum for the data added since last clear
}

P416语言修订的一个重要目标是提供一个稳定的语言定义。 换句话说,我们努力确保在P416中编写的所有程序在语言的未来版本被视为程序时将保持语法正确,行为相同。 此外,如果将来版本的语言需要反向兼容性,我们将努力为将P416程序迁移到新版本提供一条简单的途径。

4. 架构模型(Architecture Model)

P4架构识别P4可编程块(例如,解析器,入口控制流,出口控制流,拆包器等)及其数据平面接口 —— parser, ingress control flow, egress control flow, deparser, etc.) and their data plane interfaces.

P4架构可以被认为是程序与目标之间的契约。 因此,每个制造商必须为其目标提供P4编译器以及相关架构定义。 (我们预计P4编译器可以共享处理所有架构的通用前端)。 架构定义不必暴露数据平面的整个可编程表面 - 制造商甚至可以选择为同一硬件设备提供多个定义,每个具有不同的功能(例如,具有或不具有多播支持)。

图4: 它显示一个具有两个可编程块(#1和#2)的目标(target)。 每个块通过P4代码的单独片段进行编程。 目标通过一组控制寄存器或信号与P4程序接口。 输入控件向P4程序提供信息(例如,从数据包接收的输入端口),而P4程序可以写入输出控件以影响目标行为(例如,数据包必须被引导的输出端口)。 控制寄存器/信号在P4中表示为内在元数据。 P4程序还可以存储和操作与每个数据包相关的数据作为用户定义的元数据。

可以根据将矢量向量映射到位向量的变换来完整地描述P4程序的行为。 (The behavior of a P4 program can be fully described in terms of transformations that map vectors of bits to vectors of bits.)

为了实际处理数据包,架构模型解释了P4程序对固有元数据写入的位。 例如,为了使分组在特定输出端口上转发,P4程序可能需要将输出端口的索引写入专用控制寄存器。 类似地,为了使分组被丢弃,P4程序可能需要将“丢弃”位设置到另一专用控制寄存器中。 请注意,内部元数据如何解释的细节是架构特定的。

P4程序可以调用由外部对象和架构提供的功能实现的服务。 图5描绘了在目标上调用内置校验和计算单元的服务的P4程序。 在P4中没有指定校验和单元的实现,但它有提供一个接口。 通常,外部对象的接口描述了它提供的每个操作,以及它们的参数和返回类型。

一般来说,P4程序预计不会在不同体系结构中移植。 例如,通过写入自定义控制寄存器来执行广播数据包的P4程序将无法在没有控制寄存器的目标上正常工作。 然而,只要有足够的资源,为某个架构编写的P4程序应该可以移植到所有目标上,忠实地实现相应的模型。

结论:P4 不是一个比较适合移植的设计?

4.2 数据平面接口 Data plane interfaces

为了描述可以在P4中编程的功能块,该体系结构包括一个类型声明,指定块与架构中其他组件之间的接口。 例如,架构可能包含以下声明:

1
2
3
control MatchActionPipe<H>(in bit<4> inputPort,
inout H parsedHeaders,
out bit<4> outputPort);

control 是一个关键字。

此类型声明描述了一个名为MatchActionPipe的块,可以使用匹配动作单元(match-action unit)调用和其他命令式构造进行编程。

由上述声明可以看出:

  • 第一个参数是一个名为inputPort的4位值。 direction参数:input 表示此参数是输入。无法修改
  • 第二个参数是H类的对象,名为parsedHeaders,其中H是一个类型变量,表示将由P4程序员稍后定义的标题。 方向inout表示此参数既是输入又是输出。
  • 第三个参数是一个名为outputPort的4位值。 方向输出表示此参数是一个输出,其值最初未定义,但可以修改。

4.3。 外部对象和函数

P4程序还可以与架构提供的对象和功能进行交互。 这样的对象使用extern构造来描述,该外部构造描述了这些对象暴露于数据平面的接口。

例子就是校验和 checksum


http://www.sdnlab.com/17456.html

https://p4lang.github.io/p4-spec/docs/P4-16-v1.0.0-spec.html