Ryu源碼之模塊功能分析


一:模塊間通信機制分析

Ryu是一款非常輕便的SDN控制器,在科研方面得到了廣泛的應用。相比其他控制器,受益於Python語言,在Ryu上開發SDN應用的效率要遠高於其他控制器。為了解決復雜的業務,有時需要在Ryu上開發多模塊來協同工作,從而共同完成復雜的業務。這里只考慮lookup_service_brick獲取模塊實例對象,從而獲取動態實例對象的數據!!!

以:SDN實驗---Ryu的應用開發(五)網絡拓撲發現為例(TopoDetect.py),作為自定義的app,被加載到一個新的app中(Test.py)

(一)使用lookup_service_brick加載模塊實例時,對於我們自己定義的app(需要被加載的),我們需要在類中定義self.name。

(二)源碼分析: 查看如何使用self.name

參考:SDN實驗---Ryu的源碼分析

1.從main入口查找:ryu/cmd/manager.py

from ryu.base.app_manager import AppManager

def main(args=None, prog=None):
app_lists = CONF.app_lists + CONF.app #從ryu-manager傳入的App參數中獲取app_list (詳細可看參考)---重點:我們需要同時將被加載的類傳入

app_mgr
= AppManager.get_instance() #單例對象,管理所有的app app_mgr.load_apps(app_lists) #加載所有app:重點 contexts = app_mgr.create_contexts() #創建上下文 services = [] services.extend(app_mgr.instantiate_apps(**contexts)) #重點:實例化app----下一步分析 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()

2.app_mgr.instantiate_apps實例化app : ryu.base.app_manager

class AppManager(object):

    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

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

    def instantiate_apps(self, *args, **kwargs):
        for app_name, cls in self.applications_cls.items():  self._instantiate(app_name, cls, *args, **kwargs)

        self._update_bricks()
        self.report_bricks()

        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

    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) #注冊app 重點!!!
        assert app.name not in self.applications
        self.applications[app.name] = app
        return app

3.注冊App實例對象到服務鏈中 :ryu.base.app_manager(與2同文件下)

SERVICE_BRICKS = {}


def lookup_service_brick(name):
    return SERVICE_BRICKS.get(name) #重點2:由重點1可以知道,我們最終將app實例保存在了全局字典中,所以我們可以直接使用該方法獲取對於實例對象,實現模塊之間通信(數據分享)


def _lookup_service_brick_by_ev_cls(ev_cls):
    return _lookup_service_brick_by_mod_name(ev_cls.__module__)


def _lookup_service_brick_by_mod_name(mod_name):
    return lookup_service_brick(mod_name.split('.')[-1])


def register_app(app):
    assert isinstance(app, RyuApp)
    assert app.name not in SERVICE_BRICKS
    SERVICE_BRICKS[app.name] = app #重點1:將app的name成員作為key,app對象作為value放入全局字典中
    register_instance(app)

完結撒花!!!

(三)實例演示

1.Test.py使用lookup_service_brick函數

from ryu.base import app_manager
from ryu.base.app_manager import lookup_service_brick

from ryu.ofproto import ofproto_v1_3

from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER,CONFIG_DISPATCHER,DEAD_DISPATCHER,HANDSHAKE_DISPATCHER #只是表示datapath數據路徑的狀態
from ryu.controller.handler import set_ev_cls

from ryu.topology.switches import Switches
from ryu.topology.switches import LLDPPacket

class Test(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

    def __init__(self,*args,**kwargs):
        super(Test,self).__init__(*args,**kwargs)
        self.name = "delay" self.topology = lookup_service_brick("topology") #注意:我們使用lookup_service_brick加載模塊實例時,對於我們自己定義的app,我們需要在類中定義self.name。   #此外,最重要的是:我們啟動本模塊DelayDetect時,必須同時啟動自定義的模塊!!! 比如:ryu-manager ./TopoDetect.py ./DelayDetect.py --verbose --observe-links
self.switches = lookup_service_brick("switches") #該app是在ryu內部被實例化了,所以我們可以直接加載,同樣還有ofp_event也是被實例化,可以直接加載 @set_ev_cls(ofp_event.EventOFPStateChange,[MAIN_DISPATCHER, DEAD_DISPATCHER]) def _state_change_handler(self, ev):
if self.topology == None: self.topology = lookup_service_brick("topology") print("-----------------------_state_change_handler-----------------------") print(self.topology.show_topology()) #調用lookup_service_brick載入的實力對象

2.啟動Ryu:需要載入對應的自定義模塊

ryu-manager ./Test.py ./TopoDetect.py --verbose --observe-links

查看BRICK name即可發現topology被載入!!

 

對應數據、方法調用成功!!!

完結撒花!!! 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM