ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Ryu:模块间通信机制分析

2021-05-03 09:51:58  阅读:189  来源: 互联网

标签:ev self 间通信 ofp handler 模块 Ryu app


图片


_CONTEXTS

在RyuApp类中有一个属性是\_CONTEXTS。\_CONTEXTS中的内容将作为当前模块的服务在模块初始化时得到加载。示例如下:

_CONTEXTS = {

"Network_Aware": network_aware.Network_Aware,

"Network_Monitor": network_monitor.Network_Monitor,

}

def __init__(self, *args, **kwargs):

super(Shortest_forwarding, self).__init__(*args, **kwargs)

self.name = 'shortest_forwarding'

self.network_aware = kwargs["Network_Aware"]

self.network_monitor = kwargs["Network_Monitor"]

在模块启动时,首先会将\_CONTEXTS中的模块先启动,在模块的初始化函数中可以通过self.network_aware = kwargs["Network_Aware"]的形式获得该服务模块的实例,从而获取到该模块的数据,并具有完全的读写能力。这种模式很清晰地体现了模块之间的关系。然而在Ryu的实现中,这个机制并不完美,或者有所限制。首先,当某个模块作为别的模块的服务启动时,就无法在启动Ryu时手动启动。这种做法应该是出于保证模块启动顺序,从而顺利完成多模块启动而设计。另一方面,Ryu不支持多级的服务关系,如A是B的服务,那么B就不能作为其他模块的服务,也即这种服务关系只有两层。所以在设计模块时,若完全使用\_CONTEXTS方式来传递信息则需将架构设计成两层以内。若希望不受此限制,开发者可以自己修改其源码解除这个限制。

app\_manager.lookup\_service\_brick()

在某些业务场景,我们需要使用其他模块的数据,但是又不希望将对方作为自己的服务来加载,则可以通过app\_manager.lookup\_service\_brick('module name')来获取运行中的某个模块的实例,从而获取其数据。典型案例可以参考controller/controller.py中的Datapath类。示例如下:

self.ofp_brick = ryu.base.app_manager.lookup_service_brick('ofp_event')

def set_state(self, state):

self.state = state ev = ofp_event.EventOFPStateChange(self)

ev.state = state
self.ofp_brick.send_event_to_observers(ev, state)

这种做法区别于import, import引入的是静态的数据,如某个类的函数的定义,静态数据的定义。当涉及到动态的数据,import则无法获取到对应的数据。如名为app的模块中有一个属性self.domain = Domain(),那么import可以获得其类的定义,而实际上,我们需要的是运行状态时Domain的实例,而import无法做到这一点。通过app = app\_manager.lookup\_service\_brick(‘app’)可以获得当前的app实例,进而通过app.domain来获取当前的domain实例的数据。

Event

通过事件系统来通信是模块之间通信的最普通的形式。每当交换机和Ryu建立连接,都会实例化一个Datapath对象来处理这个连接。在Datapath对象中,会将接收到的数据解析成对应的报文,进而转化成对应的事件,然后发布。注册了对应事件的模块将收到事件,然后调用对应的handler处理事件。示例如下:

[module: controller]

if msg:

ev = ofp_event.ofp_msg_to_ev(msg)

self.ofp_brick.send_event_to_observers(ev, self.state)

dispatchers = lambda x: x.callers[ev.__class__].dispatchers

handlers = [handler for handler in

self.ofp_brick.get_handlers(ev) if

self.state in dispatchers(handler)]

for handler in handlers:

handler(ev)

[module:simple_switch_13.py]
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)

def _packet_in_handler(self, ev):

msg = ev.msg

datapath = msg.datapath

编译运行之后,simple\_switch\_13模块的\_packet\_in\_handler函数注册了事件ofp\_event.EventOFPPacketIn, 当Controller模块中的Datapath分发ofp\_event.EventOFPPacketIn事件时, 将会分发到\_packet\_in\_handler函数,在Datapath中调用handler(ev)来处理事件,从而完成了信息在模块之间的通信。

公共文件读写

除了以上的形式以外,某些数据的通信则通过读写公共文件完成。最典型的案例是oslo.config的使用。oslo是OpenStack的开源库。oslo.config提供一个全局的配置文件,同时也完成命令行的解析。通过读写公共文件的内容,可以完成信息的传递,如模块A将config中CONF对象的某个参数arg的i值修改为1, B再读取对应的参数arg,则可以获得数值1, 从而完成通信。面对配置信息等全局信息时,公共文件的使用可以避免不同模块之间的冲突,从而实现全局数据的统一。但是这种做法会频繁地读写文件,效率不高。且此类数据仅适合静态数据的传递,不适合存在于实例中的动态数据。

总结

在使用Ryu开发SDN网络应用的过程中,多模块协同工作是非常常见的场景。使用\_CONTEXTS形式可以更清晰地体现模块之间的关系,代码架构可读性更高;采用app\_manager.lookup\_service\_brick()形式可以得到运行的实例,可以达到\_CONTEXTS的效果,适用与仅需使用某模块某小部分功能集合,模块之间没有明显的服务关系的场景;Event是最普通的模块见通信,可以实现订阅发布模式的多模块协同工作场景,实现模块之间解耦;采用公共文件作为信息的中转站是最后的选择,效率比较低,适用于全局信息的传递。以上的几种方式是笔者在实验过程中总结的通信方式,若有错误指出,敬请指出,万分感谢。


标签:ev,self,间通信,ofp,handler,模块,Ryu,app
来源: https://blog.51cto.com/u_15127593/2750983

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有