P4 语言及架构

时间:2024-04-05 21:49:58

       P4 语言的设计目标、抽象转发模型、工作流程以及语法要素,并讨论 P4 的局限性, 然后介绍了其他数据平面编程语言。
1 P4 设计目标
P4 的核心设计目标如下:
( 1)可重配置性: 交换机的数据包处理方式能够被重新配置。由于网络新协议不断涌现,传统交换机只能通过更换设备的方式支持新协议。因此,这个设计目标是为了在不更换交换机硬件的前提下通过编程的方式灵活定义数据平面的报文处理流程。
( 2)协议无关性: 交换机支持的数据包处理行为不受协议类型局限,并且管理员可以定制交换机本身所支持的协议。由于目前交换机所支持的大量协议并不能在所有场景中得到使用,存在很多冗余协议;同时支持新的网络功能依赖于新协议的定义。因此,这个设计目标是为了让数据平面设备无需关注协议的语法语义内容,让网络管理人员可以去除不需要的协议、快速定义新的协议。
( 3)平台无关性: 网络管理员能够独立于特定的底层平台来描述报文处理功能, 管理员编写的P4 程序与平台实现无关。由于不同的数据平面平台可能会有相同的报文处理逻辑,存在跨平台移植代码的需求;并且异构的底层平台会提高网络的编程门槛。因此, 平台无关性的好处在于使 P4 代码能够跨平台无缝移植,并且网络管理员可以像编写 C或者 C++程序那样不用关注底层架构, 从而减轻网络管理员负担。
2 P4 抽象转发模型
       为了实现上述目标,在 OpenFlow 已有的匹配+动作模式基础之上, P4的抽象转发模型如图1所示。

P4 语言及架构
                                                                                图 1 P4 抽象转发模型
从组成部分上来看, 该抽象转发模型主要包含三部分——解析器、多级流水线和缓冲区:
A. 解析器。 报文首先经过一个可重配置解析器, 解析器的功能是将头部域从报文中提取出来,按照数据包头解析图解析, 余下的载荷与头部分开缓存,并且载荷不参与后续匹配。 管理员可以定制数据包头结构和解析流程, 解析流程会被编译器编译为数据包头解析图并配置到解析器上。
B. 多级流水线。( 1) 从空间上来看,被提取出来的头部经过多级匹配动作表,这些多级匹配动作表以流水线的形式组织起来, 分为入口流水线和出口流水线两部分。位于入口流水线的匹配动作表决定了报文的输出端口与队列,基于入口流水线的处理,报文可能被转发、复制、丢弃或者触发流控;位于出口流水线的匹配动作表主要负责修改报文头部。( 2) 从逻辑上来看, 流水线是由匹配动作表组成的一个有向无环图( Directed Acyclic Graph,DAG),这个 DAG 也被称作数据平面控制流。在编写 P4 程序时, 管理员可以按照 P4 语法规范去定义控制流以及每张匹配动作表要匹配什么样的数据包、执行什么样的动作,从而达到自定义数据平面流水线处理逻辑的目的; 在运行时, 数据平面则会按照定义的控制流处理数据包。 此外,报文头部在各级匹配动作表之间传递的过程中,可以携带被称为元数据的额外信息, 具体来说, 元数据可以包括入端口信息、 时间戳等等。
C. 缓冲区。 缓冲区用来缓存载荷与交换机队列中等待被匹配动作表处理的已解析的头部。在抽象转发模型方面, P4 与 OpenFlow 主要不同点在于:

