回想一下,4.2.1节将基于目的地的转发描述为查找目的地IP地址(“match”),然后将数据包发送到交换结构到指定输出端口(“action”)的两个步骤。现在让我们考虑一个更为一般的“match-plus-action”范例,其中“match”可以在与协议栈中不同层的不同协议相关联的多个首部字段上进行。“action”可以包括将数据包转发到一个或多个输出端口(如在基于目的地的转发中)、跨导致服务的多个传出接口的负载均衡数据包(如在负载均衡中)、重写首部值(如在NAT中)、故意阻止/丢弃数据包(如在防火墙中)、将数据包发送到特殊服务器以进行进一步处理和动作(如在DPI中)等等。<br />在通用转发中,匹配加操作表(match-plus-action table)概括了我们在第4.2.1节中遇到的基于目的的转发表的概念。由于转发决策可以使用网络层和/或链路层源地址和目的地址做出,因此图4.28中所示的转发设备更准确地描述为“数据包交换机(packet switches)”,而不是第3层“路由器(routers)”或第2层“交换机(switches)”。因此,在本节的其余部分和第5.5节中,我们将把这些设备称为数据包交换机,采用SDN文献中广泛采用的术语。<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/12377925/1637597103470-49e93c40-c3ba-40ed-bab2-190a8a9d6bf9.png#clientId=u99693ef2-8a12-4&from=paste&height=699&id=u3eb1e59b&margin=%5Bobject%20Object%5D&name=image.png&originHeight=699&originWidth=971&originalType=binary&ratio=1&size=142793&status=done&style=none&taskId=u27c9aa70-cc87-4aab-b6ff-39ae94aa83c&width=971)<br />**Figure 4.28 ♦ Generalized forwarding: Each packet switch contains a match-plus-action table that is computed and distributed by a remote controller**<br />**图4.28♦通用转发:每个数据包交换机都包含一个由遥控器计算和分发的匹配加动作表**<br />图4.28显示了每个数据包交换机中的匹配加操作表(match-plus-action table),该表由远程控制器计算、安装和更新。我们注意到,虽然各个数据包交换机处的控制组件可以彼此交互(例如,以类似于图4.2中的方式),但实际上,一般的匹配加动作能力是通过计算、安装和更新这些表的远程控制器来实现的。您可能需要花一分钟时间比较图4.2、4.3和4.28-您注意到图4.2和4.3中所示的基于目的地的转发与图4.28中所示的一般转发之间有什么相似之处和不同之处?<br />我们下面关于通用转发的讨论将基于OpenFlow[McKeown 2008、ONF 2020、Casado 2014、Tourrilkets 2014]--这是一个高度可见的标准,它开创了匹配加动作转发抽象和控制器的概念,以及更广泛的SDN革命[Feamster 2013]。我们将主要考虑OpenFlow 1.0,它以一种特别清晰和简洁的方式引入了关键的SDN抽象和功能。由于在实现和使用过程中积累了经验,OpenFlow的后续版本引入了额外的功能;OpenFlow标准的当前版本和早期版本可以在[ONF 2020]中找到。<br />匹配加动作转发表(在OpenFlow中称为**流表(flow table)**)中的每个条目包括:
- 传入数据包将与之匹配的一组首部字段值。与基于目的地的转发一样,基于硬件的匹配在TCAM内存中执行速度最快,可能会有超过一百万个目的地地址条目[Bosshart 2013]。不匹配流表条目的数据包可以被丢弃或发送到远程控制器进行更多处理。在实践中,出于性能或成本的原因,一个流表可能由多个流表实现[Bosshart 2013],但这里我们将重点介绍单个流表的抽象。
- 当数据包与流表条目匹配时更新的一组计数器。这些计数器可能包括与该表条目匹配的数据包数量,以及自上次更新该表条目以来的时间。
- 数据包与流表条目匹配时要执行的一组操作。这些操作可以是将数据转发到给定的输出端口、丢弃数据包、复制数据包并将其发送到多个输出端口、和/或重写选定的首部字段。
我们将分别在第4.4.1节和第4.4.2节中更详细地探讨匹配和操作。然后,我们将研究如何使用网络范围内的每数据包交换机匹配规则集合来实现通用的功能,包括路由、第2层交换、防火墙、负载均衡、虚拟网络等,请参见第4.4.3节。最后,我们注意到流表本质上是一个API,通过它可以对单个数据包交换机的行为进行编程;我们将在第4.4.3节中看到,通过在一组网络数据包交换机中适当地编程/配置这些表,可以类似地对整个网络范围的行为进行编程[Casado 2014]。
4.4.1 Match
图4.29显示了OpenFlow 1.0 match-plus-action规则中可以匹配的11个数据首部字段和传入端口ID。回想一下1.5.2节,到达数据包交换机的链路层(第2层)帧将包含作为其有效负载的网络层(第3层)数据报,而网络层(第3层)数据报通常又包含传输层(第4层)段。我们观察到的第一点是,OpenFlow的匹配抽象允许在三层协议头中选定的字段上进行匹配(因此公然违反了我们在第1.5节中研究的分层原则)。由于我们还没有讨论链路层,只需说明图4.29中所示的源和目的MAC地址是与帧的发送和接收接口相关联的链路层地址即可;通过基于以太网地址而不是IP地址进行转发,我们可以看到启用OpenFlow的设备可以与路由器(第3层设备)转发数据报以及交换机(第2层设备)转发帧一样发挥作用。以太网类型字段对应于帧的有效载荷将被多路分解到的上层协议(例如,IP),而VLAN字段与我们将在第6章中研究的所谓虚拟局域网有关。在OpenFlow 1.0规范中可以匹配的12个值的集合在更新的OpenFlow规范[Bosshart 2014]中已经增长到41个值。
Figure 4.29 ♦ Packet matching fields, OpenFlow 1.0 flow table
图4.29 OpenFlow1.0流表中的♦数据包匹配字段
入站端口(ingress port)指的是数据包交换机上接收数据包的输入端口。数据包的IP源地址、IP目的地址、IP协议字段和IP服务类型字段已在4.3.1节前面讨论过。传输层源和目的端口号字段也可以匹配。
流表条目(Flow table entries)也可以具有通配符。例如,流表中的IP地址128.119..将与地址的前16位为128.119的任何数据报的相应地址字段相匹配。每个流表条目还具有相关联的优先级。如果数据包与多个流表条目匹配,则选定的匹配和相应操作将是该数据包与之匹配的最高优先级条目的匹配和相应操作。
最后,我们发现并非IP首部中的所有字段都可以匹配。例如,OpenFlow不允许基于TTL字段或数据报长度字段进行匹配。为什么允许某些字段匹配,而不允许其他字段匹配?毫无疑问,答案与功能和复杂性之间的权衡有关。选择抽象的“艺术”是提供足够的功能来完成一项任务(在这种情况下,实现、配置和管理以前通过各种网络层设备实现的通用的网络层功能),而不会给抽象带来过多的细节和概括性负担,从而使其变得臃肿和不可用。巴特勒·兰普森(Butler Lampson)曾著名地指出(兰普森1983):
一次做一件事,把它做好。接口应该捕获抽象的最基本要素。不要一概而论,一概而论通常是错误的。
考虑到OpenFlow的成功,人们可以推测它的设计者确实选择了很好的抽象。有关OpenFlow匹配的更多详细信息,请参阅[ONF 2020]。
4.4.2 Action
如图4.28所示,每个流表条目都有一个零个或多个动作的列表,用于确定要应用于与流表条目匹配的数据包的处理。如果有多个操作,它们将按列表中指定的顺序执行。
最重要的可能行动包括:
- 转发(Forwarding)。传入数据包可以被转发到特定的物理输出端口、在所有端口(除了它到达的端口之外)上广播或者在选定的一组端口上多播。该数据包可以被封装并发送到该设备的远程控制器。然后,该控制器可以(或可以不)对该数据包采取一些动作,包括安装新的流表条目,并且可以将该数据包返回到设备以根据更新的流表规则集进行转发。
- 丢弃(Dropping)。没有动作的流表条目表示应该丢弃匹配的数据包。
- 修改-字段(Modify-field)。在将数据包转发到选定的输出端口之前,可以重写10个数据包首部字段(图4.29中显示的所有第2层、第3层和第4层字段,IP协议字段除外)中的值。
4.4.3 匹配加动作操作的OpenFlow示例 OpenFlow Examples of Match-plus-action in Action
现在已经考虑了通用转发的匹配和操作组件,让我们将这些想法放在图4.30所示的示例网络的上下文中。该网络有6台主机(h1、h2、h3、h4、h5和h6)和三台数据包交换机(s1, s2 和 s3),每台都有四个本地接口(编号为1到4)。我们将考虑要实现的许多网络范围的行为,以及实现此行为所需的s1, s2 和 s3中的流表条目。
Figure 4.30 ♦ OpenFlow match-plus-action network with three packet switches, 6 hosts, and an OpenFlow controller
图4.30♦具有三台数据包交换机、6台主机和一个OpenFlow控制器的OpenFlow匹配加动作网络第一个示例:简单转发 A First Example: Simple Forwarding
作为一个非常简单的例子,假设期望的转发行为是从h5或h6去往h3或h4的数据包要从s3转发到s1,然后从s1转发到s2(从而完全避免使用s3和s2之间的链路)。s1中的流表条目为:
s1 Flow Table (Example 1) | |
---|---|
Match | Action |
Ingress Port = 1 ; IP Src = 10.3.. ; IP Dst = 10.2.. | Forward(4) |
… | … |
当然,我们还需要s3中的流表条目,以便从h5或h6发送的数据报通过传出接口3转发到s1:
s3 Flow Table (Example 1) | |
---|---|
Match | Action |
IP Src = 10.3.. ; IP Dst = 10.2.. | Forward(3) |
… | … |
最后,我们还需要s2中的流表条目来完成第一个示例,以便将来自s1的数据报转发到它们的目的地,即主机h3或h4:
s2 Flow Table (Example 1) | |
---|---|
Match | Action |
Ingress port = 2 ; IP Dst = 10.2.0.3 | Forward(3) |
Ingress port = 2 ; IP Dst = 10.2.0.4 | Forward(4) |
… | … |
第二个示例:负载均衡 A Second Example: Load Balancing
作为第二个示例,让我们考虑一个负载平衡场景,其中从h3发往10.1..的数据报将通过s2和s1之间的直接链路转发,而从h4发往10.1..的数据报将通过s2和s3之间的链路转发(然后从s3转发到s1)。请注意,使用IP的基于目的地的转发无法实现此行为。在这种情况下,s2中的流表将为:
s2 Flow Table (Example 2) | |
---|---|
Match | Action |
Ingress port = 3; IP Dst = 10.1.. | Forward(2) |
Ingress port = 4; IP Dst = 10.1.. | Forward(1) |
… | … |
s1还需要流表条目,以便将从s2接收到的数据报转发给h1或h2;s3需要流表条目将从s2接收到的数据报通过接口3转发到s1。看看你是否能算出s1和s3的这些流表项。
第三个例子:防火墙 A Third Example: Firewalling
作为第三个示例,让我们考虑一个防火墙场景,在该场景中,s2只希望接收(在其任何接口上)从连接到的s3的主机发送的流量。
s2 Flow Table (Example 3) | |
---|---|
Match | Action |
IP Src = 10.3.. IP Dst = 10.2.0.3 | Forward(3) |
IP Src = 10.3.. IP Dst = 10.2.0.4 | Forward(4) |
… | … |
如果s2的流表中没有其它条目,则只会将来自10.3.*.*的流量转发到连接到s2的主机。<br />虽然我们在这里只考虑了几个基本场景,但希望通用转发的多功能性和优势是显而易见的。在作业问题中,我们将探索如何使用流表来创建许多不同的逻辑行为,包括虚拟网络-两个或更多逻辑上分离的网络(每个网络都有自己独立且不同的转发行为)-它们使用相同的数据包交换机和链路的物理集合。在第5.5节中,当我们学习计算和分发流表的SDN控制器,以及用于数据包交换机与其控制器之间通信的协议时,我们将返回到流表。<br />我们在本节中看到的匹配加动作流表实际上是一种有限形式的可编程性,根据数据报的报头值和匹配条件之间的匹配,指定路由器应该如何转发和操作(例如,更改报头字段)数据报。人们可以想象一种更丰富的可编程性形式-一种具有更高级结构的编程语言,例如变量、通用算术和布尔运算、变量、函数和条件语句,以及专门为线速数据报处理而设计的结构。P4(独立于编程协议的数据包处理器(Programming Protocol-independent Packet Processors))[P4 2020]就是这样一种语言,自五年前引入以来已经获得了相当大的兴趣和吸引力[Bosshart 2014]。