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

Reply via email to