本文主要是提供了有关ONOS的基于意图的流量转发应用如何开发、构建及部署等方面的实战经验,并且详细讲解了如何在命令行上调用服务的过程。最后,介绍了在开发ONOS应用过程中所遇到的常见疑难问题,并且给出了自己的看法。
1 应用程序开发手册
1.1 项目骨架安装
1.1.1 新建Maven工程
首先,打开Eclipse,导入相应的ONOS源码(详细导入过程可参考该文档),导入成功以后的代码结构如下图所示,每个bundle都是以独立的Maven工程形式存在,它们之间通过POM文件相关联:
图1. ONOS源码
然后,选择创建新的Maven工程,直接选择下一步Next,选择好相应的Archetype以后,直接选择下一步Next。在添加完相应的Group Id,Artifact Id,Version以及Package后,点击结束按钮,创建完成。如下所示:
图2. 新建Maven工程
1.1.2 编辑POM文件
1、Maven工程创建好以后,首先可以查看应用程序根目录下的pom.xml文件。该POM文件被Maven用来构建该应用程序。
图3. hello目录结构
如下所示:
图4. 应用的POM文件
这样的话,最终的bundle将会以”onos-app-hello“的名称存在。这将是在Karaf/ONOS命令行下使用类似”feature:install”的命令时指定的bundle名称。
2、接下来,编辑${ONOS_ROOT}/apps目录下的pom.xml文件,将hello添加进去,如下所示。注意,这里指定的不是bundle名称,而是应用程序的根目录。这样,就会将该应用作为它的子项目。
编辑如下所示:
图5.组件列表
1.1.3 注册应用程序
当一个新应用程序开发完以后,会把它放到Karaf下运行。而Karaf runtime需要一个应用程序的描述信息,称为一个feature,去部署该组件作为一个OSGi bundle。编辑${ONOS_ROOT}/features/features.xml文件,添加如下片段,这个片段描述了该应用程序的feature声明,该声明会告诉karaf到指定位置运行该应用程序。如下所示:
图6. 应用feature详情
至此,开发该应用之前的所有准备工作都做好了。
1.2 开发应用程序
1.2.1 应用综述
为简单起见,也本着为后面能开展更多实验的目的,这里选取的应用程序小示例以ONOS官方给出的ifwd作为参考。接下来的应用程序开发都将以此为基础。详情可参阅相关的代码和文档。
下面简单介绍一下基于意图的应用:
基于意图的转发应用与将收到数据包下发流表项的转发应用相比,它设置了一个意图。特别地,在本应用中,设置了一个主机到主机的意图,可以支持两个主机之间的互通。比起使用流表项来编程网络,使用意图的一个主要优势就在于意图能探测网络状态和重配置自身以便满足特定的意图。例如,如果某条链路down掉了,意图框架将会重路由你的意图到可用的路径。而当没有可选的路径时,此时意图将会进入失败状态,并且保持到链路重新恢复为止。关于意图的具体应用小案例,可以参见官方链接。
前面一个小节,我们创建好了一个项目骨架,现在就可以开始写我们的应用程序了。该转发应用程序的核心类是Hello.java。接下来就描述如何构建该Hello类。
1.2.2 添加注解
在编码之前,先简单介绍一下该应用使用到的Karaf的相关技术。Karaf组件加载机制会识别如下几种注解,并且允许java类通过此注解向它注册。主要包括如下几类:
- Component(immediate = true) – 声明一个类作为组件**,并且强制立即**
- Activate – 标记一个方法作为组件启动时调用
- Deactivate – 标记一个方法作为组件关闭时调用
Reference(Cardinality = ReferenceCardinality.MANDATORY_UNARY) – 标记一个服务作为一个应用程序的依赖,并且在该应用程序启动之前,需要这样服务的一个实例被提前加载。
如下所示:
要想了解更多的关于注解的信息,可以参考以下链接:
http://felix.apache.org/documentation/subprojects/apache-felix-maven-scr-plugin/scr-annotations.html。
1.2.3 注册服务
我们的应用程序在使用ONOS的各种服务之前,必须向CoreService注册获取一个唯一的application ID。然后,它会向PacketService注册去监听网络事件(packet-ins)和发送数据包(packet-outs)。通常,PacketService需要提供一个事件处理句柄,例如在这里实现了PacketProcessor接口的内部类ReactivePacketProcessor。
如下图所示:
1.2.4 添加处理代码
该事件处理句柄中的process( )方法在PacketService每次收到网包的时候被调用。这样的话,我们就可以在该方法中定义我们自己的数据包转发行为。
如下所示:
1.2.5 构建应用程序
因为本应用程序本身就是作为一个项目,它可以直接从项目的根目录下运行Maven命令,独立于其它的ONOS bundle单独构建。
图7. 构建应用程序
图8. 构建成功
如上图所示,此时应用程序已经构建成功了。此时,该应用程序就可以加载和使用了。
1.3 启动应用程序
启动应用程序主要有两种方式,一个是在启动时,还有就是在运行时。通过这两种方式均可以成功加载应用程序。分别介绍如下:
1.3.1 动态启动(运行时)
应用程序可以从ONOS 命令行或者Karaf Web控制台启动。在第一种情况下,只需要在命令行下键入以下命令即可:
图9. 安装应用程序
1.3.2 静态启动(启动时)
应用程序可以通过配置Karaf安装目录/etc文件夹下的org.apache.karaf.features.cfg文件进行加载。这个配置文件包含当启动时候,Karaf加载的features列表。我们可以简单的添加feature onos-app-hello到这个列表中。如下表所示:
图10. 添加onos-app-hello到features列表
加载成功以后,可以通过feature:list命令来查看加载后的结果,如下图所示:
图11. 查看加载后结果
2 命令行手册
2.1 综述
这个手册将会展示如何创建一个CLI命令并打印出由上一章节创建的hello应用所发现的终端节点。完成该手册后,可以理解如下两点:
- 如何扩展应用的新服务
- 如何扩展基于Karaf ONOS CLI的新命令
整个应用程序的目录结构如下所示:
图12. 应用程序的目录结构
2.2 提供服务
如果想要自己的组件能够提供服务给其它组件,就应该定义一个服务接口,并且让你的组件类实现它。
2.2.1 定义服务接口
这里定义了ForwardingMapService服务接口,只包含了获取终端信息的getEndPoints( )方法。如下所示:
2.2.2 导入服务接口
接下来,在Hello类中实现我们的服务。这里,我们使用Felix SCR 注解@Service向Karaf指示该应用程序导出了一个服务。
这样的话,我们就可以通过@Reference注解去引用这个服务了。如下图所示:
2.2.3 实现服务接口
最后,就是要实现这个服务了。这里,主要是在Hello类中添加了一个新的Map:endPoints,用于保存由process( )方法找到的终端节点的信息。如下所示:
而在getEndPoints( )方法中则是简单地返回了该Map。如下所示:
接下来,就可以通过一个CLI命令使用这个新的服务了。这个命令将会列出这个map中的内容,并且同时提供了选项接受一个参数( host ID)过滤源主机。
2.3 创建命令
CLI命令主要是定义在${ONOS_ROOT}/cli/目录下。主要是包括两种类型的命令,它们的源文件也放在不同的位置,如下所示:
- ${ONOS_ROOT}/cli/src/main/java/org/onosproject/cli – 系统配置和监控相关命令
- ${ONOS_ROOT}/cli/src/main/java/org/onosproject/cli/net –网络配置和监控相关命令
因为我们的命令将会展示网络相关信息,所以将会把我们的命令添加到第二个net目录下。
2.3.1 创建命令类
我们将会创建新命令的类骨架,暂且先命名为ForwardingMapCommand。我们的类是AbstractShellCommand的子类。并且会使用到一些命令相关的注解,如下所示:
- @Command – 用来设置一个命令的名称、范围以及描述信息
- @Argument – 用来指示由命令行参数设定的变量
具体代码结构如下所示:
以上注解支持该命令在CLI上以fwdmap或者onos:fwdmap形式调用。除此之外,它还可以接受一个host ID作为参数,例如:fwdmap 00:00:00:00:00:01/-1。
2.3.2 加入新服务
接下来,我们实现该命令。在我们的示例中,它是相当简单的 – 我们通过服务获取终端的map,并且当我们给定一个host ID时,我们可以在map中搜索到它。execute( )方法定义如下所示:
2.3.3 注册新命令
接下来,我们需要编辑shell-config.xml文件告诉Karaf关于我们的新命令,该文件位于${ONOS_ROOT}/cli/src/main/resources/OSGI-INF/blueprint/目录下。
我们在该文件的之间添加如下内容:
2.4 验证命令
一旦我们重构好了ONOS以后,就可以测试我们的命令了。
2.4.1 构建&重启
在以上我们创建好命令以后,现在就可以重新构建ONOS了。如下图所示:
图13. 编译成功
下面就可以重新启动Karaf了。如下所示:
图14. 启动ONOS
此时,从下图可以看到此时onos-app-hello应用程序已经被Karaf查找到,但还没有安装。
图15. onos-app-hello尚未安装
图16 活动列表中同样没有
进行如下的安装操作:
图17. 安装onos-app-hello
安装好以后,显示如下:
图18. 应用安装成功
此时,键入如下命令,可以看到该命令已经可以正常调用了:
图19. 创建命令可以调通
图20. 创建命令帮助文档
2.4.2 启动Mininet
启动一个带有四个主机的小型Mininet网络,并且将OVS交换机指向我们的ONOS实例。如下所示:
图21. 创建一个简单的网络拓扑
此时测试ovs-vsctl命令来查看OVS交换机到ONOS实例的连接情况,此时可以看到三个交换机都已经连接上了:
图22. 显示当前的交换机连接状况
并且此时也可以查看6633端口的连接情况:
图23. 查看6633端口连接状况
同时,启动的ONOS实例将会看到四个主机信息:
图24. ONOS实例展示的主机信息
最后的话,可以打开ONOS Web页面查看设备连接情况:
图25. ONOS Web界面展示
2.4.3 测试命令
没有网络流量时,该命令不会返回任何东西:
图26. 测试fwdmap命令
然后,在Mininet上产生流量:
图27. 产生网络流量
并且,此时重新尝试该命令。将会看到四个流表项:
图28. 产生四个流表项
如果我们指定了一个可选参数的话,也可以对源host ID进行过滤操作。
3 Q&A
3.1 Karaf clean VS Karaf?
在Karaf运行的过程中,它的data目录会记载所有的工作文件,保存所有之前安装的应用程序以及变化数据。当运行karaf命令启动Karaf实例的时候,它会加载之前保存的状态数据。而当通过karaf clean 启动Karaf的时候,则是从一个纯净状态启动,它会移除该目录,并且恢复到一个初始状态。
3.2 Karaf加载ONOS报错?
在刚开始部署hello应用的时候,一直无法正确的加载。经过排错以后,发现是因为自己的feature文件配置错了。下面红框圈出部分应该与${ONOS_ROOT}/system/org/onosproject目录下的文件夹保持一致。
1)错误的配置
图29. 错误的配置
2)纠正后的配置
图30. 纠正后的配置
3.3 Karaf只能启动单实例?
在部署应用过程中,发现当我想要重新打开一个新的Karaf实例的时候,控制台一直会报错。如下所示:
图31. 重新打开Karaf实例报错
通过该提示信息,表明4444端口已经被占用,如果需要开启新的实例,可以通过修改相应的配置文件切换到未使用的端口上。
3.4 Karaf加载ONOS流程?
在做实验的过程中,对Karaf如何加载ONOS的流程比较困惑。经过实验以后,发现Karaf加载ONOS相关组件主要是通过如下的配置文件:$KARAF_ROOT/etc/org.apache.karaf.features.cfg完成的。编辑该文件,并且将如下的片段添加到featuresRepositories中。
图32. Karaf默认加载路径
这里,有一点需要注意的是,图中方框圈出的部分不是固定不变的,要根据实际的ONOS目录进行相应的修改。这样的话,Karaf就回到自己的system目录下去查找相应组件了。
4 参考链接
https://wiki.onosproject.org/display/ONOS/Application+tutorial
https://wiki.onosproject.org/display/ONOS/CLI+and+Service+Tutorial
尊重劳动成果,以上转载自:http://www.sdnlab.com/10297.html