0x01 术语


术语 解释 应用举例
Action OpenFlow中的动作,应用在报文上面 转发到某个端口,丢弃
List of actions 有顺序的动作列表,允许重复,作用是累加的。如果有output动作,那么将拷贝一份报文及其pipeline fields,供后续处理,不影响原始的报文 apply-actions,packet-out
Set of actions 无顺序的动作集,不允许有重复 组表,流表
Action set 动作集,附加在报文之上,流表结束后执行 流表
Control channel 控制通道,用于虚拟交换机和sdn控制器通信
Counter 计数器 报文统计,报文字节数统计
Datapath 一个完整的虚拟交换机,包括流表,组表,计量表等,也即一个bridge
Flow entry 流表项,在流表中
Flow table 流表,包含多个流表项
Group 组,包含在组表中,一个Group包含多个action bucket 组播转发
Hybrid switch 一种实现了openflow交换机和传统交换机的交换机
Instructions 指令,和动作的区别在于指令是立即执行的,每个流表被命中之后立即执行
Instructions set 指令集,和动作集类似
Match field 匹配域,用于匹配报文,flow entry的一部分
Metadata 一个带有掩码的寄存器 用于流表之间传输数据
Meter 流量计量 QoS
Pipeline 报文的流水线处理,即多个flow-tale构成一个pipeline
Pipeline field 在pipeline处理过程中,除了报文头部之外的数据 ingress port,metadata

0x02 组件概览


image.png

0x03 Openflow Ports


OpenFlow的端口即报文转发的端口,不一定和物理端口是完全一致的,比如被openflow禁用,或者openflow自身的虚拟端口。一个报文的生命周期:
OpenFlow将端口分为以下几种类型:

  • Physical ports:即真实的物理接口
  • Logical ports:交换机自身定义的端口,和物理接口没有一一对应的关系,例如聚合组,隧道口
  • Reserved ports:包括以下几种: | 端口类型
    (required,optional) | 含义 | 应用范围 | | | :—-: | :—-: | :—-: | —- | | | | Ingress port | Output port | | ALL | 所有交换机定义的standar ports |
    | 该接口下报文将被转发到除了ingress port,OFPPC_NO_FWD port之外的所有标准端口 | | CONTROLLER | 和控制器连接的控制隧道 | 代表该报文来自控制器 | 将报文封装在packet-in消息里面通过隧道发送到控制器 | | TABLE | 指代pipeline的起点 | | 将该报文投递到pipeline的起点,从头开始处理 | | IN_PORT | 即ingress port | | 将报文发送到报文的入口 | | ANY | 任意端口,控制消息中使用 | | | | UNSET | 未设置的端口,匹配action set的出口中使用 | | | | LOCAL | 代表本地的网络栈 | | | | NORMAL | 表示使用传统交换机转发方式转发 | | | | FLOOD | 表示使用传统交换机转发方式泛洪 | | |

  • Strandard ports:包括Physical Ports,Logical Ports,LOCAL Reserved Ports

0x04 OpenFlow Tables


Pipeline

OpenFlow Pipeline包括多个流表,每个流表包含多个流表项。报文从表0开始处理,根据命中的指令选择是否进入下一级流表。
image.png

流表及流表项

流表项组成

Match Fields Priority Counters Instructions Timeouts Cookies Flags
  • Match Fields:匹配域,除了报文的头部以外,还包括Pipeline Fields
  • Priority:优先级
  • Counters:计数器
  • Instructions:指令
  • Timeouts:包含Hard timeout,Idle timeout
  • Cookies:交换机处理报文的时候没有使用,由控制器下发,标识一条流表项
  • FLags:表明表项的管理方式,比如表项被删除是否上报到控制器

每条流表项的key为:(Match Fields, priority)

匹配算法

根据控制器的配置,流表可以被分成两部分,Ingress和Egress,且Egress表的编号均在Ingress之后。

  1. #OFP_EGRESS is defined by controller
  2. if table_num > OFP_EGRESS
  3. #This table is Egress
  4. else
  5. #This table is Ingress

相应的匹配也分两阶段,Ingress和Egress。 入口的报文先进行Ingress处理,之后根据在出口的上下文下进行Egress处理。匹配过程中按照优先级匹配,优先级高的先命中,一个Flow Table只会有一个Entry命中。如果同时存在优先级相同的表项两个同时命中的话,官方文档对这种情况定义为Undefined。
image.png

特殊流表项(Table-Miss)

