Ryu的源码分析
一:安装Pycharm
https://www.cnblogs.com/huozf/p/9304396.html(有可取之处)
https://www.jetbrains.com/idea/buy/#discounts?billing=yearly(学生注册,免费)
二:推文
https://www.cnblogs.com/ssyfj/p/11730362.html(含目录介绍)
三:源码分析流程
四:找入口函数main
(一)我们编写的应用:全部继承于app_manager.RyuApp----去看他
from ryu.base import app_manager class Hub(app_manager.RyuApp): pass
没有找到主函数main!!!!
(二)我们启动Ryu的常用方式
ryu-manager simple_switch_13.py --verbose
通过终端输入,启动Ryu控制器。因此我们进入cmd目录中
cmd目录定义了RYU的命令系统
我们在该文件目录下的两个文件中都找到了main函数-----Ok 反正是找到了main函数
(三)使用Ctrl+B查找调用main函数的位置
1.ryu_base.py查找
在主目录下的bin目录的ryu文件中,调用了主函数main
2.在manager.py中查找
在主目录下的bin目录的ryu-manager文件中,调用了主函数main
重点:这里基本可以确定这里是函数入口----因为我们在命令行中常使用ryu-manager----(实际上两个都可以作为入口)
3.ryu和ryu-manager的区别???
ryu下:
from ryu.cmd.ryu_base import main main()
def main(): try: base_conf(project='ryu', version='ryu %s' % version) except cfg.RequiredOptError as e: base_conf.print_help() raise SystemExit(1) subcmd_name = base_conf.subcommand try: subcmd_mod_name = subcommands[subcmd_name] except KeyError: base_conf.print_help() raise SystemExit('Unknown subcommand %s' % subcmd_name) subcmd_mod = utils.import_module(subcmd_mod_name) subcmd = SubCommand(name=subcmd_name, entry=subcmd_mod.main) subcmd.run(base_conf.subcommand_args)
ryu-manager下:
from ryu.cmd.manager import main main()
def main(args=None, prog=None): _parse_user_flags() 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() logger = logging.getLogger(__name__) if CONF.enable_debugger: msg = 'debugging is available (--enable-debugger option is turned on)' logger.info(msg) else: hub.patch(thread=True) if CONF.pid_file: with open(CONF.pid_file, 'w') as pid_file: pid_file.write(str(os.getpid())) app_lists = CONF.app_lists + CONF.app # keep old behavior, run ofp if no application is specified. if not app_lists: app_lists = ['ryu.controller.ofp_handler'] app_mgr = AppManager.get_instance() app_mgr.load_apps(app_lists) contexts = app_mgr.create_contexts() services = [] services.extend(app_mgr.instantiate_apps(**contexts)) webapp = wsgi.start_service(app_mgr) if webapp: thr = hub.spawn(webapp) services.append(thr) try: hub.joinall(services) except KeyboardInterrupt: logger.debug("Keyboard Interrupt received. " "Closing RYU application manager...") finally: app_mgr.close()
比较:ryu命令main函数中默认没有参数--我们可以直接调用查看
ryu命令主要为我们提供了,文档类信息。当然我们可以看到其中有一个run命令--我们可以通过这个命令实现ryu-manager命令
ryu run ./simple_switch_13.py --verbose
subcommands = { 'run': 'ryu.cmd.manager', 'of-config-cli': 'ryu.cmd.of_config_cli', 'rpc-cli': 'ryu.cmd.rpc_cli', }
这么看来,ryu功能更强大,但是使用ryu-manage更加方便,我们开始使用ryu-manager作为入口进行研究
五:对main函数进行分析
def main(args=None, prog=None): _parse_user_flags() 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() logger = logging.getLogger(__name__) if CONF.enable_debugger: msg = 'debugging is available (--enable-debugger option is turned on)' logger.info(msg) else: hub.patch(thread=True) if CONF.pid_file: with open(CONF.pid_file, 'w') as pid_file: pid_file.write(str(os.getpid())) app_lists = CONF.app_lists + CONF.app # keep old behavior, run ofp if no application is specified. if not app_lists: app_lists = ['ryu.controller.ofp_handler'] app_mgr = AppManager.get_instance() app_mgr.load_apps(app_lists) contexts = app_mgr.create_contexts() services = [] services.extend(app_mgr.instantiate_apps(**contexts)) webapp = wsgi.start_service(app_mgr) if webapp: thr = hub.spawn(webapp) services.append(thr) try: hub.joinall(services) except KeyboardInterrupt: logger.debug("Keyboard Interrupt received. " "Closing RYU application manager...") finally: app_mgr.close()
(一)代码精简---对日志、注释删除
def main(args=None, prog=None): _parse_user_flags() 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) if CONF.enable_debugger:else: hub.patch(thread=True) if CONF.pid_file: with open(CONF.pid_file, 'w') as pid_file: pid_file.write(str(os.getpid())) app_lists = CONF.app_lists + CONF.appif not app_lists: app_lists = ['ryu.controller.ofp_handler'] app_mgr = AppManager.get_instance() app_mgr.load_apps(app_lists) contexts = app_mgr.create_contexts() services = [] services.extend(app_mgr.instantiate_apps(**contexts)) webapp = wsgi.start_service(app_mgr) if webapp: thr = hub.spawn(webapp) services.append(thr) try: hub.joinall(services)finally: app_mgr.close()
1._parse_user_flags()
Parses user-flags file and loads it to register user defined options.
idx = list(sys.argv).index('--user-flags')
没有使用过--user-flags参数,所有这个不是必须的,跳过
2.try...except... 配置文件加载---跳过
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)
"""Config options which may be set on the command line or in config files. ConfigOpts is a configuration option manager with APIs for registering option schemas, grouping options, parsing option values and retrieving the values of options. It has built-in support for :oslo.config:option:`config_file` and :oslo.config:option:`config_dir` options. """
3.CONF.enable_debugger 是否开启调试---跳过
if CONF.enable_debugger: msg = 'debugging is available (--enable-debugger option is turned on)' logger.info(msg) else: hub.patch(thread=True)
cfg.BoolOpt('enable-debugger', default=False, help='don\'t overwrite Python standard threading library' '(use only for debugging)'),
4.CONF.pid_file 根据配置信息决定是否打开一个可写文件----配置信息 跳过
if CONF.pid_file: with open(CONF.pid_file, 'w') as pid_file: pid_file.write(str(os.getpid()))
5.程序重点逻辑-----找到
app_lists = CONF.app_lists + CONF.app # keep old behavior, run ofp if no application is specified. if not app_lists: app_lists = ['ryu.controller.ofp_handler'] app_mgr = AppManager.get_instance() app_mgr.load_apps(app_lists) contexts = app_mgr.create_contexts() services = [] services.extend(app_mgr.instantiate_apps(**contexts))
6.webapp = wsgi.start_service(app_mgr) 开启web服务,提供北向接口 跳过
webapp = wsgi.start_service(app_mgr) if webapp: thr = hub.spawn(webapp) 如果开启,则产生一个协程去运行他 services.append(thr)
7.hub.joinall(services)等待程序结束
try: hub.joinall(services) 等待所有线程/协程结束 except KeyboardInterrupt: 按键触发,常按Ctrl+C的应该看见过 logger.debug("Keyboard Interrupt received. " "Closing RYU application manager...") finally: app_mgr.close() 最后进行资源回收
六:对业务主逻辑分析
app_lists = CONF.app_lists + CONF.app # keep old behavior, run ofp if no application is specified. if not app_lists: app_lists = ['ryu.controller.ofp_handler'] app_mgr = AppManager.get_instance() app_mgr.load_apps(app_lists) contexts = app_mgr.create_contexts() services = [] services.extend(app_mgr.instantiate_apps(**contexts))
首先:备份一份原始Ryu文件,在新的Ryu目录进行逻辑分析(补充,不是一定要做,也不是现在做)
sudo python3 setup.py install 修改文件后,对Ryu项目进行重新编译安装
(一)app_lists = CONF.app_lists + CONF.app 获取应用列表
1.先修改文件代码,之后进行Ryu重新编译安装
app_lists = CONF.app_lists + CONF.app print("------Start------") print("------CONF-----") print(CONF) print("------CONF.app_lists-----") print(CONF.app_lists) print("------CONF.app-----") print(CONF.app) print("------End------")
2.启动Ryu 启动多个app
ryu-manager ./simple_switch_13.py ofctl_rest.py --verbose
------Start------ ------CONF----- <oslo_config.cfg.ConfigOpts object at 0x7f89af107ac8> ------CONF.app_lists----- [] ------CONF.app----- ['./simple_switch_13.py', 'ofctl_rest.py'] ------End------
补充:CONF.app_lists 也是一个应用程序app
cfg.ListOpt('app-lists', default=[], 默认为空 help='application module name to run'),
补充:CONF.app 是我们要运行的app文件---是列表---可运行多个
cfg.MultiStrOpt('app', positional=True, default=[], help='application module name to run'),
['./simple_switch_13.py', 'ofctl_rest.py']
3.if not app_lists: 如果为空,则设置一个默认的app
if not app_lists: app_lists = ['ryu.controller.ofp_handler']
(二)app_mgr = AppManager.get_instance() 按照单例模式创建一个实例,用于应用管理
@staticmethod def get_instance(): if not AppManager._instance: AppManager._instance = AppManager() return AppManager._instance
(三)app_mgr.load_apps(app_lists) 加载应用---重点,待分析
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 = [x.__module__ for x in self.contexts_cls.values()] if app_cls_name in context_modules: continue LOG.info('loading app %s', app_cls_name) cls = self.load_app(app_cls_name) if cls is None: continue self.applications_cls[app_cls_name] = cls services = [] for key, context_cls in cls.context_iteritems(): v = self.contexts_cls.setdefault(key, context_cls) assert v == context_cls context_modules.append(context_cls.__module__) if issubclass(context_cls, RyuApp): 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): 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])
(四)contexts = app_mgr.create_contexts() 创建上下文(环境)---待分析
def create_contexts(self): for key, cls in self.contexts_cls.items(): print("------start------") print(key) print("-----------------") print(cls) print("------ end ------") if issubclass(cls, RyuApp): # hack for dpset context = self._instantiate(None, cls) else: context = cls() LOG.info('creating context %s', key) assert key not in self.contexts self.contexts[key] = context return self.contexts
for key, cls in self.contexts_cls.items(): print("------start------") print(key) print("-----------------") print(cls) print("------ end ------")
------start------ dpset ----------------- <class 'ryu.controller.dpset.DPSet'> ------ end ------ instantiating app None of DPSet creating context dpset ------start------ wsgi ----------------- <class 'ryu.app.wsgi.WSGIApplication'> ------ end ------ creating context wsgi
将所依赖的环境加载进来
(五)services---启动的服务(绿色线程---协程)---待分析
services = []
services.extend(app_mgr.instantiate_apps(**contexts))
services = [] services.extend(app_mgr.instantiate_apps(**contexts)) print("---------start-----------") for sv in services: print(sv) print("----------end------------")
---------start----------- <eventlet.greenthread.GreenThread object at 0x7fd6db2add58> ----------end------------
主要代码分析
app_mgr = AppManager.get_instance() app_mgr.load_apps(app_lists) contexts = app_mgr.create_contexts() services = [] services.extend(app_mgr.instantiate_apps(**contexts))
七:app_mgr = AppManager.get_instance() 单例模式创建一个对象--初始化对象
def __init__(self): self.applications_cls = {} self.applications = {} self.contexts_cls = {} self.contexts = {} self.close_sem = hub.Semaphore()
八:app_mgr.load_apps(app_lists) 加载app
(一)load_apps 加载多个app
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 = [x.__module__ for x in self.contexts_cls.values()] if app_cls_name in context_modules: continue LOG.info('loading app %s', app_cls_name) cls = self.load_app(app_cls_name) 调用上面加载一个app函数 if cls is None: continue self.applications_cls[app_cls_name] = cls services = [] for key, context_cls in cls.context_iteritems(): v = self.contexts_cls.setdefault(key, context_cls) assert v == context_cls context_modules.append(context_cls.__module__) if issubclass(context_cls, RyuApp): 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): 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_lists 获取app列表---我们要启动的app
app_lists = [app for app in itertools.chain.from_iterable(app.split(',') for app in app_lists)]
app_lists = [app for app in itertools.chain.from_iterable(app.split(',') for app in app_lists)] print("----------------") print(app_lists) print("----------------")
(三)while循环逻辑
while len(app_lists) > 0: app_cls_name = app_lists.pop(0) 提取出一个app类名 context_modules = [x.__module__ for x in self.contexts_cls.values()] if app_cls_name in context_modules: continue LOG.info('loading app %s', app_cls_name) cls = self.load_app(app_cls_name) if cls is None: continue self.applications_cls[app_cls_name] = cls services = [] for key, context_cls in cls.context_iteritems(): v = self.contexts_cls.setdefault(key, context_cls) assert v == context_cls context_modules.append(context_cls.__module__) if issubclass(context_cls, RyuApp): 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): 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])
1.context_modules = [x.__module__ for x in self.contexts_cls.values()]
while len(app_lists) > 0: app_cls_name = app_lists.pop(0) context_modules = [x.__module__ for x in self.contexts_cls.values()] 加载依赖环境 print("----------------") print(context_modules) print("----------------")
---------------- [] ---------------- loading app ./simple_switch_13.py ---------------- [] ---------------- loading app ofctl_rest.py ---------------- ['ryu.controller.dpset', 'ryu.app.wsgi'] ---------------- loading app ryu.controller.ofp_handler
2. if app_cls_name in context_modules: continue 如果在context_modules中加载了,就不用再加载了
3.load_app 加载单个app类------传入一个类名,获取一个类
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__)) 获取多个符合的类
if clses:
return clses[0][1] 返回第一个类信息
return None
print("---------------") print(clses) print("---------------") print(name) print(clses[0][1]) print("---------------")
loading app ./simple_switch_13.py --------------- [('SimpleSwitch13', <class 'simple_switch_13.SimpleSwitch13'>)] --------------- ./simple_switch_13.py <class 'simple_switch_13.SimpleSwitch13'> --------------- loading app ofctl_rest.py --------------- [('RestStatsApi', <class 'ofctl_rest.RestStatsApi'>)] --------------- ofctl_rest.py <class 'ofctl_rest.RestStatsApi'> --------------- loading app ryu.controller.ofp_handler --------------- [('OFPHandler', <class 'ryu.controller.ofp_handler.OFPHandler'>)] --------------- ryu.controller.ofp_handler <class 'ryu.controller.ofp_handler.OFPHandler'> ---------------
4.self.applications_cls[app_cls_name] = cls 字典--保存类名:类
5.对各个类cls进行判断
services = [] for key, context_cls in cls.context_iteritems(): v = self.contexts_cls.setdefault(key, context_cls) assert v == context_cls context_modules.append(context_cls.__module__) 如果是依赖的类,放入context_modules中 if issubclass(context_cls, RyuApp): 如果是应用类子类,加入services中 services.extend(get_dependent_services(context_cls))
6.获取一些依赖服务,如果z在context_modules中存在,则不重做
for i in get_dependent_services(cls): if i not in context_modules: services.append(i)
# we can't load an app that will be initiataed for # contexts.
7.app_lists添加 将不在context_modules中的模块,但是是app类需要的依赖加入app_lists中
if services: app_lists.extend([s for s in set(services) if s not in app_lists])
九:contexts = app_mgr.create_contexts() 环境(依赖)类的实例化
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) register_app(app) assert app.name not in self.applications self.applications[app.name] = app return 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() 实例化依赖类 LOG.info('creating context %s', key) assert key not in self.contexts self.contexts[key] = context return self.contexts 返回实例化对象列表
------key----cls-------- dict_items([
('dpset', <class 'ryu.controller.dpset.DPSet'>),
('wsgi', <class 'ryu.app.wsgi.WSGIApplication'>)]) ----------end----------- -----subclass---- <class 'ryu.controller.dpset.DPSet'> ------------
def create_contexts(self): print("------key----cls--------") print(self.contexts_cls.items()) print("----------end-----------") for key, cls in self.contexts_cls.items(): if issubclass(cls, RyuApp): # hack for dpset print("-----subclass----") print(cls) print("------------") context = self._instantiate(None, cls) else: context = cls() LOG.info('creating context %s', key) assert key not in self.contexts self.contexts[key] = context return self.contexts
最终:contexts
contexts = app_mgr.create_contexts() print("--------contexts----------") print(contexts) print("---------end--------------")
十:app_mgr.instantiate_apps(**contexts)实例化我们(调用)写的app类 传入上下文环境
def instantiate_apps(self, *args, **kwargs): print("---------init self.applications_cls.items() ----------") print(self.applications_cls.items()) print('--------end------------------')
显示:
---------init self.applications_cls.items() ---------- dict_items([('./simple_switch_13.py', <class 'simple_switch_13.SimpleSwitch13'>), ('ofctl_rest.py', <class 'ofctl_rest.RestStatsApi'>), ('ryu.controller.ofp_handler', <class 'ryu.controller.ofp_handler.OFPHandler'>)]) --------end------------------ instantiating app ./simple_switch_13.py of SimpleSwitch13 实例化对象 instantiating app ofctl_rest.py of RestStatsApi instantiating app ryu.controller.ofp_handler of OFPHandler
调用self._instantiate(app_name, cls, *args, **kwargs)进行实例化。同上九
self.applications[app.name] = app 将所有实例化对象加入全局字典
查看applications
print("---------init self.applications_cls.items() ----------") print(self.applications_cls.items()) print('--------end------------------') for app_name, cls in self.applications_cls.items(): self._instantiate(app_name, cls, *args, **kwargs) print("---------finally self.applications ----------") print(self.applications) print('--------end------------------')
两者区别:applications包含了之前实例化的依赖对象
loading app ./simple_switch_13.py loading app ofctl_rest.py loading app ryu.controller.ofp_handler instantiating app None of DPSet creating context dpset creating context wsgi ---------init self.applications_cls.items() ---------- dict_items([
('./simple_switch_13.py', <class 'simple_switch_13.SimpleSwitch13'>),
('ofctl_rest.py', <class 'ofctl_rest.RestStatsApi'>),
('ryu.controller.ofp_handler', <class 'ryu.controller.ofp_handler.OFPHandler'>)
]) --------end------------------ instantiating app ./simple_switch_13.py of SimpleSwitch13 instantiating app ofctl_rest.py of RestStatsApi instantiating app ryu.controller.ofp_handler of OFPHandler ---------finally self.applications ---------- {
'dpset': <ryu.controller.dpset.DPSet object at 0x7f223b239c50>,
'SimpleSwitch13': <simple_switch_13.SimpleSwitch13 object at 0x7f223b20aac8>,
'RestStatsApi': <ofctl_rest.RestStatsApi object at 0x7f223b20ac18>,
'ofp_event': <ryu.controller.ofp_handler.OFPHandler object at 0x7f223b19afd0>} --------end------------------
十一:生产者-消费者模型---重点---待分析
self._update_bricks() 更新服务链
self.report_bricks() 报告服务链
BRICK dpset
CONSUMES EventOFPStateChange
CONSUMES EventOFPPortStatus
CONSUMES EventOFPSwitchFeatures
BRICK SimpleSwitch13
CONSUMES EventOFPPacketIn -----待解决
CONSUMES EventOFPSwitchFeatures
BRICK RestStatsApi
CONSUMES EventOFPSwitchFeatures
CONSUMES EventOFPQueueGetConfigReply
CONSUMES EventOFPRoleReply
CONSUMES EventOFPStatsReply
CONSUMES EventOFPDescStatsReply
CONSUMES EventOFPFlowStatsReply
CONSUMES EventOFPAggregateStatsReply
CONSUMES EventOFPTableStatsReply
CONSUMES EventOFPTableFeaturesStatsReply
CONSUMES EventOFPPortStatsReply
CONSUMES EventOFPQueueStatsReply
CONSUMES EventOFPQueueDescStatsReply
CONSUMES EventOFPMeterStatsReply
CONSUMES EventOFPMeterFeaturesStatsReply
CONSUMES EventOFPMeterConfigStatsReply
CONSUMES EventOFPGroupStatsReply
CONSUMES EventOFPGroupFeaturesStatsReply
CONSUMES EventOFPGroupDescStatsReply
CONSUMES EventOFPPortDescStatsReply
BRICK ofp_event PROVIDES EventOFPStateChange TO {'dpset': {'main', 'dead'}} PROVIDES EventOFPPortStatus TO {'dpset': {'main'}} PROVIDES EventOFPSwitchFeatures TO {'dpset': {'config'}, 'SimpleSwitch13': {'config'}, 'RestStatsApi': {'main'}} PROVIDES EventOFPPacketIn TO {'SimpleSwitch13': {'main'}} PROVIDES EventOFPQueueGetConfigReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPRoleReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPDescStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPFlowStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPAggregateStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPTableStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPTableFeaturesStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPPortStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPQueueStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPQueueDescStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPMeterStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPMeterFeaturesStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPMeterConfigStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPGroupStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPGroupFeaturesStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPGroupDescStatsReply TO {'RestStatsApi': {'main'}} PROVIDES EventOFPPortDescStatsReply TO {'RestStatsApi': {'main'}} CONSUMES EventOFPEchoReply CONSUMES EventOFPEchoRequest CONSUMES EventOFPErrorMsg CONSUMES EventOFPHello CONSUMES EventOFPPortDescStatsReply CONSUMES EventOFPPortStatus CONSUMES EventOFPSwitchFeatures
(一)self._update_bricks() 将所有监听的事件进行注册,告诉app_manager,我需要监听这些事件
def _update_bricks(self): for i in SERVICE_BRICKS.values(): for _k, m in inspect.getmembers(i, inspect.ismethod): if not hasattr(m, 'callers'): continue for ev_cls, c in m.callers.items(): if not c.ev_source: continue brick = _lookup_service_brick_by_mod_name(c.ev_source) if brick: brick.register_observer(ev_cls, i.name, c.dispatchers) #注册事件,传入事件名,和在什么状态触发 # allow RyuApp and Event class are in different module for brick in SERVICE_BRICKS.values(): if ev_cls in brick._EVENTS: brick.register_observer(ev_cls, i.name, c.dispatchers)
(二)self.report_bricks()
@staticmethod def _report_brick(name, app): LOG.debug("BRICK %s", name) for ev_cls, list_ in app.observers.items(): 显示信息 LOG.debug(" PROVIDES %s TO %s", ev_cls.__name__, list_) for ev_cls in app.event_handlers.keys(): LOG.debug(" CONSUMES %s", ev_cls.__name__) @staticmethod def report_bricks(): for brick, i in SERVICE_BRICKS.items(): AppManager._report_brick(brick, i)
十二:线程启用---将上面每一个实例对象对应生成一个线程去处理
threads = [] for app in self.applications.values(): t = app.start() if t is not None: app.set_main_thread(t) threads.append(t) return threads
for app in self.applications.values(): print("-------app--------") print(app) print("-------end--------") t = app.start() if t is not None: app.set_main_thread(t) threads.append(t)
-------app-------- <ryu.controller.dpset.DPSet object at 0x7f681bbf4be0> -------end-------- -------app-------- <simple_switch_13.SimpleSwitch13 object at 0x7f681bbc5a58> -------end-------- -------app-------- <ofctl_rest.RestStatsApi object at 0x7f681bbc5ba8> -------end-------- -------app-------- <ryu.controller.ofp_handler.OFPHandler object at 0x7f681bb54f60> -------end--------
(一)因为我们的app类是继承class RyuApp(object):其中有start方法,可以生成一个协程,去循环处理等待事件信息
def start(self): """ Hook that is called after startup initialization is done. """ self.threads.append(hub.spawn(self._event_loop))
def _event_loop(self): while self.is_active or not self.events.empty(): 循环处理事件 ev, state = self.events.get() self._events_sem.release() if ev == self._event_stop: continue handlers = self.get_handlers(ev, state) for handler in handlers: try: handler(ev) except hub.TaskExit: # Normal exit. # Propagate upwards, so we leave the event loop. raise except: LOG.exception('%s: Exception occurred during handler processing. ' 'Backtrace from offending handler ' '[%s] servicing event [%s] follows.', self.name, handler.__name__, ev.__class__.__name__)