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(含目录介绍)

三:源码分析流程

Ryu的源码分析

四:找入口函数main

(一)我们编写的应用:全部继承于app_manager.RyuApp----去看他

from ryu.base import app_manager

class Hub(app_manager.RyuApp):
    pass

Ryu的源码分析

没有找到主函数main!!!! 

(二)我们启动Ryu的常用方式

ryu-manager simple_switch_13.py --verbose

Ryu的源码分析

通过终端输入,启动Ryu控制器。因此我们进入cmd目录中

cmd目录定义了RYU的命令系统

Ryu的源码分析

Ryu的源码分析 

我们在该文件目录下的两个文件中都找到了main函数-----Ok  反正是找到了main函数

(三)使用Ctrl+B查找调用main函数的位置

1.ryu_base.py查找

Ryu的源码分析

Ryu的源码分析

在主目录下的bin目录的ryu文件中,调用了主函数main

Ryu的源码分析

2.在manager.py中查找

Ryu的源码分析 

Ryu的源码分析 

在主目录下的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的源码分析

Ryu的源码分析 

ryu命令主要为我们提供了,文档类信息。当然我们可以看到其中有一个run命令--我们可以通过这个命令实现ryu-manager命令

ryu run ./simple_switch_13.py --verbose

Ryu的源码分析

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项目进行重新编译安装

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全部代码

相关文章: