diff --git a/ryu/base/app_manager.py b/ryu/base/app_manager.py index b39d6cc2..a5f1c4cf 100644 --- a/ryu/base/app_manager.py +++ b/ryu/base/app_manager.py @@ -17,9 +17,10 @@ import inspect import itertools import logging +import sys from ryu import utils -from ryu.controller.handler import register_instance +from ryu.controller.handler import register_instance, get_dependent_services from ryu.controller.controller import Datapath from ryu.controller.event import EventRequestBase, EventReplyBase from ryu.lib import hub @@ -158,15 +159,13 @@ class AppManager(object): return None def load_apps(self, app_lists): - for app_cls_name in itertools.chain.from_iterable([app_list.split(',') - for app_list - in app_lists]): - LOG.info('loading app %s', app_cls_name) + 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) - # for now, only single instance of a given module - # Do we need to support multiple instances? - # Yes, maybe for slicing. - assert app_cls_name not in self.applications_cls + LOG.info('loading app %s', app_cls_name) cls = self.load_app(app_cls_name) if cls is None: @@ -174,10 +173,18 @@ class AppManager(object): self.applications_cls[app_cls_name] = cls + services = [] for key, context_cls in cls.context_iteritems(): cls = self.contexts_cls.setdefault(key, context_cls) assert cls == context_cls + if issubclass(context_cls, RyuApp): + services.extend(get_dependent_services(context_cls)) + + services.extend(get_dependent_services(cls)) + if services: + app_lists.extend(services) + def create_contexts(self): for key, cls in self.contexts_cls.items(): context = cls() diff --git a/ryu/cmd/manager.py b/ryu/cmd/manager.py index cc1ea747..83867054 100755 --- a/ryu/cmd/manager.py +++ b/ryu/cmd/manager.py @@ -61,8 +61,7 @@ def main(): log.init_log() - # always enable ofp for now. - app_lists = CONF.app_lists + CONF.app + ['ryu.controller.ofp_handler'] + app_lists = CONF.app_lists + CONF.app app_mgr = AppManager() app_mgr.load_apps(app_lists) @@ -71,9 +70,11 @@ def main(): services = [] - ctlr = controller.OpenFlowController() - thr = hub.spawn(ctlr) - services.append(thr) + # TODO: do the following in app_manager's instantiate_apps() + ofpapp = controller.start_service(app_mgr) + if ofpapp: + thr = hub.spawn(ofpapp) + services.append(thr) webapp = wsgi.start_service(app_mgr) if webapp: diff --git a/ryu/controller/controller.py b/ryu/controller/controller.py index d6bc3def..fc6e1168 100644 --- a/ryu/controller/controller.py +++ b/ryu/controller/controller.py @@ -321,3 +321,9 @@ def datapath_connection_factory(socket, address): dpid_str = dpid_to_str(datapath.id) LOG.error("Error in the datapath %s from %s", dpid_str, address) raise + + +def start_service(app_mgr): + for app in app_mgr.applications: + if app.endswith('ofp_handler'): + return OpenFlowController() diff --git a/ryu/controller/handler.py b/ryu/controller/handler.py index ba45b0dc..d5f57cda 100644 --- a/ryu/controller/handler.py +++ b/ryu/controller/handler.py @@ -16,8 +16,7 @@ import inspect import logging - -from ryu.controller import ofp_event +import sys LOG = logging.getLogger('ryu.controller.handler') @@ -63,3 +62,24 @@ def register_instance(i): # LOG.debug('instance %s k %s m %s', i, _k, m) if _is_ev_cls(m): i.register_handler(m.ev_cls, m) + + +def get_dependent_services(cls): + services = [] + for _k, m in inspect.getmembers(cls, inspect.ismethod): + if _is_ev_cls(m): + service = getattr(sys.modules[m.ev_cls.__module__], + '_SERVICE_NAME', None) + if service: + # avoid cls that registers the own events (like ofp_handler) + if cls.__module__ != service: + services.append(service) + + services = list(set(services)) + return services + + +def register_service(service): + frm = inspect.stack()[1] + m = inspect.getmodule(frm[0]) + m._SERVICE_NAME = service diff --git a/ryu/controller/ofp_event.py b/ryu/controller/ofp_event.py index 566b834d..124a93e7 100644 --- a/ryu/controller/ofp_event.py +++ b/ryu/controller/ofp_event.py @@ -16,6 +16,7 @@ import inspect +from ryu.controller import handler from ryu import ofproto from ryu import utils from . import event @@ -75,3 +76,6 @@ class EventOFPStateChange(event.EventBase): def __init__(self, dp): super(EventOFPStateChange, self).__init__() self.datapath = dp + + +handler.register_service('ryu.controller.ofp_handler')