流表项(Match Fileds, Priority) = (*, 0)即为Table-Miss表项,用于流表的默认动作。例如发送给控制器以产生新的流表项,或者丢弃。该表项是控制器安装的表项,并非默认存在于流表中,如果控制器没有安装该表项,则未匹配中的报文就默认丢弃。

Instructions

Instructions是Flow Entry的一个成员,命中之后执行。总共包括以下几个,并且执行顺序也是按照以下的顺序,每个流表项的instruction为一个集合,即在同一个流表项中不允许出现相同的instructions。

Instruction 含义 应用
Apply-actions 不改动动作集,动作立即执行,action为有顺序的list 修改报文,在多个流表执行同一个动作
Clear-actions 清除Action set里面的action 在table-miss flow entry中使用
Write-actions 添加动作到动作集,如果有相同的将覆盖原有的 ANY
Write-metadata 修改metadata
stat-trigger 如果计量值超过指定值,则发一个消息到控制器
Goto-table 跳转到某个流表,必须是编号比自己大的流表,不允许向后跳转 ANY

流表的输入包括三部分:Action Set,Pipeline Fields,Packet。经过每张流表的处理,每一部分都可能被修改,Action Set可能被Clear-actions/Wrige-actions修改,Pipeline Fields可能被Apply-actions修改,Packet可能被Apply-actions修改。被修改后的数据通过Goto-table指定传递给下一张流表。如果没有Goto-table指令,那么Action set将被立即执行。
image.png

Action set

正如前面介绍的,Action set是附加在报文上面的。Ingress的初始动作集为空,但是Egress的初始动作集包含一个Output current port的动作,动作集的执行按照如下的顺序:

action 含义
copy TTL inwards
pop 弹出标签(vlan/mpls/PBB)
push MPLS 压入MPLS标签
push PBB 压入PBB标签
push VLAN 压入Vlan标签
copy TTL outwards
decrememet TTL 减少IP报文的TTL值
set set-field动作
QoS QoS相关,比如set-queue,meter
group 组动作
output 转发报文

如果output和group有出口是一样的,那么group的优先执行,output则不会再执行。对于output,ingress和Egress有不同的处理方式。ingress的output会检查是否有egress-table,如果有的话初始化当前出口为动作集,继续执行Egress-table;egress的output则会立即执行。

Actions

Action 含义
Output port_no 转发报文
Group group_id 执行对应的组动作
Drop 事实上不存在这个动作,这是个隐式的动作,没有出口即代表丢弃
Set-Queue queue_id 设置队列的id,出口队列
Meter meter_id 计量表,主要是限速
Push-Tag/Pop-Tag ethertype 压/弹标签,有vlan/mpls/pbb
Set-Field field_type value 设置报文头部的字段值
Copy-Field src_field_typ dst_field_type 在报文头部及pipeline域之间拷贝
Change-TTL ttl 改变报文的ttl

Counters

OpenFlow的白皮书定义了很多counter,包含在flow-table,flow-entry,port,queue, group,group bucket,meter,meter band。详情参考白皮书5.9的表格。

Group Table

Openflow仅定义了一个组表,里面包含多个组表项,供action-set里面引用。每个组表项包含以下几个字段:

字段名 含义
group identifier 标识符,引用组的时候使用
group type 组类型
counters 计数器
action buckets 每个bucket即为一个action set,所有的action bucket为一个list,即action bucket间执行是按照配置的顺序,action bucket内部执行是按照action-set的顺序

OpenFlow定义的组类型包括以下4种:

  • indirect:该组仅包含一个action bucket,和包含一个buckt的all类型是一样的。
  • all:该类型可以包含多个bucket,命中后执行所有的action bucket。组播/广播中使用到。
  • select:多选一的类型,该类型包含多个bucket,但是只选择一个bucket来执行。选择哪一个依赖于配置的算法。这种类型可以实现负载均衡作用。
  • fat failover:多选一的类型,选择第一个可用的bucket。判断是否可以依赖于每个bucket附加的端口或者group,该类型需要实现可用性机制。

Meter Table

和Group Table类似,Meter Table也只有一张,包含了多个表项。表项的构成如下所示,其中一个表项可以包含多个Meter Band,meter Band之间是没有顺序的,但是一个报文只能有一个meter band被执行。能被执行的Meter Band其速率要超过配置的速率。
image.png

  • Meter Identifier:标识符,被引用的时候使用。
  • Meter Bands:由多个meter band组成。
  • Counters:计数器

