Ryu代码解析(一)
2015-05-19 11:33
218 查看
转载:http://geekwei.com/2014/11/27/ryu-source-analysis-1/
http://www.muzixing.com/pages/2014/12/27/ryujie-du-ofphandlercontrollerryuapphe-appmanager.html
Ryu的main函数位于cmd\manager.py文件中,main函数如下:
AppManager中get_instance()函数,典型的单体类实现方法
load_app函数:加载app,本质是找到app名字对应的类
用到的python 基础:inspect.getmembers()和inspect例子
load_apps函数:加载app,说是加载,其实就是找到这个类,并把其存到applications_cls中,key是app类的名字,值就是这个类,加载的过程中顺便加载每个app依赖的app类,而且把每个app的context保存到context_cls中。
python 基础 python map函数浅析
create_contexts函数:实例化context_cls中的context,如果这个context是app,就实例化该app。记得在load_apps中没有管属于context_cls的app吗,在这里直接初始化了。
_instantiate函数:
register_app函数中调用regester_instance函数(该函数在handler.py文件中),在该函数中通过inspect.getmembers函数,获取app类中的方法,并通过app的register_handler将handler注册到app的event_handlers成员变量中
到这儿可能还比较迷惑,handler是如何挂到每个事件上的,将在后面的Ryu事件处理函数的挂接方式分析中专门介绍一下。
instantiate_apps函数:实例化app,并且启动每个app
http://www.muzixing.com/pages/2014/12/27/ryujie-du-ofphandlercontrollerryuapphe-appmanager.html
RYU main函数
Ryu的main函数位于cmd\manager.py文件中,main函数如下:def main(args=None, prog=None): try: CONF(args=args, prog=prog, project='ryu', version='ryu-manager %s' % version, default_config_files=['/usr/local/etc/ryu/ryu.conf']) except cfg.ConfigFilesNotFoundError: CONF(args=args, prog=prog, project='ryu', version='ryu-manager %s' % version) log.init_log() if CONF.pid_file: import os with open(CONF.pid_file, 'w') as pid_file: pid_file.write(str(os.getpid())) app_lists = CONF.app_lists + CONF.app //从用户命令行获取的app列表 # keep old behaivor, run ofp if no application is specified. if not app_lists: app_lists = ['ryu.controller.ofp_handler'] //添加默认的应用 app_mgr = AppManager.get_instance() //获取appManager实例,是单体类 app_mgr.load_apps(app_lists) //加载所有app contexts = app_mgr.create_contexts() //加载context services = [] services.extend(app_mgr.instantiate_apps(**contexts)) //以context作为参数,实例化app webapp = wsgi.start_service(app_mgr) if webapp: thr = hub.spawn(webapp) services.append(thr) try: hub.joinall(services) finally: app_mgr.close()
AppManager
AppManager中get_instance()函数,典型的单体类实现方法def get_instance(): if not AppManager._instance: AppManager._instance = AppManager() return AppManager._instance
load_app函数:加载app,本质是找到app名字对应的类
用到的python 基础:inspect.getmembers()和inspect例子
def load_app(self, name): mod = utils.import_module(name) clses = inspect.getmembers(mod, lambda cls: (inspect.isclass(cls) and issubclass(cls, RyuApp) and mod.__name__ == cls.__module__)) //过滤函数是lambda表达式 if clses: return clses[0][1] //只与符合条件的第一个!!!文档里就这么要求的 return None
load_apps函数:加载app,说是加载,其实就是找到这个类,并把其存到applications_cls中,key是app类的名字,值就是这个类,加载的过程中顺便加载每个app依赖的app类,而且把每个app的context保存到context_cls中。
python 基础 python map函数浅析
def load_apps(self, app_lists): app_lists = [app for app in itertools.chain.from_iterable(app.split(',') for app in app_lists)] while len(app_lists) > 0: app_cls_name = app_lists.pop(0) context_modules = map(lambda x: x.__module__, self.contexts_cls.values()) //获取所有context类所在的模块 if app_cls_name in context_modules: //不加载属于context的类,因为之后在create_context函数中会加载 continue LOG.info('loading app %s', app_cls_name) cls = self.load_app(app_cls_name) //找到app的类,cls就是这个app的类 if cls is None: continue self.applications_cls[app_cls_name] = cls //将app添加到字典 services = [] for key, context_cls in cls.context_iteritems(): //便利这个app类的context,将其context加入contexts_cls字典 v = self.contexts_cls.setdefault(key, context_cls) assert v == context_cls context_modules.append(context_cls.__module__) if issubclass(context_cls, RyuApp): //感觉这里写错了,其实context的类在之后会加载,和前面的描述不符 services.extend(get_dependent_services(context_cls)) # we can't load an app that will be initiataed for # contexts. for i in get_dependent_services(cls): //加载这个app的依赖app,依赖app不在context_modules字典中 if i not in context_modules: services.append(i) if services: app_lists.extend([s for s in set(services) if s not in app_lists]) //将依赖的app都加入app_lists,在之后的循环中加载
create_contexts函数:实例化context_cls中的context,如果这个context是app,就实例化该app。记得在load_apps中没有管属于context_cls的app吗,在这里直接初始化了。
def create_contexts(self): for key, cls in self.contexts_cls.items(): if issubclass(cls, RyuApp): # hack for dpset context = self._instantiate(None, cls) //初始化app else: context = cls() //实例化context LOG.info('creating context %s', key) assert key not in self.contexts self.contexts[key] = context //加入contexts字典 return self.contexts //返回contexts字典
_instantiate函数:
def _instantiate(self, app_name, cls, *args, **kwargs): # for now, only single instance of a given module # Do we need to support multiple instances? # Yes, maybe for slicing. LOG.info('instantiating app %s of %s', app_name, cls.__name__) if hasattr(cls, 'OFP_VERSIONS') and cls.OFP_VERSIONS is not None: ofproto_protocol.set_app_supported_versions(cls.OFP_VERSIONS) if app_name is not None: assert app_name not in self.applications app = cls(*args, **kwargs) //实例化app类,kwargs参数是context字典 register_app(app) //注册app对象,主要是通过inspect组件获取其中的handler,详见下文 assert app.name not in self.applications self.applications[app.name] = app //将app对象保存到applications字典中 return app
register_app函数中调用regester_instance函数(该函数在handler.py文件中),在该函数中通过inspect.getmembers函数,获取app类中的方法,并通过app的register_handler将handler注册到app的event_handlers成员变量中
def register_instance(i): for _k, m in inspect.getmembers(i, inspect.ismethod): # LOG.debug('instance %s k %s m %s', i, _k, m) if _has_caller(m): for ev_cls, c in m.callers.iteritems(): i.register_handler(ev_cls, m)
到这儿可能还比较迷惑,handler是如何挂到每个事件上的,将在后面的Ryu事件处理函数的挂接方式分析中专门介绍一下。
instantiate_apps函数:实例化app,并且启动每个app
def instantiate_apps(self, *args, **kwargs): for app_name, cls in self.applications_cls.items(): self._instantiate(app_name, cls, *args, **kwargs) self._update_bricks() //将app更新到全局变量SERVICE_BRICK中 self.report_bricks() threads = [] for app in self.applications.values(): t = app.start() //启动APP if t is not None: threads.append(t) return threads
相关文章推荐
- Ryu代码解析(二)
- Ryu代码解析(三)
- Ryu代码解析(四)
- Ryu代码解析(五)
- RYU控制器代码解析-Hub
- RYU控制器代码解析-简单交换机
- Ryu代码解析(六)
- Ryu控制器代码解析-任意地址Ping应答
- STM32 启动解析,启动代码,__main main
- 第45讲:Scala中Context Bounds代码实战及其在Spark中的应用源码解析学习笔记
- 代码解析String原理
- [代码笔记] python 之 xml解析_sax:基于事件驱动的解析方式
- JS延时器提示框的应用实例代码解析
- 用phpQuery像jquery一样解析html代码
- swift:使用NSJSONSerialization解析本地json数据文件(代码详细注释)
- 在java中使用dom4j解析xml(示例代码)
- 不要再吹水地球人听不懂的技术,咱来点干货!--中文前端UI框架Kit(二)kitjs组件代码解析
- Python enumerate索引迭代代码解析
- 【leetcode】第73题 Set Matrix Zeroes 题目+解析+JAVA代码
- 开机锁屏部分代码解析