RYU源码解读

RyuApp

RyuApp类是RYU封装好的APP基类,用户只需要继承该类,就可以方便地开发应用。而注册对应的observer和handler都使用@derocator的形式,使得开发非常的简单高效,这也是Python的优点之一吧。RyuApp类的定义在ryu/base/app_manager.py文件中。该文件实现了两个类RyuApp和AppManager。前者用于定义APP基类,为应用开发提供基本的模板,后者用于Application的管理,加载应用,运行应用,消息路由等功能。

app_manager.py文件中import了instpect和itertools module,从而使得开发更方便简洁。inspect模块提供了一些有用的方法,用于类型检测,获取内容,检测是否可迭代等功能。itertools则是一个关于迭代器的模块,可以提供丰富的迭代器类型,在数据处理上尤其有用。

_CONTEXT

这是一个极其难理解的概念。博主的理解是,_CONTEXT内存储着name:class的key value pairs。为什么需要存储这个内容?实际上这个_CONTEXT携带的信息是所有本APP需要依赖的APP。需要在启动本应用之前去启动,以满足依赖的,比如一个simple_switch.py的应用,如果没有OFPHandler应用作为数据收发和解析的基础的话,是无法运行的。具体文档如下:

_EVENTS

用于记录本应用会产生的event。但是当且仅当定义该event的语句在其他模块时才会被使用到。但是目前我还没有遇见过在哪里使用,如果你知道其正确的用法,恳请告知,相互学习。

self.__init__

__init__函数中初始化了许多重要的成员变量,如self.event_handler用于记录向外提供的事件处理句柄,而self.observer则刚好相反,用于通知app_manager本应用监听何种类型的事件。self.event是事件队列。

self.start

start函数将启动coroutine去处理_event_loop,并将其加入threads字典中,为什么名字叫threads呢?我也不知道。也许我理解错了?

self._event_loop

_event_loop函数用于启动事件处理循环,通过调用self.get_handlers(ev, state)函数来找到事件对应的handler,然后处理事件。

event dispatch

应用中可以通过@set_ev_cls修饰符去监听某些事件。当产生event时,通过event去get observer,得到对应的观察者,然后再使用self.send_event函数去发送事件。在这里,实际上就是直接往self.event队列中put event。

其他函数如注册handler函数:register_handler,注册监听函数:register_observer等都是非常简单直白的代码,不再赘述。

AppManager

AppManager类是RYU应用的调度中心。用于管理应用的添加删除,消息路由等等功能。

首先从启动函数开始介绍,我们可以看到run_apps函数中的代码和前文提到的main函数语句基本一样。首先获取一个对象,然后加载对应的apps,然后获取contexts,context中其实包含的是本应用所需要的依赖应用。所以在调用instantiate_apps函数时,将app_lists内的application和contexts中的services都实例化,然后启动协程去运行这些服务。

load_apps

首先从创建一个apps_lists的生成器(个人理解应该是生成器而非迭代器)。在while循环中,每次pop一个应用进行处理,然后将其本身和其context中的内容添加到services中,再去调用get_dependent_services函数获取其依赖应用,最后将所有的依赖services添加到app_lists中,循环至最终app_lists内元素全都pop出去,完成application的加载。

create_contexts

context实例化函数将context中name:service class键值对的内容实例化成对应的对象,以便加入到services 列表中,从而得到加载。首先从列表中取出对应数据,然后判断是否时RyuApp的子类,是则实例化,否则直接赋值service class。load_app函数在读取的时候还会再次判断是否是RyuApp子类。

instantiate_apps

此函数调用了self._instantiate函数,在_instantiate函数中又调用了register_app()函数,此函数将app添加到SERVICE_BRICKS字典之中,然后继续调用了ryu.controller.handler 中的 register_instance函数,最终完成了应用的注册。此后继续调用self._update_bricks函数完成了服务链表的更新,最后启动了所有的应用。

_update_bricks

此函数完成了更新service_bricks的功能。首先从获取到service实例,然后再获取到service中的方法,若方法有callers属性,即使用了@set_ev_cls的装饰符,拥有了calls属性。(caller类中的ev_source和dispatcher成员变量描述了产生该event的source module, dispatcher描述了event需要在什么状态下才可以被分发。如:HANDSHAKE_DISPATCHER,CONFIG_DISPATCHER等。)最后调用register_observer函数注册了observer。

ryu.controller.handler.register_instance

以上的部分介绍了App的注册,observer的注册,handler的查找和使用,但是,始终没有提到handler在何处注册。实际上,handler的注册在register_instance部分完成了。为什么他的位置在handler文件,而不在app_manager文件呢?个人认为可能是为了给其他非Ryu APP的模块使用吧。

Conclusion

总体而言,RYU使用了协程,在很大程度上提高了单核性能。同时也使用了许多高效的语句和库,使得代码量非常精简易读。优势方面,RYU开发门槛低,性能好,稳定读强,并迎合OpenStack编写,适合用于数据中心等云场景。劣势方面,RYU还没有实现分布式版本,在大规模网络中只能使用多个单节点分担负载。实现细节上还存在细微的问题,如虽然提供了存储依赖关系的数据结构和获取依赖关系的函数,但是并没有指定一个默认的依赖关系。不过这一点其实并不算大问题,甚至不是问题,因为开发者可以手动去指定。

认真读完RYU底层的实现代码,觉得学习一门语言需要学习的内容太多,而只有真正去使用时,才会真正的学会和理解。严谨的逻辑,优雅的编码风格,清晰的模块划分能让程序的可读性更高,代码可复用性更强。如果从一个产品的角度讲,RYU算是一个不错的产品,小而美。没有ONOS,OpenDaylight那样庞大,但是作为一个纯SDN控制器而言,用户体验算是非常好的一个了。

写完这篇之后,估计这个学期就不会再写了,非科研狗非产品狗非bababala狗的渣硕要开始预习期末考试了。希望未来的我会更好。

References

  • itertools:python关于迭代器的库,参考https://docs.python.org/2/library/itertools.html
  • contextlib:参考https://docs.python.org/2/library/contextlib.html
  • yield:类似于return,但是返回的是一个生成器,参考https://docs.python.org/2/library/contextlib.html
  • decorator:参考https://wiki.python.org/moin/PythonDecorators
  • coolshell:Python修饰器的函数式编程,参考http://coolshell.cn/articles/11265.html
分页阅读: 1 2


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

登录后才可以评论

李呈 发表于14-12-29
18