多个Meter band,到底那一个可以被执行,openflow没有明确的定义,只是规定了一些约束。最简单的可以根据Rate的大小,越大的优先级越高。

  • Band Type:类型,包括Drop,Dscp remark。
  • Rate:配置的速率大小,根据这个速率区分各个Meter band。
  • Burst:定义该meter band的粒度。
  • Counter:计数器。
  • Parameters:和Band Type相关联,比如DSCP remark其参数就存放在这个字段。

    0x05 OpenFlow Channel


OpenFlow的控制隧道是控制器和交换机的通信接口,可以基于TLS进行加密通信,或者直接使用TCP。一台交换机可以连接一到多个控制器。

通信消息

控制隧道的通信消息可以分为以下三类:

  • Controller-to-Switch:由控制器发起的消息。用于管理,查询交换机。
  • Asynchronous:由交换机发起的消息,上报交换机的状态,事件。
  • Symmetric:对称消息,由控制器或者交换机发起。 | 消息类型 | 子消息 | 含义 | 用途 | | —- | —- | —- | —- | | Controller-to-Switch | Feature | 查询交换机的特性,能力 | 兼容性 | | | Configuration | 设置或者查询交换机配置 | | | | Modify-State | 修改交换机的状态 | 修改/添加/删除流表 | | | Read-State | 查询交换机的状态 | | | | Packet-out | 控制器指定交换机某个端口发送报文 | | | | Barrier | 消息栅栏 | 由于保证消息之前的依赖 | | | Role-Request | 请求或者设置隧道的角色 | 多个连接时使用 | | | Asynchronous-Configuration | 设置或者查询异步消息的过滤器 | 连接多个控制器时,过滤交换机上报的消息,只关注自己需要的,防止隧道中消息太多 | | Asynchronous | Packet-in | 转发报文到控制器,可以在交换机缓存报文,然后上报报文头部及buffer-id | | | | Flow-Removed | 发送流表项被删除到控制器 | | | | Port-status | 端口发生变化 | 包括配置变化,状态变化 | | | Role-status | 隧道角色变化 | | | | Controller-Status | 控制隧道变化,交换机通知其他控制器 | 通过交换机,控制器之间可以知道对端的状态 | | | Flow-monitor | 流变化消息 | | | Symmetric | Hello | 连接建立的握手 | | | | Echo | 探测报文,需要回复 | 心跳,测量延时 | | | Error | 通知另一端出错 | 交换机回复控制器请求失败 | | | Experimenter | 实验特性 | 在加入标准前试验新特性 |

连接管理

OpeFlow的连接包括两种:主连接,次连接。次连接依赖于主连接,主连接断开后,次连接也要断开连接。次连接主要用于优化数据转发消息(Packet-in),比如用udp来实现次连接,从而加快转发速率。按照网络位置,连接也可以分为带内(in-band),带外(out-of-band)。带内连接的报文也需要通过OpenFlow pipeline的处理,因此带内连接交换机需要预先初始化好流表,使得报文可以进来处理。带外连接指的是连接报文所处的网络不是由OpenFlow管理的。

连接URI

交换机通过URI:protocol:name-or-address[:port]来标识一台控制器的隧道。

  • 协议:对于主连接,可以为TLS/TCP;对于次连接,其协议可以为TLS/DTLS/TCP/UDP
  • 端口号:可以配置指定也可以使用默认的6653

控制器通过(Datapath ID,Auxiliary ID)来标识一条连接,主连接的Auxiliary ID为0,

连接建立

控制隧道的建立分为以下三步:

  1. 根据指定的协议建立传输层连接,TCP或者TLS
  2. 连接建立之后立马发送Hello报文给对端。收到对端的报文之后,根据报文中携带的OpenFlow版本号信息,选择双方都支持的最高版本进行通信。如果不支持对端的OpenFlow版本,需要给对端发送一个Error Message,并终止连接。
  3. 控制器发送Feature消息获取交换机的Datapath-id,用于标识交换机。

image.png

连接维护

