← 返回 计算机网络原理

计算机网络原理

第四章 第6节补充

一、先从普通转发表开始

以前我们讲的 IP 转发表是这样的:

目的网络 | 掩码 | 下一跳 | 接口 130.130.130.0 | 255.255.255.0 | - | Eth1 140.140.140.0 | 255.255.255.0 | - | Eth2 default | - | 某下一跳 | 某接口

路由器收到一个 IP 数据报后,只看一个东西:

目的 IP 地址

然后做:

目的IP&Mask=Destination\text{目的}IP\mathbin{\&}Mask=Destination

匹配上哪一项,就从对应接口发出去。

所以传统路由器可以概括成:

目的IP输出接口\text{目的}IP\to \text{输出接口}

也就是:看目的 IP,决定往哪走。

二、那流表比普通转发表强在哪里?

普通转发表只看目的 IP。

但是流表可以看很多字段。

比如一个分组来了,它的首部里有很多信息:

链路层:

输入端口

源 MAC 地址

目的 MAC 地址

以太网类型

VLAN ID

网络层:

源 IP 地址

目的 IP 地址

IP 协议号

ToS / DSCP

运输层:

TCP/UDP 源端口

TCP/UDP 目的端口

流表可以从这些字段里挑一些来匹配。

所以它不是只会:

目的IP转发\text{目的}IP\to \text{转发}

而是可以:

很多首部字段某种动作\text{很多首部字段}\to \text{某种动作}

这个是:通用转发 general forwarding

三、什么叫“流”?

在 OpenFlow 里,流可以理解成:

具有相同特征的一类分组。

比如:

例子 1:所有去 51.6.0.8 的包

IPDst=51.6.0.8IPDst=51.6.0.8

这是一类流。

例子 2:所有 TCP 目的端口为 22 的包

TCPDstPort=22TCPDstPort=22

这也是一类流。

这通常代表 SSH 流量。

例子 3:所有从 10.0.0.3 发往 10.2.x.x 的包

IPSrc=10.0.0.3IPDst=10.2..IPSrc=10.0.0.3IPDst=10.2.*.*

这也是一类流。

所以“流”本质上就是:

用若干首部字段定义出来的一类数据包。

四、流表是什么?

流表就是很多条规则组成的表。

每条规则一般有三部分:

Match+Action+StatsMatch+Action+Stats

也就是:

部分 | 含义 Match | 匹配哪些分组 Action | 匹配后怎么处理 Stats | 统计匹配了多少包、多少字节

1. Match:匹配条件

比如:

IPDst=51.6.0.8IPDst=51.6.0.8

或者:

TCPDstPort=22TCPDstPort=22

或者:

SrcMAC=xx:xx:xxSrcMAC=xx:xx:xx

匹配字段可以跨很多层。

2. Action:动作

匹配之后可以做很多动作。

常见动作:

forward(2):从端口 2 转发

drop:丢弃

modify:修改首部字段

send to controller:发给控制器

flood:泛洪

所以流表不只是“转发”,还可以“丢弃、修改、上交控制器”。

3. Stats:统计

统计这条规则匹配了:

多少个 packet

多少 byte

比如防火墙、流量管理、计费都可能用到。

五、最简单的流表示例

假设有一张流表:

Match | Action IP Dst = 51.6.0.8 | forward(6) TCP DstPort = 22 | drop IP Src = 128.119.1.1 | drop otherwise | send to controller

意思是:

如果目的 IP 是 51.6.0.8:

转发到端口6\text{转发到端口}6

如果 TCP 目的端口是 22:

丢弃\text{丢弃}

如果源 IP 是 128.119.1.1:

丢弃\text{丢弃}

如果都不匹配:

交给控制器决定\text{交给控制器决定}

六、为什么说流表可以统一抽象很多设备?

因为很多网络设备本质都能写成:

匹配某些字段+做某个动作\text{匹配某些字段}+\text{做某个动作}

1. 路由器

传统路由器:

匹配:

目的IP前缀\text{目的}IP\text{前缀}

动作:

从某个端口转发\text{从某个端口转发}

所以路由器可以写成:

Match | Action IP Dst = 130.130.130.0/24 | forward(Eth1) IP Dst = 140.140.140.0/24 | forward(Eth2)

2. 二层交换机

交换机主要看 MAC 地址。

匹配:

目的MAC地址\text{目的}MAC\text{地址}

动作:

从某个端口转发\text{从某个端口转发}

比如:

