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