P4虚拟化数据平面

背景

现在SDN已经有了在数据平面的编程能力,这使得网络设备(包括硬件)可以被重新编程以解析自己定制的协议和执行定制的功能。

但是,数据平面的编程能力还没有发挥最大的潜能,它依旧不完善,而且在不断增长的软硬件中提供可编程能力是有很大形成碎片的风险。如果使用虚拟化方案可以解决以上两个问题。

OpenFlow已经为网络的控制平面提供了一个标准的可编程能力,并且在网络管理者寻找更加的自由和灵活的方案候起了重要的作用。

但是,它并没有使的数据平面有良好的可编程能力,数据平面依旧只能使用在OpenFlow的协议规范中被定义好的协议。如果OpenFlow需要支持较新的方案,那么OpenFlow的规范就要一直被扩展。 一个真正的数据平面按应该不被这些束缚,它应该允许管理员重新配置数据平面以完全适应自己定制的协议中的语法和语义。最近在可重配置的匹配表(reconfigurable match table,RMT)中的工作在体系结构上已经证明了可编程数据平面,即使在ASIC的硬件中也是可行的。 这个结果使得像P4这样的领域专用语言使得这些可编程数据平面可简单地以一个统一的方式在多种交换机上部署(比如基于RMT的ASIC、FPGA为基础的交换机、像PISCES一样的软件交换机、behavior model和在边缘服务器上的网络数据平面)。

简介

一般来讲,每一个P4兼容设备提供的可编程数据平面表示一种网络环境。 每一个P4的程序定义了:

  • 在流量被解析时的协议头的集合和与之相符合状态机
  • 在流量被处理时的匹配-执行表

为了支持不同的客户的类型和为复杂的包处理而灵活地组成虚拟方法,在多数情况下,操作者希望给定的网络设备可以有不止一个环境,即使只有一个物理的数据平面。

一个解决方法就是虚拟化。虚拟化可以虚拟出多个数据平面并且使用时会比多个设备更加流畅和方便。比如,借助虚拟化,我么可以同时在备上通过不同的配置部署多个网络功能,它允许:

  • 网络切片:隔离一些客户或者设备,这使得网络更加的现代和安全。每一个切面(也就是每一个网络环境)可以因为支持协议类型和功能的不同而完全不同。
  • 网络快照:当一个配置每次到达的时候,存储多个网络或者设备的配置,并且提供配置之间的快速切换。
  • 设备内部的虚拟网络,提供了针对以下两者的解决方案:
  • 包处理程序的复杂模块设计,支持模块化开发
  • 在交换机上支持多用户,并且使用可控的方法为他们提供服务
  • 提供标准的高层功能,比如程序分析,流量监控和其他功能

这些环境都需要隔离机来制止一个程序对另一个程序产生的威胁并保护设备避免其潜在危险的程序的威胁。

使用虚拟化,可以使得物理上单一的数据平面支持逻辑上的多种网络环境。那么,是不是可以有一种使用纯P4语言实现的通用虚拟化框架呢?如何使用一个用户级别的程序来实现虚拟化?是否可以使用一个特殊设计的具有模拟其他P4程序的能力的P4程序?

这样可以动态地支持虚拟化,而且可以在不中断现有的网络设备的情况下部署和重新配置,它具有很强的便携性。

HyPer4使用软件的方式拓展了P4语言,使得支持P4语言的设备可以具有如下功能:

  • 可以在逻辑上存储多个P4程序并且同时运行它们(作为网络切片)或者热切换的快照
  • 在每一个程序之间可以形成一个虚拟网络(支持程序不同部分和或者多租户服务交互)
  • HyPer4可以在运行时修改程序集和改变他们的虚拟网络连接而不用中断现在正在运行的程序。
  • 可以兼容ASCI的硬件。

运行环境

P4语言运行环境简介

上图描述了典型P4程序的编译过程,它分为两步:

1.前端编译器将P4源代码编译为高级中间表示(high-level intermediate representation, HLIR) 2.后端编译器将HLIR转换为特定目标设备的形式(比如JSON或者二进制代码)。 比如现在P4编译器后端提供了p4c-bmv2,它会将HLIR转化为Barefoot Network的bmv2软件交换机可以使用的JSON文件;SDNet可以将其编译至Xininx FPGA的代码;LLVM_P4和P4-to-EBPF可以将其转换为Linux网络平面使用的EBPF程序。