Match | Action MAC Dst = AA:BB:CC:DD:EE:FF | forward(3)

所以交换机也可以用流表表示。

3. 防火墙

防火墙主要是允许或阻止流量。

比如禁止 SSH:

匹配:

TCPDstPort=22TCPDstPort=22

动作:

dropdrop

也就是:

Match | Action TCP DstPort = 22 | drop

再比如禁止某个 IP:

Match | Action IP Src = 128.119.1.1 | drop

所以防火墙也能写成流表。

4. NAT

NAT 要修改地址和端口。

比如内网主机:

10.0.0.1:334510.0.0.1:3345

要转换成:

138.76.29.7:5001138.76.29.7:5001

可以抽象成:

Match | Action IP Src = 10.0.0.1, TCP SrcPort = 3345 | rewrite SrcIP = 138.76.29.7, rewrite SrcPort = 5001, forward

所以 NAT 也是:匹配 + 修改 + 转发

七、OpenFlow 是什么?

OpenFlow 不是一个新的普通路由算法。

它更像是:控制器和交换设备之间沟通流表规则的协议。

在 SDN 里,网络分成:控制平面

由控制器负责。

它像“大脑”。

负责决定:

哪些流应该走哪条路径

哪些流应该丢弃

哪些流应该修改

哪些规则应该安装到交换机里

数据平面

由 OpenFlow 交换机负责。

它像“手脚”。

只负责按照流表执行动作:

查表

匹配

转发

丢弃

修改

OpenFlow 的作用

OpenFlow 负责让控制器告诉交换机:

你这里装一条规则:匹配什么,动作是什么。

OpenFlow 是 SDN 控制器给交换机下发流表规则的一种协议。

八、OpenFlow 工作流程

假设一个分组进入 OpenFlow 交换机。

它大概这样处理:

第一步:查流表

交换机拿分组首部字段去匹配流表。

第二步:找到匹配项

如果匹配到一条规则,就执行对应 action。

比如:

forward(3)forward(3)

就从端口 3 发出去。

第三步:如果没有匹配项

交换机可以把这个分组发给控制器:

sendtocontrollersendtocontroller

控制器看完之后决定:

丢弃

转发

安装一条新规则

修改路径

然后控制器再把规则下发给交换机。

九、为什么要用 OpenFlow?

传统网络里,每台路由器自己运行协议,自己决定怎么转发。

OpenFlow/SDN 的思想是:把决策集中到控制器,让底层设备只执行规则。

这样有几个好处。

1. 网络可编程

以前路由器行为比较固定。

现在控制器可以像写程序一样控制网络。

比如:

某类流量走路径 A

某类流量走路径 B

游戏流量优先

某个源 IP 全部封禁

某个端口全部丢弃

2. 统一管理

控制器掌握全网拓扑,可以统一计算路径。

不用每台设备各自为战。

3. 灵活实现多种设备功能

同一个 OpenFlow 交换机,通过不同流表,可以表现得像:

路由器

交换机

防火墙

NAT

负载均衡器

十、优先级 priority

这点很重要,因为流表可能有多条规则同时匹配。

比如一个分组:

IPSrc=128.119.1.1TCPDstPort=22IPSrc=128.119.1.1TCPDstPort=22

它可能同时匹配:

Match | Action IP Src = 128.119.1.1 | drop TCP DstPort = 22 | drop IP Dst = 51.6.0.8 | forward(6)

那么到底按哪条?

OpenFlow 流表项通常有:

priority,优先级。

如果多条规则匹配,选优先级最高的。

这个和 IP 最长前缀匹配有点像。

传统路由表是:多个 IP 前缀匹配,选最长前缀。

流表是更通用的:多个流表项匹配,选优先级高的。

十一、通配符 wildcard(就是正则表达式)

流表里经常有 *。

* 表示:这个字段不关心,什么值都可以。

比如:

IP Src | IP Dst | TCP DstPort | Action * | 51.6.0.8 | * | forward(6)

表示:不管源 IP 是谁,不管端口是多少,只要目的 IP 是 51.6.0.8,就从端口 6 转发。

再比如:

IP Src | IP Dst | TCP DstPort | Action * | * | 22 | drop

表示:不管谁发的,也不管发给谁,只要 TCP 目的端口是 22,就丢弃。

十二、结合打游戏的例子理解

比如一个校园网/公司网想禁止某些流量。

它可以下发 OpenFlow 规则:

Match | Action UDP DstPort = 某游戏端口 | drop

