作为一个业余研究Ryu的软件工程师,一直惊叹于Ryu设计的优雅与简洁。一年多坚持下来,也有自己的一些收获,写出来和大家分享一下。
我们的故事从@set_ev_cls这个被大量使用的装饰器开始。
装饰器的内容已经有小伙伴写到了,这里不再重复。我关心的重点在第一个参数ev_cls上,
比如simple_switch_13.py中@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
EventOFPPacketIn,类究竟在哪定义,我在\ryu\controller\ofp_event文件中没有找到,甚至搜索完了整个ryu工程都没有搜到。与此类似的ofp_event.EventOFPPortStatus, ofp_event.EventOFPFlowRemoved,ofp_event.EventOFPDescStatsReply等等,他们这些类的定义也没有找到。
某个烈日炎炎的下午,不经意的我在\ryu\controller\ofp_event文件中发现了一点蛛丝马迹:
将ofp的msg名字加上“Event的前缀”,这个有点像。
喔,这个地方creat了一个类,好像就是ev_class(type的用法:创建类的类,元类,以name为类型,以EventOFPMsgBase为父类,并定义了初始化方法,并放到全局字典globals和_OFP_MSG_EVENTS),动态生成需要的类,小样,真有你的。
更进一步从模块名创建ev_class,明确标明了,有'cls_msg_type'属性的才有资格创建类。
终于看到调用的地方了,在同一个文件中的这段代码可不是定义函数,而是直接执行语句哦。其中get_ofp_modules就是获取ofp的版本文件的parser,然后根据这些文件创建对应了msg_ev_class.我们去ryu\ofproto\ofproto_v1_X_parser(X可以为0,1,2,3,你懂的)文件中确认一下。
看,还真是这样。连注释上都写得是一模一样的Example,其他诸如ofp_event.EventOFPPortStatus, ofp_event.EventOFPFlowRemoved,ofp_event.EventOFPDescStatsReply也能找到对应的地方。
这下终于真相大白,我们脑海中有了这样一幅画面,自动去搜索ofp不同版本的模块,找到有cls_msg_type属性的类,然后把它们的名字变换一下,生成对应的类。Ryu的优美与简洁,果然名不虚传。
还有我们的ofp_msg_to_ev,看它的定义是生成类的实例。在Datapath类的_recv_loop中,Ryu从数据流中解析出msg,然后根据msg生成上面msg_ev_class的实例,并通过ofp_brick发送给观察者。send_event_to_observers(ev, self.state)是通过SERVICE_BRICKS(服务实体链表,其实就是所有app的字典)来进行不同模块中的通信的。
在RyuApp的register_handler,register_observer可以看到,观察者和handler的注册都是通过类名。而RyuApp的get_handlers,get_observers方法传入得参数是实例。
这样我们就知道了@set_ev_cls如何用ofp的event类去修饰handler方法,以及如何由具体的报文,得到对应的实例,最后调用到具体的handler方法上。良好的命名规范还真有助于增加代码的可读性。
我们的李呈大神在《RYU源码解读》(http://www.sdnlab.com/6395.html)已经把ryu的启动流程给我们大致讲解了。
不过我本人觉得还不过瘾,有几点在这里补充一下。
1.hanglder.reuster_service是在import的时候被执行的,一般都在app文件的最开头,而不是在使用@set_ev_cls装饰器的时候。
2._Event的使用在\ryu\topology\switches中有如下代码
而在\ryu\base\app_manager文件中有
从这些线索中我们可以看到_EVENTS其实就是上文中动态生成的msg_ev_class的补充,因为不属于OFP模块的内容,自然需要other模块提供。当然Event类的来源还通过import得到,比如\ryu\lib\lacplib.py就定义了大量的Event类,simple_switch_lacp_13.py就是通过from ryu.lib import lacplib来使用的。
3.@set_ev_cls还有个兄弟@set_ev_handler,在\ryu\app\gre_tunnel和\ryu\controller\ofp_handler有使用。两者的区别在set_ev_handler收到对应的事件后自己处理就行了,不需要再通知给observer,而set_ev_cls先通知给observer,再自己处理。原因如下
读完了这些,不得不感叹,RYU实在是太美妙了。它的内部机制的实现,很值得我们学习和借鉴。