一:安装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的源码分析的更多相关文章

  1. SDN实验---Ryu的应用开发(二)Learning Switch

    一:自学习交换机(二层MAC交换机)的编程思路 (一)明确问题 如何实现软件定义的自学习交换机? (二)设计解决方案 通过控制器来实现自学习交换算法,然后指导数据平面实现交换机操作 (三)确定具体的技 ...

  2. Struts2 源码分析——调结者(Dispatcher)之执行action

    章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ...

  3. Vector和Stack源码分析/List集合的总结

    序言 这篇文章算是在这list接口下的集合的最后一篇了,前面ArrayList.LinkedList都已经讲解完了,剩下就Vector和Vector的子类Stack啦.继续努力.一步一个脚印, --W ...

  4. heapster源码分析——kubelet的api调用分析

    一.heapster简介 什么是Heapster? Heapster是容器集群监控和性能分析工具,天然的支持Kubernetes和CoreOS.Kubernetes有个出名的监控agent---cAd ...

  5. Java集合源码分析(三)Vevtor和Stack

    前言 前面写了一篇关于的是LinkedList的除了它的数据结构稍微有一点复杂之外,其他的都很好理解的.这一篇讲的可能大家在开发中很少去用到.但是有的时候也可能是会用到的! 注意在学习这一篇之前,需要 ...

  6. Android源码分析—深入认识AsyncTask内部机制

    本文转载http://blog.csdn.net/singwhatiwanna/article/details/17596225该博主博文,谢谢该博主提供的好文章! 前言 什么是AsyncTask,相 ...

  7. SpringCloud微服务如何优雅停机及源码分析

    目录 方式一:kill -9 java进程id[不建议] 方式二:kill -15 java进程id 或 直接使用/shutdown 端点[不建议] kill 与/shutdown 的含义 Sprin ...

  8. Spring IOC 容器源码分析 - 循环依赖的解决办法

    1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...

  9. Mybatis源码分析之SqlSessionFactory(一)

    简介 MyBatis的前身叫iBatis,本是apache的一个开源项目, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBa ...

随机推荐

  1. yum localinstall 解决本地 rpm 包的依赖问题

    yum localinstall 解决本地 rpm 包的依赖问题 本文原始地址:https://sitoi.cn/posts/13384.html 使用命令: sudo rpm -ivh xxx.rp ...

  2. ELK快速入门(四)filebeat替代logstash收集日志

    ELK快速入门四-filebeat替代logstash收集日志 filebeat简介 Filebeat是轻量级单用途的日志收集工具,用于在没有安装java的服务器上专门收集日志,可以将日志转发到log ...

  3. zabbix--自定义监控项vsftpd

    Zabbix 自定义监控项之监控 vsftpd zabbix 提供了很多监控选择,功能丰富,我们还可以根据自定义来监控想要监控一些日常的服务等. 说明: 此处我们通过监控 ftp (自定义命令),实现 ...

  4. Vue开发之基础路由

    1.router-link和router-view组件 src/App.vie文件内容: <template> <div id="app"> <div ...

  5. V-rep(1)

    第一次课堂作业,需要导入网格三维模型,对齐坐标系,然后在各个关节添加jiont,实现外观模型和运动仿真模型的分离. 1.首先导入模型.导入模型可能是一个整体模型(装配好的),也可能是单个(mesh)网 ...

  6. php怎样应对高并发

    高并发下的数据安全 我们知道在多线程写入同一个文件的时候,会出现“线程安全”的问题(多个线程同时运行同一段代码,如果每次运行结果和单线程运行的结果是一样的,结果和预期相同,就是线程安全的). 如果是M ...

  7. docker 启动失败 Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.

    CentOS7安装docker,安装成功后,启动失败 提示: 我们可以看到此处它提示是Failed to start Docker Application Container Engine. 于是在网 ...

  8. MySQL binlog2sql实现MySQL误操作的恢复

    对于MySQL数据库中的误操作删除数据的恢复问题,可以使用基于MySQL中binlog做到类似于闪回或者生成反向操作的SQL语句来实现,是MySQL中一个非常实用的功能.原理不难理解,基于MySQL的 ...

  9. VisualStudio中集成扩展调试SOS

    SOS扩展也是可以和VisualStudio进行集成的,这样真的方便了我们调试一些性能要求比较高的程序,当程序运行一段时间后我们用VS附加到进程,然后查看一些重要的对象数据,但是此时我们看不到.NET ...

  10. ABP 基本操作

    基本信息: 官网:https://aspnetboilerplate.com api:https://aspnetboilerplate.com/Pages/Documents/Articles-Tu ...