OpenFlow协议匹配结构进化与OXM TLV解读

在OpenFlow流表定义中,报文匹配表项是个重要的行为,我们下发的每一个流表表项都可以包含一到多个匹配项,报文进来时会与这些匹配项比较,如果匹配成功的话,表项中动作也相应的被附加到报文上。典型的匹配项有入端口、源MAC地址、目的MAC地址、VLAN Id、源 IP 地址、目的 IP 地址、MPLS 标签等等。不难想象,网络中的报文种类繁杂,想要能够匹配每一种报文,光匹配项就能列一个长长的列表出来,并且随着各种网络通信协议的不断演进以及越来越复杂的网络业务,这些匹配项将来还会可能还会增加。所以在 OpenFlow 协议中,选择一种合适的数据结构来描述这些匹配项就显得重要起来。

早期的匹配结构

在 OpenFlow 协议早期的版本中,使用一种固定的数据结构来表述所有的匹配项,这个数据结构长度固定并且所有的匹配项都包含在里面:

这个是 OpenFlow v1.1中的匹配结构体的定义,其中 type 字段的取值只有一个就是 OFPMT_STANDARDlength 代表整个匹配结构体的长度,它的值可想而知也是固定的,就是整个结构体的长度 88 字节。wildcards 字段是一个位标志符,在一次流表下发中,ofp_match 中的匹配字段并不都会被用到,协议规定哪些匹配字段被用到,其 wildcards 中的对应位就被清 0,否则就置 1。其余的字段就是各个匹配项了,其含义想必一目了然,不需多做解释。

通过以上的定义不难看出,早期的 OpenFlow 协议对于匹配项处理的不是太好,一个是匹配结构体固定,所有的匹配项都包含在一起,下流表时即时不需要这个匹配项,也要一并下发下来,加大了网络开销;另外最重要的是这个定义毫无扩展性,想要增加新的匹配项就等于再更新一版新的 OpenFlow 协议。

在后续的 OpenFlow 协议中,采用了另一种新的定义解决了这些问题。

新的匹配结构

从 OpenFlow 1.2 开始,一种新的匹配结构被定义出来,这种结构被称作 OpenFlow Extensible Match,简称 OXM,它采用 Type-length-value 结构,所以也被称作 OXM TLV。

这个结构体定义以及注释都是取自 OpenFlow 1.4 的源码,从其注释中可以看到 OFPMT_STANDARD 类型的匹配项已经废弃不用了,所以 ofp_match 结构体的 type 字段今后的取值将总是 OFPMT_OXMoxm_fields 字段表示的是一组 OXM TLV 的集合,可能是 0 个,也可能多个,从这可以看出整个 ofp_match 结构是一个变长的结构,在控制器下发消息时,只需要包含需要的匹配项,不需要的匹配项无需包含在消息体中,省去了不必要的开销。

那么 OXM TLV 的格式到底是如何的呢?

OXM TLV

每一个 OXM TLV 都一定包含一个 4 字节的头,对于 OpenFlow 标准所定义的匹配项,oxm_class 的取值固定为 0x8000oxm_field 表示具体的匹配项,比如源 MAC、VLAN ID 等。 oxm_length 表示此 OXM TLV 的值的长度,以字节为单位。M 字段则表示这个 OXM TLV 是否包含掩码,在 OXM TLV 中,掩码的长度和值的长度是一样的,掩码中的某位为 1 表示报文中匹配项对应位必须和值的对应位相同才能匹配,掩码中的某位为 0 则表示对报文中匹配项对应位的值不做限制。如果包含了掩码,那么报文的匹配将会变成先和做掩码按位与操作,结果再和 OXM TLV 的值进行比较。如果下发的消息里没有包含掩码,那就需要报文与 OXM TLV 的值完全匹配才行。

OpenFlow 1.4 中定义的标准匹配项有如下这些:

