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 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
---
 ryu/controller/dpset.py |   99 +++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 95 insertions(+), 4 deletions(-)

diff --git a/ryu/controller/dpset.py b/ryu/controller/dpset.py
index 80ffb6f..915aae2 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,42 @@ class EventDP(EventDPBase):
         # True: dp entered
         # False: dp leaving
         super(EventDP, self).__init__(dp)
-        self.enter = enter_leave
+        self.enter_leave = enter_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,8 +92,10 @@ 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)
 
     def register(self, dp):
@@ -67,17 +106,28 @@ 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()
+        self.ev_q.queue(EventDP(dp, True))
+
+        # generate port_add event for convenience
+        # so that the user don't have to handle dp enter event
+        for port in dp.ports.values():
+            self._port_added(dp, port)
 
     def unregister(self, dp):
+        # generate port_del event for convenience
+        # so that the user don't have to handle dp leave event
+        for port in self.port_state.get(dp.id, {}).values():
+            self._port_deleted(dp, port)
+
         if dp.id in self.dps:
+            self.ev_q.queue(EventDP(dp, False))
             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]
@@ -92,6 +142,14 @@ class DPSet(object):
     def get_all(self):
         return self.dps.items()
 
+    def _port_added(self, datapath, port):
+        self.port_state[datapath.id].add(port.port_no, port)
+        self.ev_q.queue(EventPortAdd(datapath, port))
+
+    def _port_deleted(self, datapath, port):
+        self.port_state[datapath.id].remove(port.port_no)
+        self.ev_q.queue(EventPortDelete(datapath, port))
+
     @set_ev_cls(dispatcher.EventDispatcherChange,
                 dispatcher.QUEUE_EV_DISPATCHER)
     def dispacher_change(self, ev):
@@ -108,3 +166,36 @@ 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.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)
+        elif reason == ofproto.OFPPR_DELETE:
+            self._port_deleted(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_port_state(self, dpid, port_no):
+        port = self.get_port(dpid, port_no)
+        return port.state
+
+    def get_ports(self, dpid):
+        return self.port_state[dpid].itervalues()
-- 
1.7.1.1


------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to