1 # Copyright (C) 2011-2014 Nippon Telegraph and Telephone Corporation.
2 # Copyright (C) 2011, 2012 Isaku Yamahata <yamahata at valinux co jp>
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
21 LOG = logging.getLogger('ryu.controller.handler')
23 # just represent OF datapath state. datapath specific so should be moved.
24 HANDSHAKE_DISPATCHER = "handshake"
25 CONFIG_DISPATCHER = "config"
26 MAIN_DISPATCHER = "main"
27 DEAD_DISPATCHER = "dead"
30 class _Caller(object):
31 """Describe how to handle an event class.
34 def __init__(self, dispatchers, ev_source):
35 """Initialize _Caller.
37 :param dispatchers: A list of states or a state, in which this
39 None and [] mean all states.
40 :param ev_source: The module which generates the event.
41 ev_cls.__module__ for set_ev_cls.
42 None for set_ev_handler.
44 self.dispatchers = dispatchers
45 self.ev_source = ev_source
48 # should be named something like 'observe_event'
49 def set_ev_cls(ev_cls, dispatchers=None):
51 A decorator for Ryu application to declare an event handler.
53 Decorated method will become an event handler.
54 ev_cls is an event class whose instances this RyuApp wants to receive.
55 dispatchers argument specifies one of the following negotiation phases
56 (or a list of them) for which events should be generated for this handler.
57 Note that, in case an event changes the phase, the phase before the change
58 is used to check the interest.
60 .. tabularcolumns:: |l|L|
62 =========================================== ===============================
63 Negotiation phase Description
64 =========================================== ===============================
65 ryu.controller.handler.HANDSHAKE_DISPATCHER Sending and waiting for hello
67 ryu.controller.handler.CONFIG_DISPATCHER Version negotiated and sent
68 features-request message
69 ryu.controller.handler.MAIN_DISPATCHER Switch-features message
70 received and sent set-config
72 ryu.controller.handler.DEAD_DISPATCHER Disconnect from the peer. Or
73 disconnecting due to some
75 =========================================== ===============================
77 def _set_ev_cls_dec(handler):
78 if 'callers' not in dir(handler):
80 for e in _listify(ev_cls):
81 handler.callers[e] = _Caller(_listify(dispatchers), e.__module__)
83 return _set_ev_cls_dec
86 def set_ev_handler(ev_cls, dispatchers=None):
87 def _set_ev_cls_dec(handler):
88 if 'callers' not in dir(handler):
90 for e in _listify(ev_cls):
91 handler.callers[e] = _Caller(_listify(dispatchers), None)
93 return _set_ev_cls_dec
96 def _has_caller(meth):
97 return hasattr(meth, 'callers')
100 def _listify(may_list):
103 if not isinstance(may_list, list):
104 may_list = [may_list]
108 def register_instance(i):
109 for _k, m in inspect.getmembers(i, inspect.ismethod):
110 # LOG.debug('instance %s k %s m %s', i, _k, m)
112 for ev_cls, c in m.callers.items():
113 i.register_handler(ev_cls, m)
117 return inspect.isfunction(f) or inspect.ismethod(f)
120 def get_dependent_services(cls):
122 for _k, m in inspect.getmembers(cls, _is_method):
124 for ev_cls, c in m.callers.items():
125 service = getattr(sys.modules[ev_cls.__module__],
126 '_SERVICE_NAME', None)
128 # avoid cls that registers the own events (like
130 if cls.__module__ != service:
131 services.append(service)
133 m = sys.modules[cls.__module__]
134 services.extend(getattr(m, '_REQUIRED_APP', []))
135 services = list(set(services))
139 def register_service(service):
141 Register the ryu application specified by 'service' as
142 a provider of events defined in the calling module.
144 If an application being loaded consumes events (in the sense of
145 set_ev_cls) provided by the 'service' application, the latter
146 application will be automatically loaded.
148 This mechanism is used to e.g. automatically start ofp_handler if
149 there are applications consuming OFP events.
151 frame = inspect.currentframe()
152 m_name = frame.f_back.f_globals['__name__']
153 m = sys.modules[m_name]
154 m._SERVICE_NAME = service