openflow笔记

本文主要参考课程为《未来网络学院-SDN系列学习课程》(b站 ‘BV1ft4y1a7ip’)。辅以自己的理解。

第一部分:介绍

  1. 名字
    • open:十分开放的
    • flow:描述一组具有相同特征的数据包的集合。举个例子:筛选出两个主机之间往来的数据包 或者 同一个用户访问同一个网站的所有数据包 等。
  2. 为什么学习 OpenFlow
    • 能真实理解SDN
    • 是主流、开放的南向接口协议,很多厂商的控制器都对 OpenFlow 有明确支持
    • 是P4的前身

  1. 起源
    • 和sdn一样,起源于斯坦福
    • OpenFlow 的前身是Ethane项目(2007)
      • 集中式控制器
      • 主动下发基于流的策略
      • 此时就有sdn的雏形了
    • OpenFlow 最初用于网络实验,因为当时还没有sdn
      • 再早以前网络的搭建依靠厂商提供的api,这不够灵活。直到有了 OpenFlow ,就可以在真实网络上搭建出虚拟网/实验网,用于验证新协议/架构/算法
    • 2008 OpenFlow 论文
      • 引用6967次
  2. 究竟是什么
    • 口号:控制与转发分离
    • 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

  1. 传统网络设备
    • 数据包路径:输入端口→MAC地址学习→MAC转发→IP查找表→ACL表→端口分组表→输出端口
    • 会发现这一串都是【协议有关】的,网络芯片一旦设计完成,功能就定死了,你一个“MAC地址学习模块”干不了IP查找吧?


传统网络设备数据包路径

  1. OpenFlow 通用转发抽象模型(请注意,这是 OpenFlow 阐述的理想模型,而真实的 OpenFlow 技术没有这么完善)
    • 数据包路径:输入端口→流表1→流表2→…→流表n→输出端口
    • 最关键的是流表(flow table)
    • 规则你定,可以把流表1配置成mac学习表,流表2配置成mac转发表 等。怎么配置?—— 通过南向接口协议,给流表写点东西,使之具备某种功能。
    • 协议无关的:不限定现有协议、用户可任意编自己的协议
    • 流表间可相互跳转


OpenFlow数据包路径

实际上原生 OpenFlow 的不足

  1. 协议解析模块 不可编程
    • 模块设计遵循【固定字段匹配逻辑】(如MAC、IP、端口等),解析规则由控制器预定义,无法动态修改解析逻辑。即:
      • OpenFlow 内部预定义了什么协议就只能用什么,无法自定义新的协议头部或匹配规则
      • Experimenter Match字段虽为扩展提供了可能性,但不好用,因为交换机可能没预留扩展的余地。(硬件TCAM通常仅支持预定义的匹配域宽度)
  2. 无状态性
    • OpenFlow 流表本质为【静态规则集合】,其动作集(如转发、丢弃、修改字段)不依赖历史流量状态。例如:
      • 无法直接实现TCP连接状态跟踪(如SYN/FIN握手)、会话超时管理 
      • 计数器(Counters)仅用于统计流量,无法触发动态规则更新
    • 能不能做存状态?
      • 能是能,但由控制器维护全局状态,通过频繁流表更新模拟有状态行为。这样延迟与控制器负载都高,不适合大规模网络。
  3. 不支持网络数据包调度
    • 因为流表本质为无状态规则,无法实现动态调度(如基于实时网络状态的流量调整)。
    • 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.3版本架构图

OpenFlow 1.5版本架构图

 OpenFlow  1.5版本架构图

术语

  1. pipeline:实现maching、转发、packet修改的flow table流水线。包含一串flow table。

  2. flow table:pipeline中的一个阶段。内部包含一堆flow entry表项。

  3. flow entry:包含一些字段,如match field、匹配优先级、instruction

  4. match field:包括包头、输入端口、元数据的值

  5. instruction:当匹配后,决定如何修改action set

  6. action:具体怎么修改包的动作

  7. 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字段值

流表下发的两种模式

  1. 主动模式(Proactive)
    控制器预装流表,交换机直接匹配转发。适用于流量可预测场景(如数据中心)

  2. 被动模式(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_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架构中的南向接口协议,其核心作用是标准化控制器与交换机之间的通信接口,允许控制器通过流表下发、规则配置等方式对网络设备进行编程。

数据平面(控制转发模型)不必去深究。原因:

  1. 因为如果基于 OpenFlow 级别去编程网络应用,就像用汇编一样繁琐:OpenFlow流表的匹配域和动作指令(如转发、丢弃)需要开发者精确处理数据包的每一层协议字段。
  2. 不同厂商的OpenFlow交换机对流表的支持程度
  3. 举个例子:例如将“最短路径算法”转化为 OpenFlow 级别的规则时,你需要:手动将路径计算分解为逐跳流表项,并处理动态拓扑变化带来的流表更新问题

所以要抽象起来。