solve application dependency via @set_ev_cls

Currently, ryu always starts ofp application because ryu doesn't know
applications that an user specifies needs ofp application or not. So
you can't run two ryu instances even if one of them doesn't use ofp
application because two instances tries to listen the same port.

The root problem is that there is no way to represent dependency
between applications. The patch to invent our own json format to
represent such was proposed ago but I'm still not sure we really need
such complicity.

This tries to solve the problem simply. A module defining events for
an application calls register_service() to declare which application
generates the events, e.g., ofp_event.py call register_service() with
'ofp_handler' argument. If an application starts including @set_ev_cls
for ofp_event, ryu-manager starts ofp application (ofp_handler).

Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
FUJITA Tomonori 2013-11-17 09:42:01 +09:00
parent 47f1d19538
commit 73ae9dd109
5 changed files with 54 additions and 16 deletions

View File

@ -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()

View File

@ -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:

View File

@ -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()

View File

@ -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

View File

@ -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')