This application provides VLAN separation with ovs tag function.
Something similar openstack quantum openvswitch vlan function.

Example to run:
ryu-manager ryu/app/simple_vlan.py \
            ryu/app/quantum_adapter.py \
            ryu/app/rest.py \
            ryu/app/rest_conf_switch.py \
            ryu/app/rest_tunnel.py \
            ryu/app/rest_quantum.py

Signed-off-by: Isaku Yamahata <[email protected]>
---
 ryu/app/simple_vlan.py |  257 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 257 insertions(+)
 create mode 100644 ryu/app/simple_vlan.py

diff --git a/ryu/app/simple_vlan.py b/ryu/app/simple_vlan.py
new file mode 100644
index 0000000..ef000e1
--- /dev/null
+++ b/ryu/app/simple_vlan.py
@@ -0,0 +1,257 @@
+# Copyright (C) 2012 Nippon Telegraph and Telephone Corporation.
+# Copyright (C) 2012 Isaku Yamahata <yamahata at private email ne 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.
+
+import gevent
+import logging
+
+from ryu.app import (conf_switch_key,
+                     rest_nw_id)
+from ryu.base import app_manager
+from ryu.controller import (conf_switch,
+                            dispatcher,
+                            dpset,
+                            handler,
+                            handler_utils,
+                            network,
+                            tunnels)
+import ryu.exception as ryu_exc
+from ryu.lib import task_queue
+from ryu.lib.ovs import bridge
+from ryu.ofproto import nx_match
+
+
+LOG = logging.getLogger(__name__)
+
+
+def _is_reserved_port(dp, port_no):
+    return port_no > dp.ofproto.OFPP_MAX
+
+
+# serialize events to avoid race
+class SimpleVLANQueue(handler_utils.QueueSerializer):
+    _QUEUE_NAME_SIMPLE_VLAN = '_simple_vlan'
+    _DISPATCHER_NAME_SIMPLE_VLAN = '_simple_vlan'
+    SIMPLE_VLAN_EV_DISPATCHER = dispatcher.EventDispatcher(
+        _DISPATCHER_NAME_SIMPLE_VLAN)
+
+    _EV_CLSES = (
+        (dpset.EventDP, dpset.DPSET_EV_DISPATCHER),
+        (dpset.EventPortAdd, dpset.DPSET_EV_DISPATCHER),
+        (dpset.EventPortDelete, dpset.DPSET_EV_DISPATCHER),
+        (network.EventNetworkPort, network.NETWORK_TENANT_EV_DISPATCHER),
+        (tunnels.EventTunnelKeyAdd, tunnels.TUNNEL_EV_DISPATCHER),
+        (conf_switch.EventConfSwitchSet,
+         conf_switch.CONF_SWITCH_EV_DISPATCHER),
+    )
+
+    def __init__(self):
+        super(SimpleVLANQueue, self).__init__(self._QUEUE_NAME_SIMPLE_VLAN,
+                                              self.SIMPLE_VLAN_EV_DISPATCHER,
+                                              self._EV_CLSES)
+
+
+class SimpleVLAN(app_manager.RyuApp):
+    _CONTEXTS = {
+        'conf_switch': conf_switch.ConfSwitchSet,
+        'dpset': dpset.DPSet,
+        'netowrk': network.Network,
+        'tunnels': tunnels.Tunnels,
+    }
+
+    _PRIORITY_CATCHALL = 1
+    _PRIORITY_DROP = 2
+    _COOKIE_DEFAULT = 0
+
+    def __init__(self, *args, **kwargs):
+        super(SimpleVLAN, self).__init__(*args, **kwargs)
+        self.conf_sw = kwargs['conf_switch']
+        self.dpset = kwargs['dpset']
+        self.nw = kwargs['network']
+        self.tunnels = kwargs['tunnels']
+
+        self.simple_vlan_q = SimpleVLANQueue()
+        self.task_q = task_queue.TaskQueue()
+
+    @handler.set_ev_cls(dpset.EventDP,
+                        SimpleVLANQueue.SIMPLE_VLAN_EV_DISPATCHER)
+    def dp_handler(self, ev):
+        if not ev.enter_leave:
+            return
+
+        dp = ev.dp
+        rule = nx_match.ClsRule()
+        ofproto = dp.ofproto
+        actions = [dp.ofproto_parser.OFPActionOutput(ofproto.OFPP_NORMAL)]
+        self.task_q.queue(
+            lambda: dp.send_flow_mod(rule=rule,
+                                     cookie=self._COOKIE_DEFAULT,
+                                     command=ofproto.OFPFC_ADD,
+                                     idle_timeout=0, hard_timeout=0,
+                                     priority=self._PRIORITY_CATCHALL,
+                                     actions=actions))
+        for port in ev.ports:
+            self._port_add(dp, port.port_no)
+
+    # There is no ordering between those events
+    #   port creation: PortAdd event
+    #   network_id assignment: NetworkPort event
+    #   tunnel_key assignment: TunnelKeyAdd event
+    #   ovsdb_addr: EventConfSwitchSet
+    # So on each events, check all necessary parameters are setup
+    def _port_setup(self, dp, port_no, tunnel_key):
+        if _is_reserved_port(dp, port_no):
+            return
+
+        dpid = dp.id
+        try:
+            port = self.dpset.get_port(dpid, port_no)
+        except ryu_exc.PortNotFound:
+            LOG.debug('port not found')
+            return
+
+        try:
+            ovsdb_addr = self.conf_sw.get_key(dpid, conf_switch_key.OVSDB_ADDR)
+        except KeyError:
+            LOG.debug('ovsdb_addr not found')
+            return
+
+        def ovs_port_update():
+            LOG.debug('ovs_port_update')
+            # ovs-vsctl --db=ovsdb_addr --timeout=2
+            # set Port port.name tag=tunnel_key
+            ovs_br = bridge.OVSBridge(dpid, ovsdb_addr, 2)
+            # ofp_phy_port::name is zero-padded
+            port_name = port.name.rstrip('\x00')
+            try:
+                ovs_br.set_db_attribute("Port", port_name, "tag", tunnel_key)
+            except gevent.Timeout:
+                LOG.error('timout')
+                return
+
+            self._port_flow_del(dp, port_no)
+        self.task_q.queue(ovs_port_update)
+
+        return True
+
+    def _port_setup_netid(self, dpid, port_no, network_id):
+        LOG.debug('_port_setup_netid %x %s %s', dpid, port_no, network_id)
+        dp = self.dpset.get(dpid)
+        if dp is None:
+            LOG.debug('dp not found')
+            return
+
+        if network_id == rest_nw_id.NW_ID_EXTERNAL:
+            LOG.debug('external interface')
+            self._port_flow_del(dp, port_no)
+            return True
+
+        try:
+            tunnel_key = self.tunnels.get_key(network_id)
+        except tunnels.TunnelKeyNotFound:
+            LOG.debug('tunnel key not found')
+            return
+
+        return self._port_setup(dp, port_no, tunnel_key)
+
+    def _port_flow_del(self, dp, port_no):
+        LOG.debug('_port_flow_del')
+        rule = nx_match.ClsRule()
+        rule.set_in_port(port_no)
+        self.task_q.queue(
+            lambda: dp.send_flow_del(rule=rule, cookie=self._COOKIE_DEFAULT))
+
+    def _port_drop_all(self, dp, port_no):
+        LOG.debug('_port_drop_all')
+        rule = nx_match.ClsRule()
+        rule.set_in_port(port_no)
+        ofproto = dp.ofproto
+        self.task_q.queue(
+            lambda: dp.send_flow_mod(rule=rule, cookie=self._COOKIE_DEFAULT,
+                                     command=ofproto.OFPFC_ADD,
+                                     idle_timeout=0, hard_timeout=0,
+                                     priority=self._PRIORITY_DROP,
+                                     actions=[]))
+
+    def _port_add(self, dp, port_no):
+        if _is_reserved_port(dp, port_no):
+            return
+
+        dpid = dp.id
+        try:
+            network_id = self.nw.get_network(dpid, port_no)
+        except ryu_exc.PortUnknown:
+            LOG.debug('port_unknown')
+            self._port_drop_all(dp, port_no)
+            return
+
+        if not self._port_setup_netid(dpid, port_no, network_id):
+            LOG.debug('_port_setup_netid failed')
+            self._port_drop_all(dp, port_no)
+
+    @handler.set_ev_cls(dpset.EventPortAdd,
+                        SimpleVLANQueue.SIMPLE_VLAN_EV_DISPATCHER)
+    def port_add_handler(self, ev):
+        LOG.debug('port_add %s', ev)
+        self._port_add(ev.dp, ev.port.port_no)
+
+    @handler.set_ev_cls(dpset.EventPortDelete,
+                        SimpleVLANQueue.SIMPLE_VLAN_EV_DISPATCHER)
+    def port_del_handler(self, ev):
+        LOG.debug('port_del %s', ev)
+        dp = ev.dp
+        port_no = ev.port.port_no
+        if _is_reserved_port(dp, port_no):
+            return
+        self._port_flow_del(dp, port_no)
+
+    @handler.set_ev_cls(network.EventNetworkPort,
+                        SimpleVLANQueue.SIMPLE_VLAN_EV_DISPATCHER)
+    def network_port_handler(self, ev):
+        LOG.debug('network_port %s', ev)
+        if not ev.add_del:
+            return
+        self._port_setup_netid(ev.dpid, ev.port_no, ev.network_id)
+
+    @handler.set_ev_cls(tunnels.EventTunnelKeyAdd,
+                        SimpleVLANQueue.SIMPLE_VLAN_EV_DISPATCHER)
+    def tunnel_key_add_handler(self, ev):
+        LOG.debug('tunnel_add %s', ev)
+        tunnel_key = ev.tunnel_key
+        for (dpid, port_no) in self.nw.list_ports(ev.network_id):
+            dp = self.dpset.get(dpid)
+            if dp is None:
+                continue
+            self._port_setup(dp, port_no, tunnel_key)
+
+    @handler.set_ev_cls(conf_switch.EventConfSwitchSet,
+                        SimpleVLANQueue.SIMPLE_VLAN_EV_DISPATCHER)
+    def conf_switch_set_handler(self, ev):
+        LOG.debug('conf_switch_set %s', ev)
+        if ev.key != conf_switch_key.OVSDB_ADDR:
+            return
+
+        dpid = ev.dpid
+        try:
+            ports = self.dpset.get_ports(dpid)
+        except KeyError:
+            return
+        for port in ports:
+            port_no = port.port_no
+            try:
+                network_id = self.nw.get_network(dpid, port_no)
+            except ryu_exc.PortUnknown:
+                continue
+            self._port_setup_netid(dpid, port_no, network_id)
-- 
1.7.10.4


------------------------------------------------------------------------------
Keep yourself connected to Go Parallel: 
TUNE You got it built. Now make it sing. Tune shows you how.
http://goparallel.sourceforge.net
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to