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(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

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) > 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

_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__)

原文地址:https://www.cnblogs.com/ssyfj/p/11768824.html

时间: 2024-07-31 10:25:34

SDN实验---Ryu的源码分析的相关文章

Android逆向之旅---反编译利器Apktool和Jadx源码分析以及错误纠正

一.前言 在之前的破解过程中可以看到我们唯一离不开的一个神器那就是apktool了,这个工具多强大就不多说了,但是如果没有他我们没法涉及到后面的破解工作了,这个工具是开源的,也是使用Java语言开发的,代码相对简单,我们今天就来分析一下他的大体逻辑,注意是大体逻辑哦,因为如果要一行一行代码分析,首先觉得没必要,其次浪费时间,有了源码,谁看不懂呢.至于为什么要分析这个工具其实原因只有一个,就是我们在之前的反编译过程中会发现,总是有那么几个apk应用不让我们那么容易的反编译,他们就利用apktool

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

章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行action呢?本章笔者就带大家来看看StrutsExecuteFilter类的工作.在理解StrutsExecuteFilter类的工作之前,笔者还是希望大家回顾一下前一章讲到的request请求工作.为什么这样子讲呢?可以说StrutsExecuteFilter类的工作是建立在StrutsPrep

Nouveau源码分析(三):NVIDIA设备初始化之nouveau_drm_probe

Nouveau源码分析(三) 向DRM注册了Nouveau驱动之后,内核中的PCI模块就会扫描所有没有对应驱动的设备,然后和nouveau_drm_pci_table对照. 对于匹配的设备,PCI模块就调用对应的probe函数,也就是nouveau_drm_probe. // /drivers/gpu/drm/nouveau/nouveau_drm.c 281 static int nouveau_drm_probe(struct pci_dev *pdev, 282 const struct

tomcat源码分析前的准备工作

Tomcat源码学习前的准备工作 注:由于网上的帖子大部分没有配套的图片和错误的分析,所有费了半天劲整理了此篇博客,希望大家少走弯路吧 下面我们就开始我们的Tomcat源码学习之旅. 1. 下载Tomcat6.0的源代码 首先,我们得下载Tomcat6.0的源代码.Tomcat源代码的版本控制工具不是CVS,而是Subversion,如果您的机器上没有安装Subversion,请从http://subversion.tigris.org/servlets/ProjectDocumentList?

Opencv2.4.9源码分析——Cascade Classification(三)

前两篇文章分别介绍了级联分类器的原理和源码解析,下面我们给出一个具体的应用实例. 下面我们以车牌识别为例,具体讲解OpenCV的级联分类器的用法.在这里我们只对蓝底白字的普通车牌进行识别判断,对于其他车牌不在考虑范围内.而且车牌是正面照,略微倾斜可以,倾斜程度太大也是不在识别范围内的. 我们通过不同渠道共收集了1545幅符合要求的带有车牌图像的照片(很遗憾,我只能得到这么多车牌照片,如果能再多一些就更好了!),通过ACDSee软件手工把车牌图像从照片中剪切出来,并统一保存为jpg格式.为便于后续

WEKA学习——CSVLoader 实例训练 和 源码分析

简介: Weka支持多种数据导入方式,CSVLoader是能从csv文件加载数据集,也可以保存为arff格式文件.官方介绍文件:Converting CSV to ARFF ( http://weka.wikispaces.com/Converting+CSV+to+ARFF) CSVLoader加载文件,关键是对文件字段属性名称和属性的类型需要自己定义,这样才能得到满足自己需要的数据集. CSVLoader通过options设置,可以设置每一列的属性为Nominal,String,Date类型

leveldb源码分析--SSTable之Compaction

对于compaction是leveldb中体量最大的一部分,也应该是最为复杂的部分,为了便于理解我们首先从一些基本的概念开始.下面是一些从doc/impl.html中翻译和整理的内容: Level 0 当日志文件超过一定大小的阈值是 (默认为 1MB): 建立一个新的memtable和日志文件,以后的操作都是用新的memtable和日志文件 后台进行如下操作: 将旧的 memtable写到SSTable中(过程为先转为immtable_table,然后遍历写入) 废弃旧的 memtable 删除

Tinker 源码分析之DexDiff / DexPatch

本文已在我的公众号hongyangAndroid首发. 转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/60874334 本文出自张鸿洋的博客 在上一篇文章中,我们介绍了Android 热修复 Tinker接入及源码浅析,里面包含了热修的一些背景知识,从tinker对dex文件的处理来看,源码大体上可以分为3部分阅读: 在应用中对patch的合并与加载,已经在上篇文章中详细介绍过了Android 热修复 Tinker接入及源码

Android 热修复 Tinker 源码分析之DexDiff / DexPatch

在上一篇文章中,我们介绍了Android 热修复 Tinker接入及源码浅析,里面包含了热修的一些背景知识,从tinker对dex文件的处理来看,源码大体上可以分为3部分阅读: 在应用中对patch的合并与加载,已经在上篇文章中详细介绍过了Android 热修复 Tinker接入及源码浅析 详细的dex patch,dex diff算法 tinker gradle plugin相关知识 tinker有个非常大的亮点就是自研发了一套dex diff.patch相关算法.本篇文章主要目的就是分析该算