SDN实验---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()
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) > :
app_cls_name = app_lists.pop() 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
create_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) > :
app_cls_name = app_lists.pop() 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) > :
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) > :
app_cls_name = app_lists.pop() 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[][])
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
_instantiate初始化注册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__)
SDN实验---Ryu的源码分析的更多相关文章
- SDN实验---Ryu的应用开发(二)Learning Switch
一:自学习交换机(二层MAC交换机)的编程思路 (一)明确问题 如何实现软件定义的自学习交换机? (二)设计解决方案 通过控制器来实现自学习交换算法,然后指导数据平面实现交换机操作 (三)确定具体的技 ...
- Struts2 源码分析——调结者(Dispatcher)之执行action
章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ...
- Vector和Stack源码分析/List集合的总结
序言 这篇文章算是在这list接口下的集合的最后一篇了,前面ArrayList.LinkedList都已经讲解完了,剩下就Vector和Vector的子类Stack啦.继续努力.一步一个脚印, --W ...
- heapster源码分析——kubelet的api调用分析
一.heapster简介 什么是Heapster? Heapster是容器集群监控和性能分析工具,天然的支持Kubernetes和CoreOS.Kubernetes有个出名的监控agent---cAd ...
- Java集合源码分析(三)Vevtor和Stack
前言 前面写了一篇关于的是LinkedList的除了它的数据结构稍微有一点复杂之外,其他的都很好理解的.这一篇讲的可能大家在开发中很少去用到.但是有的时候也可能是会用到的! 注意在学习这一篇之前,需要 ...
- Android源码分析—深入认识AsyncTask内部机制
本文转载http://blog.csdn.net/singwhatiwanna/article/details/17596225该博主博文,谢谢该博主提供的好文章! 前言 什么是AsyncTask,相 ...
- SpringCloud微服务如何优雅停机及源码分析
目录 方式一:kill -9 java进程id[不建议] 方式二:kill -15 java进程id 或 直接使用/shutdown 端点[不建议] kill 与/shutdown 的含义 Sprin ...
- Spring IOC 容器源码分析 - 循环依赖的解决办法
1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...
- Mybatis源码分析之SqlSessionFactory(一)
简介 MyBatis的前身叫iBatis,本是apache的一个开源项目, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBa ...
随机推荐
- linux日志详解-摘录
小编言:会看Linux日志是非常重要的,不仅在日常操作中可以迅速排错,也可以快速的定位.` Liunx的配置文件在/etc/rsyslog.d里,可以看到如下信息这里的意思是将不通的所有优先级的信息输 ...
- linux启动介绍
1. linux内核3.0之前,使用init(初始化 )进程管理的启动程序.一旦升级到3.0(centos7)使用systemd的方式进行管理. 2. 启动模式:启动后执行哪些典型的操作.vi/etc ...
- IDEA 注释模板
类.接口.等文件注释: /** * @Description: * @author: tangsw * @date: ${DATE} ${TIME} * */ 方法上注释: /** * @Descri ...
- Java8新特性之forEach+Lambda 表达式遍历Map和List
这是Java8系列的第二篇,今天来说一下Java8中forEach的简单使用.我们使用对比的方式来看应该会看得更加清楚,更能理解: 一.遍历Map ============Java8之前的方式==== ...
- excel双击下拉制作(以及双击下拉字符超限处理)
最近,在项目的开发过程中,遇到了一个问题,自己要修改代码中的excel模板,有些列要处理成双击下拉的形式. excel制作双击下拉: 当然,我想,这对于大家来说是不难的,好实现,但是,我在制作的过程中 ...
- 第4章 Spring的数据库开发
4.1 Spring JDBC Spring的JDBC模块负责数据库资源管理和错误处理,化简了开发者对数据库的操作. 4.11 Spring JdbcTemplate的解析 * JdbcTemplat ...
- Educational Codeforces F. Remainder Problem
[传送门] 题意就是单点加以及查询下标为等差数列位置上的值之和.刚开始看到这道题.我以为一个数的倍数是log级别的.就直接写了发暴力.就T了.还在想为啥,优化了几发才发现不太对劲.然后才想到是$\df ...
- csp 201903-3 损坏的RAID5
问题描述 试题编号: 201903-3 试题名称: 损坏的RAID5 时间限制: 1.0s 内存限制: 512.0MB 问题描述: 答题栏 核
- uni-app下拉刷新加载刷新数据
onPullDownRefresh监听该页面用户下拉刷新事件需要在 pages.json 里开启 enablePullDownRefresh "globalStyle": { } ...
- Linux常用命令简述--dirname与basename
dirname 获取父目录 basename 显示最后的目录名或文件名 .dirname [root@liang ~]# dirname /etc/httpd/ /etc [root@liang ~] ...