( 1) OpenFlow 仅支持固定协议的解析器,而 P4 支持可编程的解析器来自定义新的头部;
( 2)OpenFlow 假定多级匹配动作表是顺序执行的,而 P4 的匹配动作表可以是并行或者顺序执行的;
( 3) OpenFlow 假定动作是一系列固定的动作,而P4 的动作可以是由交换机所支持的协议无关原动作组成的复合动作。
3 P4 工作流程
对于 P4 程序而言, 其工作流程可以分为两个相互独立的阶段——配置阶段和运行阶段:
A. 配置阶段决定了交换机支持何种协议以及交换机如何处理报文。 在该阶段中,管理员按照 P4语言规范编写 P4 程序、 定义数据平面行为,包括数据包头解析器定义、控制流定义、匹配动作表定义、用户元数据定义等。 P4 程序编写完成后,管理员可以利用 P4 编程语言的前端编译器将 P4 程序 编 译 成 一 种 高 级 中 间 表 示 ( High Level Intermediate Representation,HLIR)。 然后,后端编译器会将 HLIR 文件编译到具体硬件或者软件平台上, 编译器除了配置数据平面之外,还会生成供控制平面在运行时调用的运行时控制管理接口。
B. 运行阶段决定了网络策略在指定的时间作用在报文上。 在该阶段中, 数据平面会按照 P4 程序定义的逻辑处理数据包,而运行在控制平面的应用程序会调用配置阶段生成的运行时管理控制接口, 实现运行时向数据平面下发匹配规则。
4 P4 语法要素
P4 语言是一种能够实现可重配置性、协议无关性、平台无关性的数据平面编程语言, 其中语法要素是 P4 提供给管理员来描述基于抽象转发模型的数据包处理行为的手段。 目前P4语言规范包括2014年发布的 P414[27]与 2016 年发布的 P416[28]。以下为 P4 语言的语法要素,表 1 为部分 P4 语法要素示例:
( 1)头部( Header)。 头部结构定义了数据平面需要解析的数据包头格式,包括数据包头所含域的结构、宽度和值的限定等。头部的内容决定数据包后续的操作。
( 2)表( Table)。 表的格式为匹配+动作,即匹配域和相应的执行动作。
( 3)动作( Action)。 动作用来描述数据包头部和元数据如何被处理。 P4 定义了一套协议无关的原动作( Primitive Action), 包括丢包、设置字段、复制包头等。 并且, 管理员可以自定义一个由多个原动作组成的复合动作( Compound Action)。
( 4)控制流( Control Flow)。 控制流是匹配动作表组成的有向无环图, 定义了数据包在不同的匹配动作表中的跳转关系。 其跳转逻辑包括顺序逻辑、判断逻辑等,但是不允许一张匹配动作表对同一个数据包执行多次匹配。
( 5)解析器( Parser)。 解析器定义了如何鉴别数据包头部以及数据包头部域的有效顺序,用于指导数据平面上的物理解析器按照何种逻辑去解析数据包。
( 6)逆解析器( Deparser)。 逆解析器是当数据平面多级流水线处理完数据包后, 将处理完的数据包头部进行重组的结构。
( 7 ) 用 户 自 定 义 元 数 据 ( User-defined metadata)。 用户自定义元数据是用户自定义的与每个报文相关的数据结构, 其中可以存放用户定义的值、 临时变量等。 用户自定义元数据能够有效地支持数据平面带状态处理, 数据包在各级匹配动作表之间传递时,可以携带这些用户自定义元数据以完成匹配动作表间的参数传递。
( 8)固有元数据( Intrinsic metadata)。 固有元数据是由数据平面自身产生或者消耗的信息,例如收到报文的入端口信息、报文将被转发的出端口信息等。 可以利用读取或者设置固有元数据来完成一些数据平面预定义的功能, 例如多端口洪泛等。
( 9)外部对象*( Extern object*)。 外部对象是事先定义好的库函数结构, P4 程序可以通过 API对其进行调用。 但是其内部行为是硬件实现的(例如:校验和单元),不能使用 P4 语言序来编程。
( 10)结构定义*( Architecture definition*)。结构定义是一系列用来描述可编程网络设备的声明。
注:末尾两个带*号的要素为 P4_16 新添加的。
以下 部分 P4 语法要素示例
语法要素 P4_14 程序示例 P4_16 程序示例
头部
header ethernet_t{
fields{
  dstAddr : 48;
  srcAddr : 48;
  etherType : 16;
}
}

表:
table forward_table() {
reads{
  ethernet.dstAddr:
  exact;
}
actions{
  forward1;
  NoAction;
}
size : 32;
}
table forward_table() {
key = {
  hdr.ethernet.dstAddr:
  exact;

}
actions = {
  forward1;
  NoAction;
}
  size = 32;
  default_action=NoAction();
}


动作
action forward(port){
modify_field(standard_
metadata.egress_spec,
port);
}
action forward(bit<9> port) {
standard_metadata.
egress_spec = port;
}


控制流
control ingress{
apply(forward_table);
}


control ingress(inout headers
hdr, inout metadata meta) {
apply {
  forward_table.apply();
}
}


解析器
parser TopParser{
extract(ethernet);
return
select(latest.ethertype){
  0x0800: ipv4;
  default: ingress;
}
}
parser TopParser(packet_in b,
out Parsed_packet hdr){
state start {
transition parse_ethernet;
}
state parse_ethernet {
  b.extract(hdr.ethernet);
  transition
  select(hdr.ethernet.etherType){
  0x0800: parse_ipv4;
  default: accept;
}
}
}

 

P4 语言及架构

                                                                                             图 1 P4 语言框架