For discovery, it's interested only in datapath/port appearance/disappearance. With this, discovery app would not have to handle OFP events directly.
Signed-off-by: Isaku Yamahata <[email protected]> --- Changes v3 -> v4: - don't use cork/uncork stuff. Changes v2 -> v3: - track port status change properly So far it isn't tracked. If port status is changed before entering MAIN_HANDLER after switch feature status, the controller's view and the actual port status doesn't match. So have to track ports status until MAIN_HANDLER. - fix Port{Add, Del, Modify} race When dispatching those event, the thread can be switched or other EventQueue can be served. There was a race between Port{Add, Del, Modify}. Changes v1 -> v2: - generate port add/del event when datapath appears With this change, the user don't have to handle EventDP with 'for port in ...' Thus the user code will be simplified. - some helper functions which will be used later dpset: remove cork/uncork Signed-off-by: Isaku Yamahata <[email protected]> --- ryu/controller/dpset.py | 105 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 100 insertions(+), 5 deletions(-) diff --git a/ryu/controller/dpset.py b/ryu/controller/dpset.py index 80ffb6f..0d69526 100644 --- a/ryu/controller/dpset.py +++ b/ryu/controller/dpset.py @@ -20,7 +20,9 @@ from ryu.controller import event from ryu.controller import dispatcher from ryu.controller import dp_type from ryu.controller import handler +from ryu.controller import ofp_event from ryu.controller.handler import set_ev_cls +import ryu.exception as ryu_exc LOG = logging.getLogger('ryu.controller.dpset') @@ -42,7 +44,43 @@ class EventDP(EventDPBase): # True: dp entered # False: dp leaving super(EventDP, self).__init__(dp) - self.enter = enter_leave + self.enter_leave = enter_leave + self.ports = [] # port list when enter or leave + + +class EventPortBase(EventDPBase): + def __init__(self, dp, port): + super(EventPortBase, self).__init__(dp) + self.port = port + + +class EventPortAdd(EventPortBase): + def __init__(self, dp, port): + super(EventPortAdd, self).__init__(dp, port) + + +class EventPortDelete(EventPortBase): + def __init__(self, dp, port): + super(EventPortDelete, self).__init__(dp, port) + + +class EventPortModify(EventPortBase): + def __init__(self, dp, new_port): + super(EventPortModify, self).__init__(dp, new_port) + + +class PortState(dict): + def __init__(self): + super(PortState, self).__init__() + + def add(self, port_no, port): + self[port_no] = port + + def remove(self, port_no): + del self[port_no] + + def modify(self, port_no, port): + self[port_no] = port # this depends on controller::Datapath and dispatchers in handler @@ -55,6 +93,7 @@ class DPSet(object): self.dp_types = {} self.dps = {} # datapath_id => class Datapath + self.port_state = {} # datapath_id => ports self.ev_q = dispatcher.EventQueue(QUEUE_NAME_DPSET, DPSET_EV_DISPATCHER) handler.register_instance(self) @@ -67,17 +106,30 @@ class DPSet(object): if dp_type_ is not None: dp.dp_type = dp_type_ - self.ev_q.queue(EventDP(dp, True)) self.dps[dp.id] = dp + self.port_state[dp.id] = PortState() + + ev = EventDP(dp, True) + for port in dp.ports.values(): + self._port_added(dp, port) + ev.ports.append(port) + self.ev_q.queue(ev) def unregister(self, dp): + # Now datapath is already dead, so port status change event doesn't + # interfere us. + ev = EventDP(dp, False) + for port in self.port_state.get(dp.id, {}).values(): + self._port_deleted(dp, port) + ev.ports.append(port) + self.ev_q.queue(ev) + if dp.id in self.dps: del self.dps[dp.id] + del self.port_state[dp.id] assert dp.id not in self.dp_types self.dp_types[dp.id] = getattr(dp, 'dp_type', dp_type.UNKNOWN) - self.ev_q.queue(EventDP(dp, False)) - def set_type(self, dp_id, dp_type_=dp_type.UNKNOWN): if dp_id in self.dps: dp = self.dps[dp_id] @@ -87,11 +139,17 @@ class DPSet(object): self.dp_types[dp_id] = dp_type_ def get(self, dp_id): - return self.dps.get(dp_id, None) + return self.dps.get(dp_id) def get_all(self): return self.dps.items() + def _port_added(self, datapath, port): + self.port_state[datapath.id].add(port.port_no, port) + + def _port_deleted(self, datapath, port): + self.port_state[datapath.id].remove(port.port_no) + @set_ev_cls(dispatcher.EventDispatcherChange, dispatcher.QUEUE_EV_DISPATCHER) def dispacher_change(self, ev): @@ -108,3 +166,40 @@ class DPSet(object): elif ev.new_dispatcher.name == handler.DISPATCHER_NAME_OFP_DEAD: LOG.debug('DPSET: unregister datapath %s', datapath) self.unregister(datapath) + + @set_ev_cls(ofp_event.EventOFPSwitchFeatures, handler.CONFIG_DISPATCHER) + def switch_features_handler(self, ev): + msg = ev.msg + datapath = msg.datapath + datapath.ports = msg.ports + + @set_ev_cls(ofp_event.EventOFPPortStatus, handler.MAIN_DISPATCHER) + def port_status_handler(self, ev): + msg = ev.msg + reason = msg.reason + datapath = msg.datapath + port = msg.desc + ofproto = datapath.ofproto + + LOG.debug('port status %s', reason) + + if reason == ofproto.OFPPR_ADD: + self._port_added(datapath, port) + self.ev_q.queue(EventPortAdd(datapath, port)) + elif reason == ofproto.OFPPR_DELETE: + self._port_deleted(datapath, port) + self.ev_q.queue(EventPortDelete(datapath, port)) + else: + assert reason == ofproto.OFPPR_MODIFY + self.port_state[datapath.id].modify(port.port_no, port) + self.ev_q.queue(EventPortModify(datapath, port)) + + def get_port(self, dpid, port_no): + try: + return self.port_state[dpid][port_no] + except KeyError: + raise ryu_exc.PortNotFound(dpid=dpid, port=port_no, + network_id=None) + + def get_ports(self, dpid): + return self.port_state[dpid].values() -- 1.7.10.4 ------------------------------------------------------------------------------ Don't let slow site performance ruin your business. Deploy New Relic APM Deploy New Relic app performance management and know exactly what is happening inside your Ruby, Python, PHP, Java, and .NET app Try New Relic at no cost today and get our sweet Data Nerd shirt too! http://p.sf.net/sfu/newrelic-dev2dev _______________________________________________ Ryu-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ryu-devel
