阅读任何一个协议都要注意的一点是这个协议中所定义的专有术语,对这些术语的理解不到位的话也会造成对协议的理解偏差。本文想和大家分享几个可能容易混淆的术语。
在OpenFlow协议文档中经常会看到这么几个词语:Instruction,Action,Apply-actions,Action Set,Action List,Clear-actions,… 有点迷惑人,实际上这里面只有两个实体的概念:Instruction 和 Action。为了保持后文的易读性,这两个概念分别用中文”指令”和”动作”来描述,下文中的”指令”和”动作”都特指在OpenFlow协议中的含义。
指令这个词,特指流表表项中的指令,当某个报文匹配了这个表项之后,表项中的指令就会被应用于这个报文;而动作是比指令更细粒度的概念,但它并不是局限于流表表项的概念,动作可以独立于指令而存在,也可以被包含在指令中,具体说来,我们在下流表的时候,可以为某个表项的某种指令指定一些列的动作,但是动作并不是只有下流表的时候才会被用到。
本文以目前较新的 OpenFlow 1.4 版本为准,分别看一下指令和动作的含义。
指令
每一个流表的表项都包含一系列的指令,当报文匹配上了这个表项后,这些指令就会被执行,这些指令的执行结果有几种:改变报文,改变action set,改变pipeline。这些指令可以按照其执行结果的不同而分类,不同的流表的表项包含的指令种类也不同,前面说了指令可以包含动作,但也并非所有种类的指令都包含动作,下面我们一起来看一下指令的分类。
指令的分类
OpenFlow1.4中规定了6种类型的指令,但并不要求交换机支持所有的类型。另外要注意的是,在OpenFlow协议文档中指令的类型名字几乎全都以”actions”后缀结尾,我觉得这是非常容易令人混淆的地方,我们一定要记住指令类型名中的”actions”字样和我们上面说的”动作”的概念完全没有关系。然而OpenFlow协议文档的这种写法看起来似乎每种指令都包含了一组动作,而实际上只有几种指令是真正包含动作的,下面我们来看一下这6种指令与动作的关系。
为了避免我们更加混淆,6种指令类型的名字我还是保持和OpenFlow1.4的Spec一样。还有一点需要注意的是,括号里的 “可选”,”必选”字样指的是交换机是否必须支持这个指令,而不是说下流表时表项中是否必须包含这个指令。
☘ (可选指令)Meter meter_id,不包含动作,行为是将报文送往指定的meter
☘ (可选指令)Apply-actions action(s),这个指令是真正包含动作的指令,它的行为是立即对报文应用这些指令,不要改变报文的action set
☘ (可选指令)Clear-actions,这个指令并不包含任何的动作,它的行为是立即清除报文的action set中所有的动作
☘ (必选指令)Write-actions actions(s),这个指令真正的包含动作,它的行为是将自己包含的动作合并到报文的action set中
☘ (可选指令)Write-Metadata metadata / mask,这个也不包含动作,用的不多
☘ (必选指令)Goto-Table next-table-id,这个指令也不包含动作,它表示把报文交给后续的哪张流表处理。OpenFlow协议要求交换机必须支持这个action,但有一个例外是假设你的交换机本身就只支持一张流表,那可以不支持这个action。
动作
前面说了动作也有分类,但是相比指令的分类,动作的分类就比较好理解了,我们稍加带过,然后解释下Action Set和Action List两个概念。
同样,OpenFlow协议不要求交换机支持所有的动作种类,我们只看几个常见的:
☘ (可选) Output,表示将报文从某个特定的端口送出去
☘ (必选) Drop,丢弃报文
☘ (必选) Group,表示将报文交给指定的组
☘ (可选) Change-TTL,改变报文的TTL字段(可以是IPv4 TTL,MPLS TTL或者Ipv6 Hop Limit)
关于 Action Set
Action set是一个与报文相关联的概念,只要提起action set,它就一定是报文的action set,它包含了当报文离开流表时要附加于这个报文上的动作。我们前面看到了有一种Apply-actions指令,它是在报文匹配了表项的时候将它包含的动作立即应用到报文上,而Write-actions则是将它包含的动作合并到报文的action set中,另外还有Clear-actions指令,是将报文的action set清空。最终报文走完所有流表时,其action set里面有什么动作,就执行什么动作,这就是action set的作用了。
关于Action List
Action list实际上就是一系列动作的有序序列,一定要注意其有序性。在上面说到的流表中的Apply-actions指令中,以及OpenFlow协议中同样能够包含动作的Packet-out命令中,都要求所包含的动作被有序执行。所以就出来了这么个action list的概念,这是与action set的一点区别。另一个区别是action list并不是和报文相关联的概念,action list可以直接夹带在 controller发给agent的消息中,比如Packet-out消息;也可以存在于流表表项的指令中,比如Apply-actions指令。
协议源代码
说实话,光看协议Spec我是没有理清楚这些个指令与动作的关系的,真正完全理清楚是看了OpenFlow源码之后。在OpenFlow源码中,指令与动作的结构头分别如下:
Meter,Write-metadata,Goto-Table这三类指令的结构如下,它们的前两个字段和struct ofp_instruction_header是相同的,另外可以看出,它们都不包含struct ofp_action_header结构体,所以这三个指令是不包含动作的。
而Apply-actions,Clear-actions,Write-actions三种指令则共用如下的结构体,可以看到它是包含struct ofp_action_header的,你可能会奇怪Clear-actions指令不是也不包含动作吗,为什么也用了这个结构体,实际上对于Clear-actions指令来说,structofp_instruction_actions结构体的最后一个actions字段是大小为0的数组。
另外上面还说到了一个Packet-out消息也是包含动作的,它的定义如下,actions字段包含了一个动作列表,也就是action list。
参考
OpenFlow Spec v1.4.0(http://pan.baidu.com/s/1sl7wVA9)