OpenFlow不处理连接的维护,连接的维护比如心跳,流量管理,拥塞管理应该由下层传输层协议维护。在连接因为网络的问题导致中断的情况下,发起连接的一端需要主动去重连,但是如果是因为收到Error消息导致的主动断开,则不需要重连。在连接状态发生变化的时候(中断或者重新连接上),OpenFlow交换机需要主动上报改连接的状态给其他控制器,使得其他控制器可以据此作出响应。如果所有的连接均中断,那么交换机可以运行在以下两种模式:

  • fail secure mode:在这种模式下,唯一的变化是所有发给控制器的报文都将被丢弃,同时当前的流表还是会按照既定的时间老化。
  • fail standalone mode:在这种模式下,交换机将变成一个普通交换机,按照传统的方式转发报文,并且可以任意修改流表。一般在Hybrid Switch才有。

    多控制器

    一台交换机可以和多台控制器连接,多台控制器之间可以做备份或者负载。一台控制器挂掉之后,交换机可以连接另外一台控制器,提高网络的高可用性;相应地,控制器可以通过Asynchronous Configuration消息来配置从交换机收什么类型的消息,以达到负载的作用。如果一台交换机连接了多台控制器,那么对于Asynchronous消息,交换机需要发送给每台控制器。对于Controller-to-Switch的消息,则根据控制器隧道分开处理,在哪条隧道收到的消息则回复给那一台控制器。此时对于流表的修改可能存在冲突,但是交换机不处理该冲突情况,由控制器之间相互协商解决。这也体现了SDN的思想,将业务逻辑的复杂性放到控制器处理。对于交换机连接的所有控制器来说,他们之间通过角色选举决定如何由谁控制该交换机。控制器角色分为以下三种:

  • Eqal:该角色可以读写交换机的状态,处于该角色的控制器是同等的地位。可以有多个控制器处于该角色。

  • Mater:处于该角色的控制器只能有一个(由交换机保证),该角色的控制器也具有读写交换机状态的权限。
  • Slave:处于该角色的控制器可以有多个,该角色的控制器只有读权限。

控制器的角色都是由控制器触发的,交换机无权干涉。控制器通过OFPT_ROLE_REQUEST消息告知交换机当前控制器的角色,交换机无条件接受。唯一比较特殊的是:如果控制器设置为Mater,但是当前有一台为Master,那么之前那台主将被交换机切换为备,并且发送一个角色切换的消息给之前的主(一般情况下,是那台主掉线了,另外一台才升主的,所以这种情况下是无法通知到的)。为了防止主备切换过程中的乱序(比如连续切换两次,由于是多条连接,可能存在最后的那个主发的消息提前到达的情况,这个时候就会设置错误),在OFPT_ROLE_REQUEST消息中会带上一个generation_id,表明消息的顺序。generation_id是一个单调递增的整数,在每次主设备变化的时候改变。交换机收到该消息的处理算法如下:

  1. //On switch startup:
  2. int64_t generation_is_defined = false;
  3. //On receiving OFPT_ROLE_REQUEST with role equal to OFPCR_ROLE_MASTER or OFPCR_ROLE_SLAVE and with a given generation_id, say GEN_ID_X:
  4. if (generation_is_defined &&
  5. distance(GEN_ID_X, cached_generation_id) < 0) {
  6. //<discard OFPT_ROLE_REQUEST message>;
  7. //<send an error message with code OFPRRFC_STALE>;
  8. } else {
  9. cached_generation_id = GEN_ID_X;
  10. generation_is_defined = true;
  11. //<process the message normally>;
  12. }
  13. //where distance() is the Wrapping Sequence Number Distance operator defined as following:
  14. distance(a, b) := (int64_t)(a - b)
  15. //I.e. distance() is the unsigned difference between the sequence numbers, interpreted as a two’s complement signed value. This results in a positive distance if a is greater than b (in a circular sense) but less than “half the sequence number space” away from it. It results in a negative distance otherwise.(a < b).

次连接

次连接依赖于主连接,只有主连接存在,次连接才存在。也就是次连接在主连接之后建立,次连接在主连接断开时候端开。对于次连接有如下限制:

  • 相同的源IP
  • 相同的目的IP
  • 相同的传输层目的端口。

对于某种类型的连接处理什么消息没有特别的约束,每一条连接都可以处理所有消息,但是一个连接收到的请求必须在这条连接上面回复。下面的处理方式是一种较优的建议:

  • 对于控制器:
    • Packet-Out的所有消息都在主连接上面发送。
    • 连接维护消息(hello/echo request/features request)所有的连接上面发送。
    • Packet-In对应的消息在其收到的连接上面发送。
    • 对于非Packet-In对应的Packet-Out消息分散到各个次连接上面,但是需要保证同一条流映射到同一条连接。
    • 以上如果对应的次连接不可用,则统一使用主连接。
  • 对于交换机:
    • Packet-In通过次连接发送,但是需要保证同一条流在同一条连接上面发送
    • Packet-In之外的所有消息在主连接上面发送。