上图左边部分描述了P4设备开始配置的过程。首先,用户会编译P4的代码,然后将二进制代码(或者其等价形式)装载进P4兼容的设备中。

上图右边部分描述了在二进制代码被装在进入P4设备后,设备就可以在运行时接受和代码兼容的控制器的指令。

HyPer4运行环境

上图分为三部分:

1.左边部分演示了使用HyPer4环境部署和载入foo.p4代码的过程,和原生P4环境一样,在P4设备中生成了一个HyPer4的运行时环境,但是这时的运行时环境只是具有执行的能力,并没有可执行的表。 2.中间部分展示了如何将普通的P4程序通过HyPer4编译器编译为实体表然后载入运行时环境。 3.右边部分展示了为了不修改现有的控制器,HyPer4使用了一个数据平面管理单元(Data Plane Mangagement Unit, DPMU)来作为控制器和交换机之间的代理。它可以将对于原有P4代码的虚拟表的操作转换为HyPer4表的操作。

几个例子

已实现的代码片段

  • 一个二层以太网交换机
  • 一个IPv4路由器
  • 一个代表交换机上的IPv4主机回复ARP请求的ARP代理
  • 一个可以过滤IPv4、TCP和UDP源和目的的防火墙

使用这几个简单的P4代码片段,有以下三个例子来说明可编程数据平面

快照和简单地模块化

上图是一个网络快照和模块化的示例。这个网络包含三个已经连接的P4设备:s1、s2和s3,每一个设备上都在运行HyPer4程序。两个主机h1、h2和s1连接,另外两个主机h3、h4和s3连接。

最开始,HyPer4的表项是空的,而且设备被分为不同的功能。我们接着将HyPer的表实体下发给每个设备,使得每个设备逻辑上存储了所有的程序,这三个程序可以通过网络配置进行切换。

在开始的配置中,s1和s3分别运行arp代理,s2运行二层交换。在上图的s1和s3中,虚线框中的A代表arp代理功能,在s2中,虚线框中的A代表二层交换功能。

在第二个配置中,s1和s3都运行二层交换,s2运行防火墙。这些功能都被标记为B。

在第三个配置中,s1和s3都运行了和第二个配置一样的二层交换,s2运行了一个复合的程序,这些被标记为C。当流量第一次到达s2的时候,首先被arp代理处理,然后其他的流量会被传送到s2中的下一个虚拟功能——一个防火墙。并且任何可以通过防火墙的流量都会被一个路由应用处理。

同时,每个虚拟功能的流表也会被下发给每一个运行HyPer4的设备:

  • 二层交换机的MAC和目的端口对
  • arp代理的IPv4和MAC对
  • 路由器的IPv4目的地址和下一跳IP和MAC地址对
  • 防火墙对于TCP特定端口的过滤规则

每次在一台设备中只有一个配置被激活。切换配置的时候需要控制器发送一个流表项。

网络切片和模块化

上图描述了一个运行HyPer4的P4设备s1和4个连接它主机h1、h2、h3、h4。 s3、s4的IP地址和子网掩码已经被设置,所以他们在不同的逻辑网络内。

使用HyPer4来将s1进行切片,使得连接h1和h2的端口1和2被分配到一个逻辑设备,连接h3和h4的端口3和4被分配到另一个逻辑设备。

在一开始,s1中HyPer4的表项是空的,并且s1已经被分为许多功能。

然后给HyPer4下流表,使得s1逻辑上存储三个程序:

  • 在1和2端口上的流量被一个二层交换机处理
  • 在4和3端口上的流量首先被一个防火墙处理,然后通过防火墙的流量被一个路由器处理

同时,也需要针对二层交换机(MAC地址和出端口对),防火墙(过滤TCP特定端口的流量)和路由器(IPv4目的地址和下一跳IP和MAC地址对)下流表。

虚拟网络

上图描述了虚拟设备间的虚拟网络。这个网络包含了一个有h1、h2、h3、h4四个主机连接的单一的P4设备s1。每个主机都被分配到了不同的网络。

在S1上被载入了8段程序,创立了8个虚拟设备:

  • 在h1上的一个路由器r1和一个防火墙f1
  • 在h2上的一个路由器r2和一个防火墙f2
  • 在h3上的一个路由器r3
  • 在h4上的一个路由器r4
  • 连接内部网络的两个二层交换机l2s1和l2s2

