Based on the following patch:

From: Isaku Yamahata <[email protected]>
Subject: dpset: add port{add, delete, modify} event for convenience and helper 
functions

It is sometimes commonly interesting to track datapath/port
appearance/disappearance. The applications usually want to see that ports
appear after datapath becomes ready, and ports disappear when datapath is dead.
It requires to handle properly events, hand shaking, port_mod event,
switch_feature_reply. So introduce a common layer to handle them.

GRE tunnel is interested in datapath/port appearance/disappearance.
With this, tunnel app doesn't have to handle those conditions.
Discovery is 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]>
Signed-off-by: FUJITA Tomonori <[email protected]>
---
 ryu/controller/dpset.py |  108 +++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 100 insertions(+), 8 deletions(-)

diff --git a/ryu/controller/dpset.py b/ryu/controller/dpset.py
index c960906..1660410 100644
--- a/ryu/controller/dpset.py
+++ b/ryu/controller/dpset.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation.
+# Copyright (C) 2012, 2013 Nippon Telegraph and Telephone Corporation.
 # Copyright (C) 2012 Isaku Yamahata <yamahata at valinux co jp>
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,14 +21,13 @@ from ryu.controller import event
 from ryu.controller import ofp_event
 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')
 
 
-DPSET_EV_DISPATCHER = 'dpset'
-
-
 class EventDPBase(event.EventBase):
     def __init__(self, dp):
         super(EventDPBase, self).__init__()
@@ -42,6 +41,42 @@ class EventDP(EventDPBase):
         # False: dp leaving
         super(EventDP, self).__init__(dp)
         self.enter = 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 +90,7 @@ class DPSet(app_manager.RyuApp):
         self.dp_types = {}
 
         self.dps = {}   # datapath_id => class Datapath
+        self.port_state = {}  # datapath_id => ports
 
     def register(self, dp):
         assert dp.id is not None
@@ -65,16 +101,29 @@ class DPSet(app_manager.RyuApp):
             dp.dp_type = dp_type_
 
         self.dps[dp.id] = dp
-        self.send_event_to_observers(EventDP(dp, True))
+        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.send_event_to_observers(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.send_event_to_observers(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.send_event_to_observers(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]
@@ -84,11 +133,17 @@ class DPSet(app_manager.RyuApp):
             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(ofp_event.EventOFPStateChange,
                 [handler.MAIN_DISPATCHER, handler.DEAD_DISPATCHER])
     def dispacher_change(self, ev):
@@ -100,3 +155,40 @@ class DPSet(app_manager.RyuApp):
         elif ev.state == handler.DEAD_DISPATCHER:
             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.send_event_to_observers(EventPortAdd(datapath, port))
+        elif reason == ofproto.OFPPR_DELETE:
+            self._port_deleted(datapath, port)
+            self.send_event_to_observers(EventPortDelete(datapath, port))
+        else:
+            assert reason == ofproto.OFPPR_MODIFY
+            self.port_state[datapath.id].modify(port.port_no, port)
+            self.send_event_to_observers(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.4.4


------------------------------------------------------------------------------
Free Next-Gen Firewall Hardware Offer
Buy your Sophos next-gen firewall before the end March 2013 
and get the hardware for free! Learn more.
http://p.sf.net/sfu/sophos-d2d-feb
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to