次连接使用不可靠的传输层协议的时候(例如UDP),不支持所有类型的消息。支持的消息类型为OFPT_HELLO, OFPT_ERROR,OFPT_ECHO_REQUEST, OFPT_ECHO_REPLY, OFPT_FEATURES_REQUEST, OFPT_FEATURES_REPLY,OFPT_PACKET_IN, OFPT_PACKET_OUT and OFPT_EXPERIMENTER

流表管理

流表消息类型

流表的消息一共有5种类型,如下所示:

  1. enum ofp_flow_mod_command {
  2. OFPFC_ADD = 0, /* New flow. */
  3. OFPFC_MODIFY = 1, /* Modify all matching flows. */
  4. OFPFC_MODIFY_STRICT = 2, /* Modify entry strictly matching wildcards and priority. */
  5. OFPFC_DELETE = 3, /* Delete all matching flows. */
  6. OFPFC_DELETE_STRICT = 4, /* Delete entry strictly matching wildcards and priority. */
  7. };
  • OFPFC_ADD:添加流表项,如果该流表项已经存在,那么旧的流表项将被删除,新的流表项添加进去。
    • 设置OFPFF_CHECK_OVERLAflag:该添加需要检查是否存在overlap的情况,即是否存在一条表项和当前的表项可以同时被命中;如果存在,那么该表项不能被插入,交换机返回一个overlap错误消息。
  • OFPFC_MODIFY/OFPFC_MODIFY_STRICT:修改流表项,幂等操作。strict?
    • 存在该流表项,修改之。
    • 不存在该流表项,无变化,不返回错误。
  • OFPFC_DELETE/OFPFC_DELETE_STRICT:删除流表项,幂等操作。
    • 存在该流表项,删除。
    • 不存在该流表项,无变化,不返回错误。

流表的删除有以下三种方式:

  • 控制器下发的删除指令OFPFC_DELETE
  • 老化时间到期后被交换机删除。
  • 交换机主动回收资源,例如表项满的时候回收不重要的表项。

    流表同步机制

    流表的同步机制即交换机上面的流表自同步,被同步的流表的表项的增删改将映射到同步的流表。可以分为两类:单向同步,双向同步。这种机制使得交换机可以根据需要执行多个匹配,同时对应到同一个操作。OpenFlow标准里面没有对这种机制作出规定,里面举了个mac地址的学习转发的例子。一个表(A表)用于学习查找,另一个表(B表)用于根据目的mac转发查找。

  • A表解析报文的源MAC地址,查找表项,没有的话通知控制器学习。同时设置表项的老化时间。

  • B表解析报文目的MAC地址,查找表项转发报文。A表新增删除表项的时候,B表也同步操作。

组表管理

  1. enum ofp_group_mod_command {
  2. OFPGC_ADD = 0, /* New group. */
  3. OFPGC_MODIFY = 1, /* Modify all matching groups. */
  4. OFPGC_DELETE = 2, /* Delete all matching groups. */
  5. OFPGC_INSERT_BUCKET = 3,/* Insert action buckets to the already available list of action buckets in a matching group */
  6. /* OFPGC_??? = 4, */ /* Reserved for future use. */
  7. OFPGC_REMOVE_BUCKET = 5,/* Remove all action buckets or any specific action bucket from matching group */
  8. };
  • OFPGC_ADD:添加一个新的组,与流表不同的是,如果当前存在该组表,那么将返回错误
  • OFPGC_MODIFY:修改一个组,与流表不同的是,当前如果不存在该组表,那么将返回错误
  • OFPGC_DELETE:删除一个组,是一个幂等操作,如果当前不存在则不删除。
  • OFPGC_INSERT_BUCKET:插入一个action bucket到指定的group中。插入位置由command_bucket_id指定。有以下几种类型:
    • OFPG_BUCKET_FIRST:插入到首部。
    • OFPG_BUCKET_LAST:插入到尾部。
    • 指定的bucket id:插入到bucket id之后。
  • OFPGC_REMOVE_BUCKET:在指定的group中删除一个action bucket,删除的位置与插入类型,由command_bucket_id指定。有以下几种类型:
    • OFPG_BUCKET_FIRST:删除最后一个。
    • OFPG_BUCKET_LAST:删除第一个。
    • OFPG_BUCKET_ALL:删除所有。
    • 指定的bucket id:删除指定位置的bucket