可以看出相比 OpenFlow 1.1,这里的匹配项多了很多,新的匹配结构也提供了方便的扩展匹配项的机制。前面说了对于 OpenFlow 定义的标准的匹配项,其 oxm_class 字段的值固定为 0x8000,如果是其它厂商或组织定义的匹配项,则可以使用 0xFFFF 这个值。OpenFlow 协议还规定了 oxm_class 取值在 [0x8000, 0xFFFF) 范围内的都留给 OpenFlow 标准,以备将来协议更新之用; 而 [0x0000, 0x7FFF] 范围内的值则留给 ONF 组织。

OXM TLV 中 payload 的长度

对于某个 OXM 类别下的某个确定的 OXM TLV,显然其值的长度是一定的,如果这个 OXM TLV 不包含掩码,那么其值的长度就是 payload 的长度;如果包含掩码,那么 payload 的长度就是值长度的两倍。

关于值的长度,有一点需要注意的是,虽然很多 OXM TLV 的值的长度都按 bit 计算的,比如 IP 报文的 DSCP 字段其实是 6 bits字段,Vlan Id是个12 bits字段,但是oxm_length 段的单位是字节,就是说即时OXM TLV值用不了一个字节,也会占用一字节的空间。

这里还有一个细微的问题,协议 Spec 中没有明确说明的,就是如果某个 OXM TLV 包含掩码,并且其值的长度小于4 bits,那么这个OXM TLV的payload最终占用的空间是1字节还是 2 字节呢?这个问题微妙的地方在于值的长度小于4 bits,通过上面所说的我们知道如果没有掩码payload肯定也是占用 1 字节,但如果有掩码呢? 在值和掩码加起来还是不超过1字节的情况下,协议会为这种情况做一点空间优化,让值和掩码 “挤” 进1个字节里吗?

答案是不会,这种情况下payload还是会占用2字节的空间,这个问题OpenFlow的文档里没有明确的回答,答案我也是从源码里找到的。在OpenFlow中OXM TLV的定义是用OXM_HEADER以及OXM_HEADER_W这两个宏来定义的,前者定义不包含掩码的OXM TLV, 后者则定义包含掩码的OXM TLV,而这两个宏其实又都引用了OXM_HEADER__这个宏。可以看到,定义中并没有对值小于4 bits的OXM TLV做什么特殊处理, 就算值只有1 bit,定义包含掩码时也要对长度乘以2变成2字节。

扩展OXM TLV

我们可以通过Experimenter特性来扩展OXM TLV,前面已经说了当oxm_class字段取值0xFFFF时,就代表这个OXM TLV是扩展字段。另外对于扩展 OXM TLV 最重要的一点就是,紧跟在4字节头后面的一定得是一个32 bit的 Experimenter ID,而不是OXM TLV的值。Experimenter ID可以用来唯一标志厂商或组织,可以向 ONF 申请分配,也可以是厂商自己已有的IEEE分配的 OUI 号码。

Experimenter ID 之后的内容 OpenFlow 协议就不关心了,完全由厂商自己来解释。

参考

  1. OpenFlow Spec v1.4.0

作者简介:李晓东 (Cifer), 盛科网络软件组研发工程师,博客: http://cifer.me


  • 本站原创文章仅代表作者观点,不代表SDNLAB立场。所有原创内容版权均属SDNLAB,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用,转载须注明来自 SDNLAB并附上本文链接。
  • 本文链接http://www.sdnlab.com/18119.html
分享到:
相关文章
2条评论

登录后才可以评论

  1. comment reply yuyif99 2016/11/24 22:29
    开发者引入新的匹配字段怎么更改OXM Header?
        1楼
  2. comment reply Cifer 2016/11/25 13:41
    @yuyif99 确定你有一个 experimenter id, 以及定义好你自己的 oxm 字段的编号, 值的长度以及是否包含掩码。 然后 oxm header 中的四个字段对号入座就可以了, oxm_class 设置为 0xffff, oxm_fields 设置为你 oxm 字段的编号 (你可以看到你的编号不能大于 127), 掩码,长度也同理。 最后要注意在 oxm header 后面紧跟的 4 个字节填上你的 experimenter id, 用网络序
        2楼
Cifer 发表于16-11-24