当为每一个设备下流表以后,这个示例演示了如何使得s1通过HyPer4支持希望为每个人服务但是又需要有安全控制的多租户方案。

HyPer4系统的设计

总览

在高层上来看,HyPer4具有一个运行环境,一个编译器和一个数据平面管理单元(data plane management unit,DPMU)。

一个P4程序定义了包处理的结构。当执行的时候,以匹配表形式出现的运行时状态(可随时改变)会影响一个包会如何被包处理结构处理。

Hyper4定义了一个足够通用的结构,这个结构可以允许状态以任意的途径改变,并影响数据包处理的流程。

上图描述了HyPer4运行环境的概览。

HyPer4分为三个阶段

1.解析和设置阶段接受数据包并且使用一个模拟的P4程序来为将数据包设置为一个明确的HyPer4状态 2.HyPer4模拟了目标程序的匹配-执行状态序列 3.egress阶段处理任意的egress专有的的原始操作并且准备传输

可编程的解析器

运行环境必须可以解析在包中匹配到的任意字节的数据,它通过遍历一棵分析树来达到这个目的。在一棵树中每一个节点解析整体需求的一部分需要并且在一个元数据分支上的字段numbytes_to_extract存储这些需求。

框架在ingres pipeline的设置阶段设置了解析器的一些属性,如果需要,它会将包返回至ingress pipeline。

特别地,numbytes_to_extract依赖于虚拟设备以及和它有关的包。

框架也使用了P4的resubmit操作来使得包被重新送回解析器(如果需要的话)。

resubmit操作非常强大,因为可以将需要保留他们的值的字段列表传给它(比如numbytes_to_extract)。最终,解析器提取了一个字节栈,resubmit的操作可以在一个包含一个虚拟设备可能需要处理的许多包头的包上被重复调用多次。

字段描述

框架使用了非常广泛的元数据字段来表示虚拟设备需要使用的字段列表。

框架也定义了一个逻辑上存储所有被从包中解析出的数据(被解析器解析出的字节栈)的字段,并且另一个字段会被用来表示虚拟设备中所有的元数据字段。

匹配

任意的P4程序匹配任意的字段。HyPer4的任务是以将一个大的源数据字段的相关部分隔离开的方法支持任意的字段,并将其用以表示一个P4程序的被定义好的字段。

HyPer4使用了非常多的P4的三元组匹配机制对这种模式进行支持,它允许在匹配值的时候一同提供表中匹配实体和掩码,这些掩码被用于在和匹配的数据比较之前确定匹配的区域。

执行

匹配在P4程序中会触发可能是复杂的原始操作集合的执行过程。

HyPer4为每一个支持的P4原始操作提供了一套共同执行需要的行为的表。

简单来说,框架使用了一个元数据字段的集合在每个包处理阶段的必要时重定向HyPer4的控制流。

各种HyPer4中不同的匹配-执行阶段会读取(匹配),写入,或者读写这些元数据字段。

用提供这些表的实体来确定被用于读取或者写入这些确定的值,使得操作者可以调用相关HyPer4提供的需要执行任意行为的方法。

虚拟网络

HyPer4依赖P4的recirculate原始操作将包从一个设备传送到另一个设备。这个操作会在完成egress pipeline以后标记一个会被重新发回的包。

它允许将一个字段列表作为参数传入。当包重新在解析器出现的时候,这个列表里所有的字段将会保持它原有的值。

HyPer4结构依赖于一般的匹配-执行阶段的概念。HyPer4的状态可以决定应该进行哪一种匹配操作和进行每一种原始操作的参数。为了模拟其他的P4程序,HyPer4需要根据被仿真的目的程序改变HyPer4的状态,进而将其被转换成对于表的操作。

通过将P4程序表示成状态,HyPer4可以支持P4程序的实时更新。

解析器

P4程序解析器的规则是将一个包前N比特的结构鉴别为一系列具有相关标签的比特字段。这些被打标签的比特字段也可以被称为一个包的“Parsered Representation(被解析的表示)”。

程序员定义了包头的类型,其中指出了名字、宽度和在比特区域中的位置,并且还声明了当解析包中比特的时候这些类型所定义的包实例。

为了解析一个包头,要做的是添加根据包的类型被结构化和命名的一个比特域的集合,并将其转变为Parsered Representation。