meter表管理

  1. /* Meter commands */
  2. enum ofp_meter_mod_command {
  3. OFPMC_ADD = 0, /* New meter. */
  4. OFPMC_MODIFY = 1, /* Modify specified meter. */
  5. OFPMC_DELETE = 2, /* Delete specified meter. */
  6. };
  • OFPMC_ADD:与组表类似,如果已经存在则返回错误。
  • OFPMC_MODIFY:与组表类型,如果不存在则返回错误。
  • OFPMC_DELETE:与组表类似,属于幂等操作。

各个表之间对比

表类型/消息类型 ADD MODIFY DELETE
Flow 幂等 幂等 幂等
Group 非幂等 非幂等 幂等
Meter 非幂等 非幂等 幂等
  • 为什么Flow表和Group/Meter表设计不一致?
    • Group/Meter表由唯一的id标识,而Flow表则没有。
    • Flow表可以由交换机主动删除/新增。因此对于增删改设计成幂等操作,而Group/Meter则完全有控制器管理,和控制器视角不一致时应该告知控制器。连接多台控制器,需要告知控制器?
  • 为什么在Group/Meter表中ADD/MODIFY不是幂等,而DELETE是幂等。
    • ADD/MODIFY需要通知控制器,不然后续交换机和控制器的数据就不一致了。
      • ADD:如果不告知控制器
      • MODIFY:由于数据可能不一致。

Bundle消息

Bundle消息类似于一个事务,具有原子性。即将多个OpenFlow消息放在一起执行,同时成功或者同时失败。有以下两个用途:

  • 将关联的消息作为一个事务执行,防止由于某些消息执行失败出现中间状态。
  • 可以让整个网络里面的所有OpenFlow交换机同时更新状态。

交换机在处理Bundle消息的时候,每收到一个Bundle ADD消息都需要校验是否可以执行成功,如果不能执行成功,那么需要返回错误。虽然前面有校验,但是在执行Commit的时候的还是可能失败,比如执行的时候资源正好不可用,这个时候仍然需要返回错误给控制器。
对于控制器来说,整个Bundle消息必须是一个原子操作,也就是在还是执行commit的时候,控制器不能查询到交换机的中间状态。一种可能的实现是在收到Bundle open的时候,保存当前的一份状态副本,在当前副本上面做校验,之后Commit的时候再在原始环境上面执行。同时控制器可以指定Bundle的执行方式,有以下几种:

  • OFPBF_ORDERED:按照顺序执行。
  • OFPBF_ATOMIC:原子执行,也就是任何时刻的报文看到的状态是整个Bundle执行前或者执行后的状态,不能是执行过程种的状态。

    Whether OFPBF_ATOMIC is supported would depend on the switch hardware and software architecture. Packets and messages can temporarily be enqueued while changes are applied. As the resulting increase in forwarding / processing latency may be unacceptable, double buffering techniques are often employed.


Bundle调度

image.png

  1. 控制器发送一个OFPBCT_OPEN_REQUEST消息到交换机,请求开始一个Bundle,消息中包含Bundle id。交换机回复一个OFPBCT_OPEN_REPLY
  2. 控制发送OFPT_BUNDLE_ADD_MESSAGE消息,一个个发送到交换机,根据Bundle id识别属于哪一个Bundle
  3. 控制器发送OFPBCT_CLOSE_REQUEST消息,表示后续不再有Bundle Add消息,交换机回复OFPBCT_CLOSE_REPLY
  4. 控制器发送OFPBCT_COMMIT_REQUEST消息,表示要提交执行,同时会带上一个OpenFlow原理 - 图8表示执行的时间。

控制器在发送OFPBCT_COMMIT_REQUEST消息给交换机之后,在交换机执行之前,控制器可以通过发送OFPBCT_DISCARD_REQUEST消息终止该Bundle的执行。
image.png
交换机执行Bundle有一个时间容忍度。如下图所示,时间容忍度包括参数sched_max_futuresched_max_past。默认为1S,可以由控制器配置。
image.png
时间容忍度对执行的影响如下算法:

  1. #define Tl lower_bound
  2. #define Tu upper_bound
  3. if (Ts > Tu) {
  4. //Execute the bundle as close as possiable to Ts.
  5. } else if (Ts < Tl) {
  6. //Abort the bundle,reply error message.
  7. } else {
  8. //Execute the bundle as soon as possiable.
  9. }