RYU源码解读

编者按:RYU使用了协程,在很大程度上提高了单核性能。同时也使用了许多高效的语句和库,使得代码精简易读。本文以RYU真实运行流程作为主线,从main函数入手,详细讲述OFPHandler,Controller,RyuApp和AppManager等类的实现细节。

每接触一个控制器我都会习惯性的把控制器的源码读一读,走一走处理流程,RYU也不例外。本篇博文将从main函数入手,讲述RYU的ryuapp基类细节、app_manager类如何load apps,注册并运行application,Event的产生以及分发,还有最重要的应用ofp_handler。文章将以RYU真实运行流程作为主线,详细讲述RYU如何运作。如果文中出现理解错的地方,敬请指出,万分感谢!转载请声明原出处。

main()

RYU的main函数在ryu/cmd/manager.py文件中。main函数中CONF部分已经在在前一篇《RYU oslo学习总结》已经有所介绍,所以这次关注的重点的是后续部分,如app_manager如何工作。

首先从CONF文件中读取出app list。如果ryu-manager 命令任何参数,则默认应用为ofp_handler应用。紧接着实例化一个AppManager对象,调用load_apps函数将应用加载。调用create_contexts函数创建对应的contexts, 然后调用instantiate_apps函数将app_list和context中的app均实例化。启动wsgi架构,提供web应用。最后将所有的应用作为任务,作为coroutine的task去执行,joinall使得程序必须等待所有的task都执行完成才可以退出程序。最后调用close函数,关闭程序,释放资源。以下的部分将以主函数中出现的调用顺序为依据,展开讲解。

OFPHandler

上文说到,如果没有捕获Application输入,那么默认启动的应用是OFPHandler应用。该应用主要用于处理OpenFlow消息。在start函数初始化运行了一个OpenFlowController实例。OpenFlowController类将在后续介绍。

OFPHandler应用完成了基本的消息处理,如hello_handler:用于处理hello报文,协议版本的协商。其处理并不复杂,但是值得注意的一点是装饰器:Decorator的使用。

Decorator

如果你已经了解Decorator,可以直接跳过本部分。装饰器是什么?Python Decorator coolshell上的介绍Python修饰器的函数式编程 Python Decorator可以看作是一种声明,一种修饰。以下举例参考自Coolshell。举例如下:

实际上等同于foo = decorator(foo), 而且它还被执行了。举个例子:

运行之后,就会输出。。。

多个decorator:

这相当于:

而带参数的decorator:

相当于

decorator(arg1,arg2)将生成一个decorator。

class式的 Decorator

@decorator使用时,__init__被调用,当function被调用是,执行__call__函数,而不执行function,所以在__call__函数中需要写出self.fn = fn,更多内容可以直接访问Python Decorator Library。

OpenFlowController

前一部分提到OFPHandle的start函数会将OpenFlowController启动。本小节介绍OpenFlowController类。该类的定义在ryu/cmd/controller.py文件中。OpenFlowController.__call__()函数启动了server_loop()函数,该函数实例化了hub.py中的StreamServer类,并将handler函数初始化为datapath_connection_factory函数,并调用serve_forever(),不断进行socket的监听。StreamServer定义如下:

Datapath

Datapath类在RYU中极为重要,每当一个datapath实体与控制器建立连接时,就会实例化一个Datapath的对象。 该类中不仅定义了许多的成员变量用于描述一个datapath,还管理控制器与该datapath通信的数据收发。其中_recv_loop函数完成数据的接收与解析,事件的产生与分发。

@_deactivate修饰符作用在于在Datapath断开连接之后,将其状态is_active置为False。self.ofp_brick.send_event_to_observers(ev, self.state) 语句完成了事件的分发。self.brick的初始化语句可以在self.__init__函数中找到:

由上可知,self.ofp_brick实际上是由service_brick(中文可以成为:服务链表?)中的“ofp_event”服务赋值的。在每一个app中,使用@set_ev_cls(ev_cls,dispatchers)时,就会将实例化ofp_event模块,执行文件中最后一句:

register_service函数实体如下:

其中inspect.stack()[1]返回了调用此函数的caller, inspect.getmodule(frm[0])返回了该caller的模块,当前例子下,module=ofp_event。

我们可以通过ryu-manager --verbose来查看到输出信息,从而印证这一点。

所以当运行ofp_handler应用时,就会注册ofp_event service,为后续的应用提供服务。分发事件之后,还要处理自身订阅的事件,所以首先找到符合当前state的caller,然后调用handler。_caller类可以在handler.py文件中找到,包含dispatchers和ev_source两个成员变量。前者用于描述caller需要的state,后者是event产生者的模块名称。

对应的发送循环由_send_loop完成。self.send_p是一个深度为16的发送queue。

serve函数完成了发送循环的启动和接受循环的启动。启动一个coroutine去执行self._send_loop(), 然后马上主动发送hello报文到datapath(可以理解为交换网桥:Bridge),最后执行self._recv_loop()。

而serve函数又在datapath_connection_factory函数中被调用。当然向外提供完整功能的API就是这个。所以在OpenFlowController类中可以看到在初始化server实例的时候,handler赋值为datapath_connection_factory。其中使用到的contextlib module具体内容不作介绍,读者可自行学习。

到此为止,OFPHandler应用的功能实现介绍完毕。RYU启动时,需要启动OFPHandler,才能完成数据的收发和解析。更多的上层应用逻辑都是在此基础之上进行的。若要开发APP则需要继承RyuApp类,并完成observer监听事件,以及注册handler去完成事件处理。

分页阅读: 1 2


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

登录后才可以评论

李呈 发表于14-12-29
18