解析器决定那些包头应该被解析的方法是根据包中的数据或者元数据中一些字段的数据标记解析图的分支。

HyPer4必须用可以在运行时重新配置的方法来解析足够数量的的数据来达到模拟其他P4程序的需求。

框架定义了一个有一字节宽度单一字段的包头类型,并且声明了一个这个类型的数组来适应从包中解析出的变化的字节长度。

同时,框架也定义了一个元数据字段(比如numbytes_to_extract)。

一旦收到了一个包,解析器会验证这些字段。

数值为0表明它还没有为引导解析过程做好准备。在这种情况下,一个默认长度的字节会被解析(一般来说是20字节),并且控制流被重定向到一个初始化方法中去(上图的setup -a环节),如果有必要,它会更新numbytes_to_extract并且将包重新提交。被重新提交的包会重新回到解析器,但是这次numbytes_to_extract是一个有意义的值。

HyPer4遍历了在这个区域的解析树中可以解析的每个部分的分支。

在完成解析以后,HyPer4将所有被解析的字节连接到一起。在整个剩下的处理流程中,框架使用一个非常大的元数据字段来表示这些被解析的字段。

设置函数(上图的setup -b)接着配置包处理的流程。特别地,这个函数设置一个指示了被仿真的程序在HyPer4中可能需要执行的元数据字段。它也设置了另一个字段去表明哪一个表应该是最初被执行的(根据被模拟的程序中匹配到的类别的匹配-执行阶段),并将其作为HyPer4的匹配-执行阶段。

原文发布于微信公众号 - SDNLAB(SDNLAB)

原文发表时间:2017-04-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏SeanCheney的专栏

深入理解Python异步编程(上)

彻底理解异步编程是什么、为什么、怎么样。深入学习asyncio的基本原理和原型,了解生成器、协程在Python异步编程中是如何发展的。

6032
来自专栏腾讯Bugly的专栏

Redex 初探与 Interdex:Andorid 冷启动优化

导语 早在去年10月份,facebook就发布了介绍redex的文章,这个据说可以直接对apk做处理,既提高启动性能,又可减少安装包的利器让安卓开发者们都心动不...

6036
来自专栏SDNLAB

SDN实战团分享(二十九):Microflow性能调优分享

Hello大家好,很高兴可以在这里和大家分享一下我的个人开源项目Microflow的相关工作。 我是BII天地互连的工程师,在公司里负责SDN产品和技术的开发,...

3607
来自专栏CDA数据分析师

用Python爬虫获取自己感兴趣的博客文章

作者 CDA数据分析师 在CSDN上有很多精彩的技术博客文章,我们可以把它爬取下来,保存在本地磁盘,可以很方便以后阅读和学习,现在我们就用python编写一段...

3498
来自专栏腾讯移动品质中心TMQ的专栏

【腾讯TMQ】和开发一起写代码,让测试左移起来

软件工程中有提到测试人员越早的介入到研发的流程当中,就可以越早的发现问题,从而降低发现问题的成本。因此"左移"变得非常的有必要了起来,当然左移的方式有很多,例如...

5560
来自专栏架构师之路

龙神教你“如何做系统性能优化”

性能优化的目标是什么?不外乎两个: 时间性能:减小系统执行的时间 空间性能:减小系统占用的空间 一、代码优化 做代码优化前,先了解下硬件Cache: (1)C...

2967
来自专栏腾讯NEXT学位

《Node.js在CLI下的工程化体系实践》成都OSC源创会分享总结

1362
来自专栏韩伟的专栏

高性能服务器架构思路(四)——编码复杂度和通信

以前我们的代码,从上往下执行,每一行都会占用一定的CPU时间,这些代码的直接顺序,也是和编写的顺序基本一致,任何一行代码,都是唯一时刻的执行任务。当我们在编写分...

13.5K2
来自专栏小尘哥的专栏

小程序(1)-入坑

老板想要一个小程序的东西,作为实诚却又没干过小程序开发的程序猿,二话不说,撸起袖子,开整。

1565
来自专栏Crossin的编程教室

答同学问(三)

Git课程因为有些事耽搁了,会尽快更新。今天先来说几个之前有人问过的关于Python的几个小问题。 1. 如何查看异常处理时except里的出错信息? 给ex...

3046

扫码关注云+社区

领取腾讯云代金券