backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / controller / dpset.py
diff --git a/ryu/build/lib.linux-armv7l-2.7/ryu/controller/dpset.py b/ryu/build/lib.linux-armv7l-2.7/ryu/controller/dpset.py
new file mode 100644 (file)
index 0000000..45ead0e
--- /dev/null
@@ -0,0 +1,347 @@
+# 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");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Manage switches.
+
+Planned to be replaced by ryu/topology.
+"""
+
+import logging
+import warnings
+
+from ryu.base import app_manager
+from ryu.controller import event
+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
+
+from ryu.lib.dpid import dpid_to_str
+
+LOG = logging.getLogger('ryu.controller.dpset')
+
+DPSET_EV_DISPATCHER = "dpset"
+
+
+class EventDPBase(event.EventBase):
+    def __init__(self, dp):
+        super(EventDPBase, self).__init__()
+        self.dp = dp
+
+
+class EventDP(EventDPBase):
+    """
+    An event class to notify connect/disconnect of a switch.
+
+    For OpenFlow switches, one can get the same notification by observing
+    ryu.controller.ofp_event.EventOFPStateChange.
+    An instance has at least the following attributes.
+
+    ========= =================================================================
+    Attribute Description
+    ========= =================================================================
+    dp        A ryu.controller.controller.Datapath instance of the switch
+    enter     True when the switch connected to our controller.  False for
+              disconnect.
+    ports     A list of port instances.
+    ========= =================================================================
+    """
+
+    def __init__(self, dp, enter_leave):
+        # enter_leave
+        # True: dp entered
+        # False: dp leaving
+        super(EventDP, self).__init__(dp)
+        self.enter = enter_leave
+        self.ports = []  # port list when enter or leave
+
+
+class EventDPReconnected(EventDPBase):
+    def __init__(self, dp):
+        super(EventDPReconnected, self).__init__(dp)
+        # port list, which should not change across reconnects
+        self.ports = []
+
+
+class EventPortBase(EventDPBase):
+    def __init__(self, dp, port):
+        super(EventPortBase, self).__init__(dp)
+        self.port = port
+
+
+class EventPortAdd(EventPortBase):
+    """
+    An event class for switch port status "ADD" notification.
+
+    This event is generated when a new port is added to a switch.
+    For OpenFlow switches, one can get the same notification by observing
+    ryu.controller.ofp_event.EventOFPPortStatus.
+    An instance has at least the following attributes.
+
+    ========= =================================================================
+    Attribute Description
+    ========= =================================================================
+    dp        A ryu.controller.controller.Datapath instance of the switch
+    port      port number
+    ========= =================================================================
+    """
+
+    def __init__(self, dp, port):
+        super(EventPortAdd, self).__init__(dp, port)
+
+
+class EventPortDelete(EventPortBase):
+    """
+    An event class for switch port status "DELETE" notification.
+
+    This event is generated when a port is removed from a switch.
+    For OpenFlow switches, one can get the same notification by observing
+    ryu.controller.ofp_event.EventOFPPortStatus.
+    An instance has at least the following attributes.
+
+    ========= =================================================================
+    Attribute Description
+    ========= =================================================================
+    dp        A ryu.controller.controller.Datapath instance of the switch
+    port      port number
+    ========= =================================================================
+    """
+
+    def __init__(self, dp, port):
+        super(EventPortDelete, self).__init__(dp, port)
+
+
+class EventPortModify(EventPortBase):
+    """
+    An event class for switch port status "MODIFY" notification.
+
+    This event is generated when some attribute of a port is changed.
+    For OpenFlow switches, one can get the same notification by observing
+    ryu.controller.ofp_event.EventOFPPortStatus.
+    An instance has at least the following attributes.
+
+    ========= ====================================================================
+    Attribute Description
+    ========= ====================================================================
+    dp        A ryu.controller.controller.Datapath instance of the switch
+    port      port number
+    ========= ====================================================================
+    """
+
+    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
+class DPSet(app_manager.RyuApp):
+    """
+    DPSet application manages a set of switches (datapaths)
+    connected to this controller.
+
+    Usage Example::
+
+        # ...(snip)...
+        from ryu.controller import dpset
+
+
+        class MyApp(app_manager.RyuApp):
+            _CONTEXTS = {
+                'dpset': dpset.DPSet,
+            }
+
+            def __init__(self, *args, **kwargs):
+                super(MyApp, self).__init__(*args, **kwargs)
+                # Stores DPSet instance to call its API in this app
+                self.dpset = kwargs['dpset']
+
+            def _my_handler(self):
+                # Get the datapath object which has the given dpid
+                dpid = 1
+                dp = self.dpset.get(dpid)
+                if dp is None:
+                    self.logger.info('No such datapath: dpid=%d', dpid)
+    """
+
+    def __init__(self, *args, **kwargs):
+        super(DPSet, self).__init__(*args, **kwargs)
+        self.name = 'dpset'
+
+        self.dps = {}   # datapath_id => class Datapath
+        self.port_state = {}  # datapath_id => ports
+
+    def _register(self, dp):
+        LOG.debug('DPSET: register datapath %s', dp)
+        assert dp.id is not None
+
+        # while dpid should be unique, we need to handle duplicates here
+        # because it's entirely possible for a switch to reconnect us
+        # before we notice the drop of the previous connection.
+        # in that case,
+        # - forget the older connection as it likely will disappear soon
+        # - do not send EventDP leave/enter events
+        # - keep the PortState for the dpid
+        send_dp_reconnected = False
+        if dp.id in self.dps:
+            self.logger.warning('DPSET: Multiple connections from %s',
+                                dpid_to_str(dp.id))
+            self.logger.debug('DPSET: Forgetting datapath %s', self.dps[dp.id])
+            (self.dps[dp.id]).close()
+            self.logger.debug('DPSET: New datapath %s', dp)
+            send_dp_reconnected = True
+        self.dps[dp.id] = dp
+        if dp.id not in self.port_state:
+            self.port_state[dp.id] = PortState()
+            ev = EventDP(dp, True)
+            with warnings.catch_warnings():
+                warnings.simplefilter('ignore')
+                for port in dp.ports.values():
+                    self._port_added(dp, port)
+                    ev.ports.append(port)
+            self.send_event_to_observers(ev)
+        if send_dp_reconnected:
+            ev = EventDPReconnected(dp)
+            ev.ports = self.port_state.get(dp.id, {}).values()
+            self.send_event_to_observers(ev)
+
+    def _unregister(self, dp):
+        # see the comment in _register().
+        if dp not in self.dps.values():
+            return
+        LOG.debug('DPSET: unregister datapath %s', dp)
+        assert self.dps[dp.id] == dp
+
+        # Now datapath is already dead, so port status change event doesn't
+        # interfere us.
+        ev = EventDP(dp, False)
+        for port in list(self.port_state.get(dp.id, {}).values()):
+            self._port_deleted(dp, port)
+            ev.ports.append(port)
+
+        self.send_event_to_observers(ev)
+
+        del self.dps[dp.id]
+        del self.port_state[dp.id]
+
+    def get(self, dp_id):
+        """
+        This method returns the ryu.controller.controller.Datapath
+        instance for the given Datapath ID.
+        """
+        return self.dps.get(dp_id)
+
+    def get_all(self):
+        """
+        This method returns a list of tuples which represents
+        instances for switches connected to this controller.
+        The tuple consists of a Datapath ID and an instance of
+        ryu.controller.controller.Datapath.
+
+        A return value looks like the following::
+
+            [ (dpid_A, Datapath_A), (dpid_B, Datapath_B), ... ]
+        """
+        return list(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 dispatcher_change(self, ev):
+        datapath = ev.datapath
+        assert datapath is not None
+        if ev.state == handler.MAIN_DISPATCHER:
+            self._register(datapath)
+        elif ev.state == handler.DEAD_DISPATCHER:
+            self._unregister(datapath)
+
+    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, handler.CONFIG_DISPATCHER)
+    def switch_features_handler(self, ev):
+        msg = ev.msg
+        datapath = msg.datapath
+        # ofp_handler.py does the following so we could remove...
+        if datapath.ofproto.OFP_VERSION < 0x04:
+            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
+
+        if reason == ofproto.OFPPR_ADD:
+            LOG.debug('DPSET: A port was added.' +
+                      '(datapath id = %s, port number = %s)',
+                      dpid_to_str(datapath.id), port.port_no)
+            self._port_added(datapath, port)
+            self.send_event_to_observers(EventPortAdd(datapath, port))
+        elif reason == ofproto.OFPPR_DELETE:
+            LOG.debug('DPSET: A port was deleted.' +
+                      '(datapath id = %s, port number = %s)',
+                      dpid_to_str(datapath.id), port.port_no)
+            self._port_deleted(datapath, port)
+            self.send_event_to_observers(EventPortDelete(datapath, port))
+        else:
+            assert reason == ofproto.OFPPR_MODIFY
+            LOG.debug('DPSET: A port was modified.' +
+                      '(datapath id = %s, port number = %s)',
+                      dpid_to_str(datapath.id), port.port_no)
+            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):
+        """
+        This method returns the ryu.controller.dpset.PortState
+        instance for the given Datapath ID and the port number.
+        Raises ryu_exc.PortNotFound if no such a datapath connected to
+        this controller or no such a port exists.
+        """
+        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):
+        """
+        This method returns a list of ryu.controller.dpset.PortState
+        instances for the given Datapath ID.
+        Raises KeyError if no such a datapath connected to this controller.
+        """
+        return list(self.port_state[dpid].values())
+
+
+handler.register_service('ryu.controller.dpset')