那游戏数据包就过不去。

如果它想让游戏流量走低延迟链路,可以写:

Match | Action UDP DstPort = 游戏端口 | forward(高速出口)

如果它想让网页流量走普通出口:

Match | Action TCP DstPort = 80 or 443 | forward(普通出口)

所以 OpenFlow 很像:

用规则表控制不同类型流量怎么走。

十三、OpenFlow 和普通路由表的区别

对比 | 普通路由表 | OpenFlow 流表 主要匹配字段 | 目的 IP | 多层首部字段 动作 | 转发到下一跳/接口 | 转发、丢弃、修改、送控制器 控制方式 | 路由协议计算 | 控制器下发 灵活性 | 较低 | 高 表项形式 | 目的网络 → 接口 | Match → Action 典型应用 | 路由器 | SDN、交换机、防火墙、NAT 等

路由表是流表的一种特例。

传统路由表相当于只匹配目的 IP,只执行转发动作的流表。

十四、其实可以把 OpenFlow 想成“网络里的 if 语句”

这特别好理解。

一条流表项就像一条 if 语句:

if 目的IP == 51.6.0.8: 从端口6转发

或者:

if TCP目的端口 == 22: 丢弃

或者:

if 源IP == 10.0.0.1 and 目的IP == 10.2.0.4: 从端口3转发

所以 OpenFlow 设备其实就是在高速执行很多条:

ifmatchthenactionifmatchthenaction

十五、OpenFlow 例子:控制一条路径

假设有三个交换机:

s1s2s3s1\to s2\to s3

想让:

h5h4h5\to h4

的数据走这条路径。

控制器可以分别给每个交换机下规则。

在 s1 上

匹配:

IPSrc=h5IPDst=h4IPSrc=h5IPDst=h4

动作:

forward(通向s2的端口)forward(\text{通向}s2\text{的端口})

在 s2 上

匹配:

IPSrc=h5IPDst=h4IPSrc=h5IPDst=h4

动作:

forward(通向s3的端口)forward(\text{通向}s3\text{的端口})

在 s3 上

匹配:

IPSrc=h5IPDst=h4IPSrc=h5IPDst=h4

动作:

forward(通向h4的端口)forward(\text{通向}h4\text{的端口})

这样一来,整条路径就被控制器安排好了。

编排出来的表项可以控制网络范围内的行为。

十六、OpenFlow 和 SDN 的关系

SDN是一种网络架构思想:

控制平面和数据平面分离,控制器集中控制网络。

OpenFlow

是 SDN 中一种具体协议:

控制器通过 OpenFlow 给交换机下发流表。

十七、自问自答

问:什么是流表?

答:

流表是通用转发设备中的规则表,每个表项通常由匹配字段、动作和统计信息组成。设备对到达分组的首部字段进行匹配,并执行对应动作。

问:OpenFlow 表项包括什么?

答:

Match、Action、Stats。

问:OpenFlow 的 Match 可以匹配哪些字段?

答:

可以匹配输入端口、源/目的 MAC、VLAN、源/目的 IP、IP 协议号、TCP/UDP 源端口和目的端口等多个层次的首部字段。

问:OpenFlow 的 Action 有哪些?

答:

可以转发到某个端口、丢弃、修改首部字段,或者封装后发送给控制器。

问:为什么 OpenFlow 是通用转发?

答:

因为它不局限于目的 IP 转发,而是能匹配链路层、网络层、运输层多个字段,并执行转发、丢弃、修改等动作。

问:OpenFlow 如何抽象路由器、交换机、防火墙、NAT?

答:

路由器匹配目的 IP 前缀并转发;交换机匹配目的 MAC 并转发或泛洪;防火墙匹配 IP 地址或端口并允许/丢弃;NAT 匹配地址和端口并改写地址端口。它们都能表示成匹配加行动。

OpenFlow 的核心是流表,流表的核心是 Match + Action + Stats。

传统路由表:

目的IP输出接口\text{目的}IP\to \text{输出接口}

OpenFlow 流表:

任意首部字段组合转发/丢弃/修改/上交控制器\text{任意首部字段组合}\to \text{转发}/\text{丢弃}/\text{修改}/\text{上交控制器}

所以:路由表是流表的特例,OpenFlow 是把网络设备行为变成可编程规则表。

OpenFlow 让网络设备不再只会按目的 IP 转发,而是可以像执行 if 语句一样,根据多层首部字段灵活处理分组。