一:安裝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__)