SDN实验---Ryu的源码分析

Posted ssyfj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 cant 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 cant 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 cant 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 cant 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
View Code

最终: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的应用开发北向接口RESTAPI

SDN安装Ryu及GUI,并解决Disconnected问题

SDN安装Ryu及GUI,并解决Disconnected问题

vty_read_config: failed to open configuration file /root/ryu/SDN-IP-Ryu/sdn-ip-topology/quagga-sdn.c

SDN中ryu安装出现的问题

SDN-IP-Ryu