本文概览
本文主要参考课程为《未来网络学院-SDN系列学习课程》(b站 ‘BV1ft4y1a7ip’)。辅以自己的理解。
第一部分:介绍
- 名字
- open:十分开放的
- flow:描述一组具有相同特征的数据包的集合。举个例子:筛选出两个主机之间往来的数据包 或者 同一个用户访问同一个网站的所有数据包 等。
- 为什么学习 OpenFlow
- 能真实理解SDN
- 是主流、开放的南向接口协议,很多厂商的控制器都对 OpenFlow 有明确支持
- 是P4的前身
- 起源
- 和sdn一样,起源于斯坦福
- OpenFlow 的前身是Ethane项目(2007)
- 集中式控制器
- 主动下发基于流的策略
- 此时就有sdn的雏形了
- OpenFlow 最初用于网络实验,因为当时还没有sdn
- 再早以前网络的搭建依靠厂商提供的api,这不够灵活。直到有了 OpenFlow ,就可以在真实网络上搭建出虚拟网/实验网,用于验证新协议/架构/算法
- 2008 OpenFlow 论文
- 引用6967次
- 究竟是什么
- 口号:控制与转发分离
- sdn != OpenFlow
- sdn是架构. OpenFlow 只是sdn 1.0使用的协议;sdn 2.0是以P4为代表的;sdn3.0时代还未到来,那时是所有网络设备皆可编程。
- 维基百科说它是:
- 访问网络交换机/路由器的转发面的通信协议
- 能够让网络交换机决定转发路径
- 总结
- 是主流、开放的南向接口协议
- 也是数据面编程的API
- 通用转发抽象模型(重点,稍后)
- 充当“网络的x86指令集”
- 目标是:架构的演进和处理器硬件的演进是互不影响的(并行计算中的“模型”就在讨论这个问题)
南向接口协议
什么是南/北向接口?
只是针对某个组件来说的,向下的接口称为南向,向上的接口称为北向。所以南向接口是指网络设备与下层设备(如交换机和路由器)之间的接口。
要做到控制面、数据面分离,那么二者之间就要有通用的API, OpenFlow 就是API.
比如大名鼎鼎的open v switch
控制面和数据面之间使用的就是 OpenFlow 协议
其中控制平面也可以通过 OpenFlow 编程,定义数据平面设备的网络处理行为,亮点是可以自定不同粒度(粗如ip地址层面、细如网络协议层面)。而在这之前,只能在地址层面来筛选数据包。
传统网络数据平面 vs. 理想的 OpenFlow
- 传统网络设备
- 数据包路径:输入端口→MAC地址学习→MAC转发→IP查找表→ACL表→端口分组表→输出端口
- 会发现这一串都是【协议有关】的,网络芯片一旦设计完成,功能就定死了,你一个“MAC地址学习模块”干不了IP查找吧?
传统网络设备数据包路径
- OpenFlow 通用转发抽象模型(请注意,这是 OpenFlow 阐述的理想模型,而真实的 OpenFlow 技术没有这么完善)
- 数据包路径:输入端口→流表1→流表2→…→流表n→输出端口
- 最关键的是流表(flow table)
- 规则你定,可以把流表1配置成mac学习表,流表2配置成mac转发表 等。怎么配置?—— 通过南向接口协议,给流表写点东西,使之具备某种功能。
- 协议无关的:不限定现有协议、用户可任意编自己的协议
- 流表间可相互跳转
OpenFlow数据包路径
实际上原生 OpenFlow 的不足
- 协议解析模块 不可编程
- 模块设计遵循【固定字段匹配逻辑】(如MAC、IP、端口等),解析规则由控制器预定义,无法动态修改解析逻辑。即:
- OpenFlow 内部预定义了什么协议就只能用什么,无法自定义新的协议头部或匹配规则
- Experimenter Match字段虽为扩展提供了可能性,但不好用,因为交换机可能没预留扩展的余地。(硬件TCAM通常仅支持预定义的匹配域宽度)
- 模块设计遵循【固定字段匹配逻辑】(如MAC、IP、端口等),解析规则由控制器预定义,无法动态修改解析逻辑。即:
- 无状态性
- OpenFlow 流表本质为【静态规则集合】,其动作集(如转发、丢弃、修改字段)不依赖历史流量状态。例如:
- 无法直接实现TCP连接状态跟踪(如SYN/FIN握手)、会话超时管理
- 计数器(Counters)仅用于统计流量,无法触发动态规则更新
- 能不能做存状态?
- 能是能,但由控制器维护全局状态,通过频繁流表更新模拟有状态行为。这样延迟与控制器负载都高,不适合大规模网络。
- OpenFlow 流表本质为【静态规则集合】,其动作集(如转发、丢弃、修改字段)不依赖历史流量状态。例如:
- 不支持网络数据包调度
- 因为流表本质为无状态规则,无法实现动态调度(如基于实时网络状态的流量调整)。
- OpenFlow 无法直接控制交换机的队列调度机制(如WRR、SP)
- 简单的调度——组表(group table)
- 组表是在v1.1加入的
- Select动作:基于哈希或轮询算法将流量分发至多个端口,实现负载均衡。
- Indirect动作:将流量转发至特定端口,适用于固定路径调度。
OpenFlow 发展历史
网络应用场景推动了 OpenFlow 的版本发展。弄明白1.0版本升到1.1增加的feature具体是为了支持哪些场景,也是很重要的。所以不单单要抓住最hot的版本(比如1.3.5)。
OpenFlow 各个版本特性
第二部分: OpenFlow 定义的通用抽象(数据结构)
模型
OpenFlow 1.3版本架构图
OpenFlow 1.5版本架构图
术语
- pipeline:实现maching、转发、packet修改的flow table流水线。包含一串flow table。
-
flow table:pipeline中的一个阶段。内部包含一堆flow entry表项。
-
flow entry:包含一些字段,如match field、匹配优先级、instruction
-
match field:包括包头、输入端口、元数据的值
-
instruction:当匹配后,决定如何修改action set
-
action:具体怎么修改包的动作
-
action set:一组Action
上图整个就是一个流水线(pipeline)
矩形是流表(flow table),它有很多行
每一行是一个流表项(flow entry)
上图是不同版本的流表项(flow entry)的字段安排
可以看到有刚刚介绍的匹配域(match field)、指令(instruction)等
上图是早期的匹配域设计,非常清晰明了
不过现在大多使用OXM TLV来描述匹配域,请看稍后例子
流表的匹配域
实例:OXM格式的匹配域写法
OXM TLV 是 OpenFlow Extensible Match Type-Length-Value 的缩写,它用于OpenFlow协议中用于定义流表匹配字段。
采用 Type-Length-Value(类型-长度-值) 的三元组结构。
上图是OXM TLV的头格式
匹配类:如果是自定义扩展字段,值设置为:0xFFFF
类字段:取值为0~44,枚举了现有的全部
掩码标志:0为无,1为有
载荷长度:即匹配字段长度,如mac地址就是6
上图是匹配一个无掩码mac地址的流表中匹配域字段的值
上图是匹配一个有掩码mac地址的流表中匹配域字段的值
流表的指令
Instruction 和 Action 是有区别的: Instruction 说的是怎么修改动作表, Action 才是真正操作数据包的。
在最初1.0版本中,没有 Instruction ,只有 Action ,因为当时是单级流表,还没有流表流水线。
上图是 Instruction 的举例和 Action 的举例
Instruction 包括应用 Action 、清除 Action 、写 Action、跳转至某流表
对于Action ,在此介绍几个好理解的 Action:
output port_no
从port_no端口转发此数据包
drop
丢弃此数据包
change-ttl
修改数据包中ttl字段值
流表下发的两种模式
- 主动模式(Proactive)
控制器预装流表,交换机直接匹配转发。适用于流量可预测场景(如数据中心) -
被动模式(Reactive)
交换机按需询问控制器,动态安装流表。节省存储空间,但增加控制器负载
流表处理流程
一开始,网络数据包进入某端口,清空action set,初始化pipeline,从表0开始
- 如果匹配了表0,更新action set,看是否跳转到表M
- 如果未匹配,通常给出一个table-miss表项,总是要能做点事情的。
- 如果连table-miss表项都不匹配,丢弃。
组表
组表用于实现复杂转发逻辑,如组播、负载均衡、容灾备份。一个组表项包含多个动作桶(Action Buckets),每个动作桶定义一组动作(如转发到不同端口)
计量表
计量表用于实现流量监管和QoS策略,如限速、带宽保障。每个计量表项包含计量带(Meter Bands),可设置不同速率阈值及超限处理方式(如丢弃或标记)
小结
流表是基础转发单元,组表扩展复杂逻辑,计量表增强流量控制能力
第三部分: OpenFlow 协议
发生在 OpenFlow 交换机与控制器之间。基于TCP或TLS建立安全通道。(TLS用于加密通信,防止中间人攻击。)
协议交互流程
①连接建立阶段
- 三次握手:控制器与交换机通过TCP/TLS完成底层连接建立。
- OFPT_HELLO消息
双方交换支持的OpenFlow最高版本,协商一致后确定通信版本(例如1.3)。若版本不兼容,发送OFPT_ERROR消息并断开连接。
②特性协商阶段
- OFPT_FEATURES_REQUEST/REPLY
控制器发送请求(OFPT_FEATURES_REQUEST
),交换机回复包含自身能力的信息(如支持的流表数量、端口列表、动作类型等)。回复消息结构包括:datapath_id
(交换机唯一标识)n_tables
(流表数量)ports
(端口属性如MAC地址、状态等)
③配置下发阶段
- OFPT_SET_CONFIG
控制器配置交换机的全局参数:flags
:控制IP分片处理方式(如是否丢弃分片)。miss_send_len
:未匹配流表时,发送给控制器的数据包最大字节数
④数据包处理阶段
- OFPT_PACKET_IN
当交换机收到数据包但未匹配流表时,通过OFPT_PACKET_IN
消息上报控制器。消息包含:buffer_id
:数据包在交换机的缓存ID(若未被缓存则为-1
)in_port
:数据包进入的端口号data
:数据包内容(部分或全部)
- 控制器响应
控制器根据策略下发处理指令:- OFPT_FLOW_MOD:添加/删除/修改流表项。例如,
ADD
指令预装流表,指导后续同类数据包转发 - OFPT_PACKET_OUT:直接指示交换机转发缓存的数据包,并可选附带动作(如修改包头)
- OFPT_FLOW_MOD:添加/删除/修改流表项。例如,
⑤状态维护与异常处理
- OFPT_ECHO_REQUEST/REPLY
定期发送心跳检测,确保连接存活。若超时未回复,判定对方故障 -
OFPT_ERROR
报告错误类型和原因,例如:OFPET_HELLO_FAILED
(版本不兼容)OFPET_BAD_ACTION
(无效动作指令)
- OFPT_PORT_STATUS
交换机主动上报端口状态变化(如端口宕机或新增)
消息类型分类
消息类型 | 方向 | 功能 |
---|---|---|
Controller-to-Switch | 控制器→交换机 | 流表下发(Flow-Mod)、配置下发(Set-Config) |
Asynchronous | 交换机→控制器 | 事件上报(Packet-In、Port-Status) |
Symmetric | 双向 | 心跳检测(Echo)、错误通知(Error) |
第四部分:从 OpenFlow 到P4
OpenFlow接口一开始很简单,只抽象了单个规则表,并且表中只能在数据包特定的十二个包头字段上进行匹配(比如MAC地址、IP地址、载荷协议类型、TCP/UDP端口等等)。在过去的几年中,协议标准已经演进得越来越复杂,OpenFlow1.4的时候字段增加到41个。归结起来就是支持匹配越来越多的首部区域和支持多级的规则表,由此能够允许交换机向控制器暴露出它们更多的能力。
新的包头字段增多,而且没有表露出任何即将结束的迹象。相比持续地扩展OpenFlow 的协议标准,未来的交换机应该为包解析和包头字段匹配支持灵活的机制,允许控制器应用通过一个通用的开放的接口利用交换机的这些能力。
此时P4出现了。这是一种面向网络数据面编程的高级语言。能够用来配置交换机,告诉它们应该如何处理数据包。
总结:怎么看待 OpenFlow 的角色
最好把它理解为网络设备API,即它是SDN架构中的南向接口协议,其核心作用是标准化控制器与交换机之间的通信接口,允许控制器通过流表下发、规则配置等方式对网络设备进行编程。
数据平面(控制转发模型)不必去深究。原因:
- 因为如果基于 OpenFlow 级别去编程网络应用,就像用汇编一样繁琐:OpenFlow流表的匹配域和动作指令(如转发、丢弃)需要开发者精确处理数据包的每一层协议字段。
- 不同厂商的OpenFlow交换机对流表的支持程度
- 举个例子:例如将“最短路径算法”转化为 OpenFlow 级别的规则时,你需要:手动将路径计算分解为逐跳流表项,并处理动态拓扑变化带来的流表更新问题
所以要抽象起来。