ODL碳版本模块开发及流程梳理
文章主要基于ODL碳版本,进行简单插件的构建、安装、部署,以一个插件开发为例,介绍ODL新版本开发过程中的一些具体问题。
一、碳版本简易开发流程
1.1 开发环境搭建
1.安装java1.8以上环境,安装maven。 2.配置maven settings.xml 。 首先在odl的git中访问odl-parent项目,进入项目可以看到settings.xml,把这个项目拷贝到自己maven的.m2文件夹下。(一定要注意自己拷贝的版本和要开发的版本必须要保持一致) 在使用maven-archetype-plugin:3.0.1插件创建项目时与之前版本略有不同,需要在setting.xml文件中添加odlarchtype标签。具体的配置信息如下。
Shell
1234567891011121314151617 |
<profile> <id>odlarchtype</id> <repositories> <repository> <id>archetype</id> <url>http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url> <releases> <enabled>true</enabled> <checksumPolicy>fail</checksumPolicy> </releases> <snapshots> <enabled>true</enabled> <checksumPolicy>warn</checksumPolicy> </snapshots> </repository> </repositories> </profile> |
---|
到此基本的开发环境配置完毕,由于odl的maven仓库在国外,可能需要自己在maven的settings.xml文件中自行配置代理。
1.2 项目框架建立
打开终端,输入指令:
Shell
1 |
mvn archetype:generate -DarchetypeGroupId=org.opendaylight.controller -DarchetypeArtifactId=opendaylight-startup-archetype -DarchetypeVersion=1.3.0-Carbon |
---|
注:1.3.0-Carbon表示项目的版本号
输入建立项目的基本信息,生成如下项目骨架: 我们需要关注的主要是api和impl两个文件夹,其中api中存放我们项目要对外提供的webapi,impl中是项目的具体实现。打开impl,可以看到里边已经生成了DelaycollectorProvider.java文件,该文件是整个项目的入口。 在代码的impl/src/main/resources文件夹下生成了impl-blueprint.xml文件,用于为项目提供依赖注入。 (具体内容可参考https://wiki.opendaylight.org/view/Using_Blueprint) 我们可以结合上边DelaycollectorProvider.java文件的代码大致的分析一下该文件的具体含义,其中标签后边的内容正好与上边的Provider代码相互对应,指明了函数的入口。其中init-methord对应初始化方法,也就是插件install之后会首先运行这个方法。而destory-methord方法是项目卸载时运行的方法,可以把一些资源的清理放在该方法中。 标签与下面的标签对应,为插件的构造方法提供参数注入。 在odl的开发过程中,以上两个文件尤为重要。 到目前为止,虽然我们一行代码都没写,但它已经是一个完整的插件了。在项目目录下运行如下命令对项目进行编译:
Shell
1 |
mvn clean install –DskipTests |
---|
进入/delaycollector/karaf/target/assembly/bin$目录下,运行./karaf,但是并没有发生什么,因为我们的项目现在只是一个空壳,没有编写任何代码。Init方法中只是在日志中打印了一句话。打开/delaycollector/karaf/target/assembly/data/log$文件夹下的log文件。
可以看到确实在日志中打印了字符串。如果觉得效果还不明显,那么我们可以在eclipse中对代码进行 远程调试 。
1.3 代码调试
首先将项目导入eclispe,然后重新启动控制器,运行:
Shell
1 |
./karaf debug |
---|
可以看到控制器已经处于debug模式下并且在监听5005端口。打开eclipse,配置eclipse远程调试:
点击debug就可以开启调试了。(如果调试显示无法连接,请尝试更换eclipse版本)由于插件在odl启动的过程中已经被安装了,我们可以先把它卸载,同时在close方法内打一个断点。在odl中运行feature:uninstall odl-delaycollector,可以看到eclipse弹出了进入调试窗口的提示。 代码确实停在了我们打断点的地方。点击上边的绿色调过按钮,插件被成功卸载。之后可以再次运行feature:install odl-delaycollector安装插件,同时观察init方法中的断点。
1.4 项目集成
现在我们已经可以运行自己的项目了,那么我们要怎样把我们的插件集成到发行版控制器中呢? 打开/delaycollector/karaf/target/assembly/system$目录,进入org.bupt目录,可以看到我们的插件所生成的jar包。可以直接把该目录拷贝到对应版本的odl发行版的对应目录下。
然后启动发行版odl控制器。运行feature repo-add: mvn:org.bupt.delaycollector/delaycollector-features/0.1.0-SNAPSHOT/xml/features(这条指令的后半部分可以在我们的插件的delaycollector/karaf/target/assembly/etc$目录下找到)。这条指令的意思就是告诉odl我要把自己的插件添加进odl,karaf会读取到插件的信息。然后安装插件feature:install odl-delaycollector。 进行到这一步,我们已经完成了一个最简单插件的构建,安装,部署,接下来会以之前写过的一个插件为例,介绍odl新版本开发过程中的一些具体问题。
二、模块插件功能开发
SDN集中控制的思想使得控制器可以获取全网的链路信息,交换机的传输时延就是其中之一。该插件的目标之一就是测量网路的链路时延。传统的sdn网络时延测量方法主要是采用的“三角”测量法,该方法实现较为简单,但是缺点就是测量的准确性一般。今天介绍另一种方法,改方法需要修改一部分ovs交换机的代码。(这部分代码是学长做的,我不太了解具体内幕)总而言之就是让交换机在某种特定协议的包上打上时间戳,当一个数据包从交换机出发,经过两个ovs交换机之后,它的身上就携带了两个时间戳,只要我们在控制器中把时间戳取出并相减即可得到这条链路的时延大小。这种方法可以直接得出链路时延,无需像三角法一样减掉两边,因此准确度可以得到大大提高(大概在微妙级)。
2.1 插件配置
在插件开发过程中我们常常添加一些用户配置,比如本插件中我们想控制发包器的发包速率。那么我们如何定义这些配置文件呢。 在carbon版本中,插件的配置通过yang文件来定义。在impl文件下新建yang文件夹,之后新建delaycollector-config.yang文件。在文件中声明我们所需的参数。 其中is-active为boolean类型,用于控制发包器的开关。querry-delay为uint8,用于控制发包的频率,这里设置默认值为1,每秒发送一次。之后再次编译impl插件。编译成功后在delaycollector/impl/target/generated-sources/mdsal-binding/org/opendaylight/yang/gen/v1/urn/opendaylight/packet/delaycollector/config/rev140528目录下可以看到yang-tools生成的config类。
2.2 模块开发
介绍完大体思路后我们就可以进行模块的开发,这个插件中控制器其实主要就做了两部分。 1.发送特定协议的数据包 2.接收指定协议数据包并解析数据包内的时间戳。 整理好思路之后我们就可以写代码了。首先写发包模块,既然要发包,那么我们肯定要用到ODL提供给我们的发包服务,那么如何在我们的项目中引入这个服务呢?上篇文章中我们提到了关键的blueprint.xml文件用于依赖注入,引入服务的话也要在这个文件中进行声明。 关键代码按如图所示:
其中我们之前定义的配置文件也要在blueprint文件中进行注入。
这里具体的服务名称建议大家去ODL中的官方插件的xml文件中去找。(ODL初学者建议先去阅读ODL l2-switch项目源码,因为这个插件涉及的协议较为简单,基本都是二层和arp协议,其中的代码相对容易理解) 其中packetprocessingservice类就是我们要用的发包服务,它提供了一系列发送数据包的方法。
DelaycollectorConfig类是我们之前定义的配置类,其中包含我们所需的配置参数。 首先发送数据包需要一直运行,因此肯定是一个多线程任务,继承Runnable接口,之后再run函数中写我们的具体执行逻辑。 发包先要生成一个包,那么如何生成一个可被发包服务发送的数据包呢? 我这里用到了ipv4数据包,具体代码在ipv4.java中,该类需要继承org.opendaylight.controller.liblldp.Packet基类。(这个类如果大家看过ODL链路发现插件的代码应该会熟悉,在构造lldp数据包时,就用到了相关的方法。具体代码大家可以自行阅读体会,总之就是它给我们提供了一个大致的模板,只要我们在自己想构造的数据包中添加好相应的字段,基类提供的方法将会自动帮我们完成数据包的序列化) 有了iPv4.java,我们就可以用它来构建一个ip数据包了。在这个插件中,我们用来打标签的数据包是协议号为253的实验用数据包,这样可以尽量避免对其他网络协议的影响。
New一个对象然后一路set,三层包就造好了。当然到这还未结束,要正常发送数据包我们还需要一个二层包头,这里ODL给我们提供了现成的类,org.opendaylight.controller.liblldp.Ethernet,直接调用即可。这块代码就不具体介绍了,比较好理解,总之也是写好包头信息即可。
之后会用到两个ODL-l2-switch中arphandler中的两个类。PacketDispatcher,InventoryReader。其中PacketDispathcer用于处理数据包,提供了例如广播,单播数据包等操作,InventoryReader用于获取网络的拓扑信息,例如获取所有交换机,获取某个交换机的所有端口等等,这两个类的源码也相对简单,强烈建议大家去阅读相关代码。 目前为止我们已经构造好了相应数据包并且有了发包的方法,之后就可以以一定的频率把这种数据包在交换机的所有端口flood出去。
发包器的工作基本就是这些了。 有了发包器我们还需要一个收包器接收发送的数据包。在ODL中如果我们想接收特定类型的数据包只需要使用相应的Listener接口。以下是ODL中提供的各种Listener,我们只需在插件中implements相关接口并使用NotificationProviderService对其进行注册即可,这样当符合条件的包进入控制器中就会触发我们的回调函数。 其中的关键代码在onIpv4PacketReceived方法中,首先对收到的packet进行简单判断,包括包的类型和包的协议号,如果不符合条件,方法直接返回。之后从数据包的ipv4Options中读出两个时间戳计算时延数据和包的来源即可。用一个Map对其进行缓存。
2.3 RPC的定义与实现
时延数据我们已经得到了,那么我们怎样从控制器中把它取出来呢?答案是通过rpc(远程服务调用)。之前我们提到过在ODL开发中有两个文件夹特别重要,一个是impl,一个是api,我们的rpc定义就是放在api文件夹中。进入delaycollector/api/src/main/yang文件夹,可以看到里边已经有一个项目自动生成的yang文件,但是其中并没有定义实际内容,我们直接在这个文件中添加我们的rpc定义。
这里我们定义了两个rpc,其中一个用于返回特定节点的时延,另一个返回所有节点的时延。之后再次编译api项目,在target的对应目录下将生成相应的java文件。 要实现rpc功能,需要在我们的实现类中implements DelaycollectorService接口。
这部分代码也很简单,从input中获取输如数据,通过outputBuilder构造输出。
2.4 项目整合
插件的各个模块我们已经创建完毕,之后要做的就是把各个模块有序的运行起来。 回到DelayCollertor.Java文件,在init方法中进行插件的初始化工作。
其中需要注意的是对rpc服务和ipv4包监听器进行注册。
2.5 项目验证
对整个插件进行最后一次编译,并把它集成到发行版ODL中,启动ODL,安装插件。进入YangUI,可以看到插件已经有了相关的接口。 打开PostMan软件,输入相应链接,getGlobalDelay接口不需要输入参数,直接Post,即可得到返回参数。
再测试另一个接口,输入参数,直接post。 更改插件配置