Programming Protocol-Independent Packet Processors
引言
- OpenFlow协议固定的包头域数目,使得南向协议过于死板。
- P4可以实现自定义包头,增加灵活性。
- P4是OpenFlow未来发展的方向。
We propose P4 as a strawman proposal for how OpenFlow should evolve in the future.
- P4的三个目标:
- 可重新配置。
- 协议无关性。
- 目标无关性:强调了P4的通用性。
1. INTRODUCTION
- 可以看出:随着版本的迭代,OpenFlow协议越来越复杂。
- 不再像OpenFlow一样重复的扩展包头,交换机应该支持灵活的“匹配-动作”机制,灵活的包解析机制。这样带来的好处是:
- 网络供应商扩展新功能变得简单。
- 控制器应用可以通过通用的南向接口(OpenFlow2.0)来利用交换机的这些功能。
- 简化南向协议。(与OpenFlow1.x相比)
- P4:用来配置交换机,告诉交换机如何处理包。
- existing APIs:例如OpenFlow,被设计用来填充固定功能交换机中的转发表。
- Figure 1展示了P4与existing APIs的关系:P4提高了网络编程的抽象程度,P4也可以称为像OpenFlow一样的南向协议。
That is, we believe that future generations of OpenFlow should allow the controller to tell the switch how to operate, rather than be constrained by a fixed switch design.
- 全文框架
- 一个关于P4的实例。
- P4如何实现自定义包头,包解析,多张“匹配-动作”表以及多张表之间的控制流。
- P4编译器的功能及实现。
- Related work
- Yadav et al:提出了OpenFlow的一个抽象转发模型,但是忽略了编译器。
- Kangaroo:介绍了可编程包解析的概念。
- Song:提出了协议无关,但是他的目标交换机更加倾向于网络处理器。
- ONF:介绍了表达交换机的匹配能力的类型表。
- NOSIX:“匹配-动作”表的灵活规范,但是没有考虑协议无关,也没有提出一种语言来定义自定义包头,包解析,多张“匹配-动作”表以及多张表之间的控制流。
- Other recent work:提出了用于数据平面监视、拥塞控制和队列管理的编程接口。
- The Click modular router:在软件中支持灵活的数据包处理,但无法将程序配置到各种目标交换机。
2. P4 LANGUAGE BY EXAMPLE
背景:网络部署分为核心交换机与边缘交换机。终端主机与边缘交换机直接相连,边缘交换机通过高带宽的核心交换机相连,核心交换机负责包的转发。
例子是这样的
- 一个L2网络,使用ToR相连的交换机做为边缘设备。边缘设备之间用2层核心交换机相连。
L2网络:
OSI网络模型分为七层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
L1代表layer 1就是物理层 L2是数据链路层 L3是网络层
ToR连接技术:
TOR(Top of Rack)是一种数据中心的布线方式。其他的布线方式还有EOR(End of Row)和MOR(Middle of Row)。
TOR接入方式就是在标准的42U的服务器机柜的最上面安装接入交换机。服务器的网口都接入到机柜上部的交换机上。这个接入交换机再通过铜缆或光纤接入到网络机柜的汇聚或核心交换机上。这种组网的好处是简化布线,从服务器机柜到列头柜只有很少的电缆。
这种布局要求每个服务器机柜的服务器密度比较高。
从网络设计上看,TOR布局中每台交换机上的VLAN/子网不会太多,在网络规划的时候也尽量避免让一个VLAN跨了多台交换机,所以TOR布局时一个VLAN范围不会太大,所包含的端口不会太多。但对于EOR来说,一个VLAN范围可能会更大,包含的端口更多。
还有一点,TOR布局的交换机数量多,EOR布局的交换机数量少,所以两者的维护管理工作量也不同。
- 假设终端主机数目增多,二层核心交换的的转发表Overflowing,有以下三种方法来解决这个问题:
方案 | 做法 | 不足 |
---|---|---|
MPLS协议 | 为每个数据包打上一个Tag,转发时只根据这个Tag来转发。 | 分发标签,多标签难实现 |
PortLand | 重写MAC地址 | 破坏网络调试工具 增加ARP协议的负担 |
P4 | mTag:结合上面二者。把核心路由的转发路线以及 目的定界符(PortLand's Pseudo MAC)编码为4字节的 Tag,核心交换机在转发时只需检查4字节中的1个字节即可 完成转发。这个标签可以由数据包经过的第一个ToR交换机打 上,也可以由主机上的NIC打上。这个例子采用了前者。 |
- |
2.1 Underlying Hardware Assumptions
- 为了实现P4的目标无关性,底层的通用硬件必须满足如下要求:
编号 | 具体细节 |
---|---|
1 | 支持两种执行模式: 1. 配置模式:在这个模式下,把数据包格式、"匹配-动作"表格式,下发给交换机。 2. 人口模式:在这个模式下,可以向交换机添加/删除规则。 |
2 | 有可配置的包解析器,用来识别和提取新的字段。 |
3 | 硬件中的表,必须支持:与所有已经定义的字段的匹配。 |
4 | 硬件必须支持一些独立于协议的原语,比如对旧域、新域、元数据的复制、添加、删除、修改等操作。 |
- P4与OpenFlow的一些对比
- | P4 | OpenFlow |
---|---|---|
对硬件要求 | 高 | 低 |
解析器功能 | 可编程、可定义新字段 | 只能识别固化的头部 |
流表 | 顺序+并行处理 (超标量流水线) |
只能顺序的处理 (普通流水线) |
支持的动作 | 动做均由原语构成,灵活可编程 | 固化的几个动作 |
2.2 P4 Overview
- 为了实现硬件的两个模式(configuration,population),一个P4程序包含了以下几个组件:
名称 | 含义/功能 |
---|---|
头部(Headers) | 一系列头部字段的顺序和结构,包括字段的宽度以及一些对字段值的约束。 |
解析器(Parsers) | 从数据包中提取出头部。 |
表(Tables) | "匹配-动作"表,类似于流表。 |
动作(Actions) | "匹配-动作"表中的动作,由独立于协议的原语组成。 |
控制程序(Control Programs) | 描述了数据包匹配、动作的顺序以各张表之间的控制流(control flow)。 |
2.3 Header Formats
- 每个头部都由一系列有序的字段组成,字段名称后的数字为可选字段,标注最大长度(约束)。
- 一些例子:
//以太网头部
header ethernet {
fields {
dst_addr : 48; // width in bits
src_addr : 48;
ethertype : 16;
}
}
//VLAN头部
header vlan {
fields {
pcp : 3;
cfi : 1;
vid : 12;
ethertype : 16;
}
}
- mTag的头部,每个核心交换机检查头部字段中的一个比特,这个比特取决于交换机的
location in the hierarchy
和数据包的direction of travel
(向上层还是下层)。
//mTag头部
header mTag {
fields {
up1 : 8;
up2 : 8;
down1 : 8;
down2 : 8;
ethertype : 16;
}
}
2.4 The Packet Parser
- P4的解析器其实是Header之间转换的状态机,根据检测到的值,跳转到下一个解析器。
- 贴上原文,方便理解:
P4 describes this state machine directly as the set of transitions from one header to the next. Each transition may be triggered by values in the preceding header.
- P4的解析器都会有一个
start
状态,从它对应的解析器(状态)开始检测数据包。
parser start{ //start状态
ethernet; //起始先调用名为ethernet的解析器
}
parser ethernet { //刚开始调用的解析器,也是ethernet状态
switch(ethertype) { //检测ethertype字段的值
case 0x8100: vlan; //如果ethertype的值=0x8100,跳转到名为vlan的解析器
case 0x9100: vlan; //如果ethertype的值=0x9100,跳转到名为vlan的解析器
case 0x800: ipv4; //如果ethertype的值=0x0800,跳转到名为ipv4的解析器
// Other cases
}
}
parser vlan { //vlan状态
switch(ethertype) { //检测ethertype字段的值
case 0xaaaa: mTag; //如果ethertype的值=0xaaaa,跳转到名为mTag的解析器
case 0x800: ipv4; //如果ethertype的值=0x0800,跳转到名为ipv4的解析器
// Other cases
}
}
parser mTag { //mTag状态
switch(ethertype) { //检测ethertype字段的值
case 0x800: ipv4; //如果ethertype的值=0x0800,跳转到名为ipv4的解析器
// Other cases
}
}
- P4的解析器状态机从起始状态
start
开始,直到stop
状态或者在处理过程中出错才停止。 - 到达一个新状态时,解析器提取某些字段,根据它的值跳转到下一状态。
- 解析器提取到的头部信息,交给"匹配-动作"表。
2.5 Table Specification
- 在我们的mTag例子中,边缘交换机根据目的MAC地址和VLAN ID,为数据包加上mTag的头部,其实这就相当于一次"match -action",根据MAC地址和VLAN ID匹配,动作是:打上mTag标签。
- P4程序员根据上面了例子,定义一张表。用来
match on these fields, with the action to add the mTag header
。 - 例子说明:
table mTag_table {
reads {
ethernet.dst_addr : exact; //对目的MAC地址的精确匹配
vlan.vid : exact; //对VLAN ID的精确匹配
}
actions {
// At runtime, entries are programmed with params
// for the mTag action. See below.
add_mTag;
}
max_size : 20000;
}
- 各个字段及其解释
字段名 | 含义/作用 |
---|---|
read | 声明要匹配的字段,以及匹配类型(精确、三元等)。 |
actions | 声明可能对数据包进行的操作,下面还会详细介绍。 |
max_size | 声明这张表最多容纳多少条目。 |
- 论文中又给出了控制程序中的三张表的伪代码,控制程序会在后面介绍。2.7节
table source_check {
// Verify mtag only on ports to the core
reads {
mtag : defined; // Was mtag parsed?
metadata.ingress_port;
}
actions {
// If inappropriate mTag, send to CPU
fault_to_cpu;
// If mtag found, strip and record in metadata
strip_mtag;
// Otherwise, allow the packet to continue
pass;
}
max_size : 64; // One rule per port
}
table local_switching {
// Reads destination and checks if local
// If miss occurs, goto mtag table.
}
table egress_check {
// Verify egress is resolved
// Do not retag packets received with tag
// Reads egress and whether packet was mTagged
}
2.6 Action Specifications
- 前面我们提到过,P4语言中,动作是由P4定义的一系列原语组成的。
- 为了使
Table
更加简单,P4把Action
定义在函数中。每个P4程序都有自己的Action
。 - 刚刚我们提到的
add_mTag
,由以下代码实现。
action add_mTag(up1, up2, down1, down2, egr_spec) { //传入五个参数
add_header(mTag); //原语,在数据包前加上mTag类型的头部
// Copy VLAN ethertype to mTag
copy_field(mTag.ethertype, vlan.ethertype);
// Set VLAN's ethertype to signal mTag
set_field(vlan.ethertype, 0xaaaa);
set_field(mTag.up1, up1);
set_field(mTag.up2, up2);
set_field(mTag.down1, down1);
set_field(mTag.down2, down2);
// Set the destination egress port as well
set_field(metadata.egress_spec, egr_spec);
}
- 传入的参数,是在
match
的时候产生的。 - 我们也可以逆着这个
action
函数,写出一个去掉mTag
的action
。 - 介绍一下P4提供的原语。
名称 | 含义/功能 |
---|---|
set_field | set某一头部中的某一个域。 |
copy_field | 把某一头部包含的某一个域的值复制到另一个头部上的某一域 |
add_header | 给数据包加上一个新的头部。 |
remove_header | 从数据包中删除一个头部。 |
increment | 修改头部中某一字段的值。 |
checksum | 计算头部的校验和。 |
2.7 The Control Program
- 控制程序负责控制表的顺序,它是由一系列函数、条件句和表的引用组成的程序。
- 这张图演示了用于在边缘交换机中实现mTag的控制流。
- 在包解析过后,"source_check"表检差收到的包与如端口是否一致,例如,带有mTag的包只能从与核心交换机相连的端口收到。"source_check"表同时还会剥掉mTag头部,并在metadata中记录这个数据包是否带有mTag头部,防止重复的贴标签。
- "local_switching"表开始工作,如果这个表"miss"了,就表明这个数据包不是发给本地主机的,转3。如果是发给本地的,转4。
- 不是本地的数据包,交给我们刚刚定义过的"mTag"表,进行匹配,然后交给"egress_check"表,转4。
- 不管是不是本地数据包,"egress_check"表会根据匹配的结果或者根据本地主机所在位置,将包转发。对于那些未知目的地址的数据包,"egress_check"表会把它交给SDN控制器。
- 下面是
mTag
控制流的源代码,所用到的表在前面已经提过。
control main() {
// Verify mTag state and port are consistent
table(source_check);
// If no error from source_check, continue
if (!defined(metadata.ingress_error)) {
// Attempt to switch to end hosts
table(local_switching);
if (!defined(metadata.egress_spec)) {
// Not a known local host; try mtagging
table(mTag_table);
}
// Check for unknown egress state or
// bad retagging with mTag.
table(egress_check);
}
}
3. COMPILING A P4 PROGRAM
- 为了在一个网络中使用我们的P4程序,我们需要一个编译器将P4代码配置到目标交换机。
- 其中涉及到设备资源分配和设备配置的问题。
3.1 Compiling Packet Parsers
- 对于具有可编程解析器的设备,P4编译器把对解析器的描述翻译成解析状态机(类似有穷自动机)。
- 对于具有固化的解析器的设备,P4编译器只是去检查它的解析器和P4代码中描述的是否相同。
- 具体细节在这篇论文中:G. Gibb, G. Varghese, M. Horowitz, and N. McKeown, "Design principles for packet parsers," in ANCS, pp. 13-24, 2013.
- 下面的表格展示了
vlan
和mTag
状态机的状态转移表,是不是很像有穷自动机的转移函数呢?
- 根据当前状态和检测到的字段值,来决定下一状态。