Open vSwitch系列之openflow版本兼容

众所周知Open vSwitch支持的openflow版本从1.0到1.5版本(当前Open vSwitch版本是2.3.2)通过阅读代码,处理openflow协议的入口函数是openflow_handle__(一看命名就知道这个是老外写的,因为老外比较喜欢用handle这个单词)。当我看到这个函数后,和我想象中处理不太一样,我个人想法应该会有各种版本号判断,然而实际上却没有而只有switch-case,那么Open vSwitch是如何做到不同协议版本的兼容呢?

为了弄清楚这个问题,我大概花了三四天时间,终于揭开了版本兼容面纱—raw这个结构。因此今天来分析一下raw这个结构体。

在介绍之前,说明一下Open vSwitch代码风格,函数名字凡是以两个下划线结尾(__),都是静态函数,并且是真正逻辑处理函数。

我们开始步入正题吧,还是以往的形式,所有解释说明都在代码注释中,除非特别需要强调的才会单独摘出来进行补充说明。

在进行函数分析之前,我觉得理解枚举定义是重点,只有充分理解这个枚举,才能理解下面解析流程。因此在这里我强烈建议读者:阅读一下代码中注释。下面对于枚举解释只是我个人理解,不保证是正确的。由于这个枚举定义很长,为了节省篇幅,这里只摘取典型类型。

由于openflow版本较多并且有些版本差异化比较大(我经常说openflow还很年轻!!),OpenvSwitch为了支持各个版本的差异化,的确花费了很多心思。所以OpenvSwitch定义了一系列的枚举,枚举格式是以OFPRAW_开始。在介绍各个枚举之前,我们先说一下注释内容,因为RAW注释对于我们理解代码非常有帮助。
我们在阅读代码的时候,会发现每个枚举类型的上方有类似的注释

根据注释内容我知道,这些注释格式大体是这样的:type versions (number): arguments
就那上面例子来说吧,就会出现下面的表格:

那么我们来看一下type,version,arguments分别代表什么意思?这部分主要是翻译源代码中注释,网友可以自行查阅。

Type:有下面几种OFPT(标准openflow协议消息),OFPST(标准openflow统计消息),NXT(Nicira扩展消息),NXST(Nicira扩展统计消息)

Version:对应openflow协议版本号,如果是则表示消息在所有版本都是一样的,例如hello消息。如果“1.1+”表示从openflow的1.1版本(含)之后消息是相同的。

Number:理解不是很深入,只能通过代码注释得知是类型值。然而当我自己去匹配的时候,没有匹配成功。这个字段需要在再仔细分析一下。

Arguments:表示消息体具体类型。如果是void表示无消息体,如果uint8[]表示消息体是变长的。Argument存在多个时候,表示消息体可能里面类型它们中之一,这就要依据openflow版本号啦。 例如: /* OFPT 1.1-1.3 (12): struct ofp_port_status, struct ofp11_port. */表示消息体既可以是ofp_port_status,又可以是ofp11_port.

通过上面分析,可以得出下面两种枚举定义格式:
1)标准协议
OFPRAW_OFPT_ (OFPRAW_OFPT10_, OFPRAW_OFPT11_等)
OFPRAW_OFPST_ (OFPRAW_OFPST10_, OFPRAW_OFPST11_等)

2)Nicira扩展协议
OFPRAW_NXT_
OFPRAW_NXST_

通过上面类型的抽象,完成对openflow各个版本兼容,这个抽象过程非常重要,只有充分理解这个抽象过程,才能更好的理解处理流程。

上面这个两个函数都很重要,下面我会对它们进行详细说明的。我们现在调整一下介绍顺序,这样能够方便理解:

ofpraw_pull函数中会调用右侧三个函数,所我们先来介绍这三个函数,这三个函数搞清楚了ofpraw_pull函数也就清楚了。

在介绍之前,我抓取两个报文,方便解释代码:

图1:feature_reply消息

图2:multipart_request消息

上面这个函数逻辑相对简单,我们主要看一下raw_instance_map组成结构,ofpmsgs_init这个函数是用于初始化raw_instance_map的。通过查看这个函数源代码又可知,这个hashmap的输入是这个结构raw_infos(ofp-msg.inc文件)。我们看一下这个定义,这是一个结构体数组:static struct raw_info raw_infos[] = {...}。我们分析一下这个结构体定义:

我们再来看一下ofpraw_ofpt11_flow_mod_instances的定义:

其中红色字体就是函数ofpraw_from_ofphdrs最终返回的raw类型,数组大小是6-2+1=5。
下面这个两个函数就是根据返回的raw,获取对应实例raw_instance,在定义的时候成员变量hdrs_len,定义成0。当在初始化hashmap的时候,会对这个成员进行初始化,可以参考函数ofpmsgs_init。

有了这个上面分析基础,我们再回过头来看一下这个最外部函数ofpraw_pull。

通过上面这一系列的分析,我们梳理清楚raw是怎么操作的,下面我们返回到这个最开始的函数:

我们现在看一下函数ofptype_from_ofpraw,这个函数也非常简单,我们跟踪代码可以得知,返回来的类型,其实就是文件ofp-msg.inc中定义的数组结构体struct raw_info raw_infos,里面某个成员(raw是数组下标)。

这样我们就比较清楚的梳理出,openvswitch是如何进行各个版本兼容的。我们总结一下:
1、OpenvSwitch版本兼容核心技巧,在于这个数组定义,raw_info raw_infos,其中min_version,max_version是关键,通过这个两个变量做到了版本兼容。

2、虽然版本能做到兼容,但是各个版本还有差异,那么Open vSwitch是如何做到呢?是通过raw_instance数组定义,也是定义在文件Ofp-msgs.inc中。

只有充分理解上面这个两个数组,我们就能清楚知道Open vSwitch是何如做到版本兼容,当我们基于Open vSwitch进行二次开发的时候,就能够知道在哪些地方增加对应的消息啦。

作者简介:
徐小冰:毕业于河北大学,主要从事嵌入式软件开发,虚拟化,SDN。目前基于ODL和Open vSwitch进行二次开发,希望与广大网友一起探讨学习。作者系OpenDaylihgt群(194240432)资深活跃用户,@IT难人。


  • 本站原创文章仅代表作者观点,不代表SDNLAB立场。所有原创内容版权均属SDNLAB,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用,转载须注明来自 SDNLAB并附上本文链接。 本站中所有编译类文章仅用于学习和交流目的,编译工作遵照 CC 协议,如果有侵犯到您权益的地方,请及时联系我们。
  • 本文链接https://www.sdnlab.com/15790.html
分享到:
相关文章
条评论

登录后才可以评论

xxb249 发表于16-02-15
2