]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
add local network type and use by default for tenant networks
authorBob Kukura <rkukura@redhat.com>
Tue, 4 Sep 2012 16:30:34 +0000 (12:30 -0400)
committerBob Kukura <rkukura@redhat.com>
Sat, 8 Sep 2012 01:42:01 +0000 (21:42 -0400)
Fixes bug 1045142.

This patch adds 'local' as a new value for provider:network_type,
supported by the openvswitch and linuxbridge plugins. Networks of this
type provide connectivity through a bridge for VMs and agents local to
the host, but no external connectivity. They do not require
provider:physical_network or provider:segmentation_id values. These
local networks are intended mainly to support single-box
zero-configuration testing (including quantum gating), but may have
other uses as well.

For openvswitch, the new OVS.tenant_network_type configuration
variable selects what type of networks are allocated as tenant
(i.e. non-provider) networks. It defaults to 'local', but must be
changed to 'vlan' or 'gre' for openvswitch tenant networks to have
external connectivity. The default value is intended to support
single-box zero-configuration testing without any need to allocate
physical network resources or configure bridges, and without requiring
the operating system to support OVS GRE tunneling. It can also be set
to 'none' to completely disable creation of tenant networks.

For linuxbridge, the new VLANS.tenant_network_type configuration
variable works similarly, with a value of 'vlan' supporting tenant
networks with external connectivity.

With either plugin, administrators can create provider local networks
by specifying "--provider:network_type local". Additionally, with
openvswitch, provider GRE networks can now be created by specifying
"--provider:network_type gre --provider:segmentation_id <tunnel-id>".

A corresponding devstack patch is available at
https://review.openstack.org/#/c/12456/. With this patch, the
openvswitch and linuxbridge plugins are by default configured to
support only local networks. A set of shell variables, documented in
stack.sh, can be set in localrc to configure remote connectivity,
including bridges/interfaces available for provider networks.

Change-Id: I2812548326141d2212d04f34d5448fb974d298e0

16 files changed:
etc/quantum/plugins/linuxbridge/linuxbridge_conf.ini
etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini
quantum/common/exceptions.py
quantum/extensions/providernet.py
quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py
quantum/plugins/linuxbridge/common/config.py
quantum/plugins/linuxbridge/common/constants.py
quantum/plugins/linuxbridge/db/l2network_models_v2.py
quantum/plugins/linuxbridge/lb_quantum_plugin.py
quantum/plugins/openvswitch/agent/ovs_quantum_agent.py
quantum/plugins/openvswitch/common/config.py
quantum/plugins/openvswitch/common/constants.py
quantum/plugins/openvswitch/ovs_models_v2.py
quantum/plugins/openvswitch/ovs_quantum_plugin.py
quantum/tests/unit/linuxbridge/test_defaults.py
quantum/tests/unit/openvswitch/test_ovs_defaults.py

index b571cc0a6e775ff88cf0574a2a18d7a317d44977..2523a658a448130d1e295a753427f5e7163a158b 100644 (file)
@@ -1,9 +1,24 @@
 [VLANS]
+# (StrOpt) Type of network to allocate for tenant networks. The
+# default value 'local' is useful only for single-box testing and
+# provides no connectivity between hosts. You MUST change this to
+# 'vlan' and configure network_vlan_ranges below in order for tenant
+# networks to provide connectivity between hosts. Set to 'none' to
+# disable creation of tenant networks.
+#
+# Default: tenant_network_type = local
+# Example: tenant_network_type = vlan
+
 # (ListOpt) Comma-separated list of
-# <physical_network>:<vlan_min>:<vlan_max> tuples enumerating ranges
+# <physical_network>[:<vlan_min>:<vlan_max>] tuples enumerating ranges
 # of VLAN IDs on named physical networks that are available for
-# allocation.
-# network_vlan_ranges = default:1000:2999
+# allocation. All physical networks listed are available for flat and
+# VLAN provider network creation. Specified ranges of VLAN IDs are
+# available for tenant network allocation if tenant_network_type is
+# 'vlan'. If empty, only local networks may be created.
+#
+# Default: network_vlan_ranges =
+# Example: network_vlan_ranges = physnet1:1000:2999
 
 [DATABASE]
 # This line MUST be changed to actually run the plugin.
@@ -21,10 +36,13 @@ reconnect_interval = 2
 [LINUX_BRIDGE]
 # (ListOpt) Comma-separated list of
 # <physical_network>:<physical_interface> tuples mapping physical
-# network names to agent's node-specific physical network
-# interfaces. Server uses physical network names for validation but
-# ignores interfaces.
-# physical_interface_mappings = default:eth1
+# network names to the agent's node-specific physical network
+# interfaces to be used for flat and VLAN networks. All physical
+# networks listed in network_vlan_ranges on the server should have
+# mappings to appropriate interfaces on each agent.
+#
+# Default: physical_interface_mappings =
+# Example: physical_interface_mappings = physnet1:eth1
 
 [AGENT]
 # Agent's polling interval in seconds
index 1b1b870879624e44650aa68f2bb7e87efdbe9303..ea3db361d7854f22f6a0c74a5a918550b0b4ef21 100644 (file)
@@ -12,37 +12,63 @@ sql_connection = sqlite://
 reconnect_interval = 2
 
 [OVS]
+# (StrOpt) Type of network to allocate for tenant networks. The
+# default value 'local' is useful only for single-box testing and
+# provides no connectivity between hosts. You MUST either change this
+# to 'vlan' and configure network_vlan_ranges below or change this to
+# 'gre' and configure tunnel_id_ranges below in order for tenant
+# networks to provide connectivity between hosts. Set to 'none' to
+# disable creation of tenant networks.
+#
+# Default: tenant_network_type = local
+# Example: tenant_network_type = gre
+
 # (ListOpt) Comma-separated list of
-# <physical_network>:<vlan_min>:<vlan_max> tuples enumerating ranges
+# <physical_network>[:<vlan_min>:<vlan_max>] tuples enumerating ranges
 # of VLAN IDs on named physical networks that are available for
-# allocation.
-# network_vlan_ranges = default:1000:2999
+# allocation. All physical networks listed are available for flat and
+# VLAN provider network creation. Specified ranges of VLAN IDs are
+# available for tenant network allocation if tenant_network_type is
+# 'vlan'. If empty, only gre and local networks may be created.
+#
+# Default: network_vlan_ranges =
+# Example: network_vlan_ranges = physnet1:1000:2999
 
 # (ListOpt) Comma-separated list of <tun_min>:<tun_max> tuples
-# enumerating ranges of GRE tunnel IDs that are available for
-# allocation.
-# tunnel_id_ranges =
+# enumerating ranges of GRE tunnel IDs that are available for tenant
+# network allocation if tenant_network_type is 'gre'.
+#
+# Default: tunnel_id_ranges =
+# Example: tunnel_id_ranges = 1:1000
 
 # Do not change this parameter unless you have a good reason to.
 # This is the name of the OVS integration bridge. There is one per hypervisor.
-# The integration bridge acts as a virtual "patch port". All VM VIFs are
+# The integration bridge acts as a virtual "patch bay". All VM VIFs are
 # attached to this bridge and then "patched" according to their network
 # connectivity.
-# integration_bridge = br-int
+#
+# Default: integration_bridge = br-int
 
-# Only used if tunnel_id_ranges (above) is not empty.
-# In most cases, the default value should be fine.
-# tunnel_bridge = br-tun
+# Only used for the agent if tunnel_id_ranges (above) is not empty for
+# the server.  In most cases, the default value should be fine.
+#
+# Default: tunnel_bridge = br-tun
 
-# (ListOpt) Comma-separated list of <physical_network>:<bridge> tuples
-# mapping physical network names to agent's node-specific OVS bridge
-# names. Each bridge must exist, and should have physical network
-# interface configured as a port.
-# bridge_mappings = default:br-eth1
+# Uncomment this line for the agent if tunnel_id_ranges (above) is not
+# empty for the server. Set local-ip to be the local IP address of
+# this hypervisor.
+#
+# Default: local_ip = 10.0.0.3
 
-# Uncomment this line if tunnel_id_ranges (above) is not empty.
-# Set local-ip to be the local IP address of this hypervisor.
-# local_ip = 10.0.0.3
+# (ListOpt) Comma-separated list of <physical_network>:<bridge> tuples
+# mapping physical network names to the agent's node-specific OVS
+# bridge names to be used for flat and VLAN networks. Each bridge must
+# exist, and should have a physical network interface configured as a
+# port. All physical networks listed in network_vlan_ranges on the
+# server should have mappings to appropriate bridges on each agent.
+#
+# Default: bridge_mappings =
+# Example: bridge_mappings = physnet1:br-eth1
 
 [AGENT]
 # Agent's polling interval in seconds
index 0a117c3a2907ada05ff433bff9cd589723559394..bed98faff00e1b526a5aefdfa2be5d6090486841 100644 (file)
@@ -137,6 +137,10 @@ class TunnelIdInUse(InUse):
                 "The tunnel ID %(tunnel_id)s is in use.")
 
 
+class TenantNetworksDisabled(QuantumException):
+    message = _("Tenant network creation is not enabled.")
+
+
 class ResourceExhausted(QuantumException):
     pass
 
index 0b41494e0957ee8689bf7059ebc8c81a70e4281a..204b7164c80144ca35999daec5f26158433bcdce 100644 (file)
@@ -19,11 +19,12 @@ NETWORK_TYPE = 'provider:network_type'
 PHYSICAL_NETWORK = 'provider:physical_network'
 SEGMENTATION_ID = 'provider:segmentation_id'
 
+NETWORK_TYPE_VALUES = ['flat', 'gre', 'local', 'vlan']
+
 EXTENDED_ATTRIBUTES_2_0 = {
     'networks': {
         NETWORK_TYPE: {'allow_post': True, 'allow_put': True,
-                       'validate': {'type:values': ['flat',
-                                                    'vlan']},
+                       'validate': {'type:values': NETWORK_TYPE_VALUES},
                        'default': attributes.ATTR_NOT_SPECIFIED,
                        'is_visible': True},
         PHYSICAL_NETWORK: {'allow_post': True, 'allow_put': True,
@@ -49,6 +50,8 @@ class Providernet(object):
     To create a provider VLAN network using the CLI with admin rights:
 
        (shell) net-create --tenant_id <tenant-id> <net-name> \
+       --provider:network_type vlan \
+       --provider:physical_network <physical-net> \
        --provider:segmentation_id <vlan-id>
 
     With admin rights, network dictionaries returned from CLI commands
@@ -65,7 +68,7 @@ class Providernet(object):
 
     @classmethod
     def get_description(cls):
-        return "Expose mapping of virtual networks to VLANs and flat networks"
+        return "Expose mapping of virtual networks to physical networks"
 
     @classmethod
     def get_namespace(cls):
@@ -73,7 +76,7 @@ class Providernet(object):
 
     @classmethod
     def get_updated(cls):
-        return "2012-07-23T10:00:00-00:00"
+        return "2012-09-07T10:00:00-00:00"
 
     def get_extended_resources(self, version):
         if version == "2.0":
index 5b467a86e73622c156bf084f712268a1ae9dab37..2cb25c32ddab17525a41e6a479990a4be076fe18 100755 (executable)
@@ -192,6 +192,11 @@ class LinuxBridge:
         self.ensure_bridge(bridge_name, physical_interface, ips, gateway)
         return physical_interface
 
+    def ensure_local_bridge(self, network_id):
+        """Create a local bridge unless it already exists."""
+        bridge_name = self.get_bridge_name(network_id)
+        self.ensure_bridge(bridge_name)
+
     def ensure_vlan(self, physical_interface, vlan_id):
         """Create a vlan unless it already exists."""
         interface = self.get_subinterface_name(physical_interface, vlan_id)
@@ -237,7 +242,8 @@ class LinuxBridge:
                 src_device.addr.delete(ip_version=ip['ip_version'],
                                        cidr=ip['cidr'])
 
-    def ensure_bridge(self, bridge_name, interface, ips=None, gateway=None):
+    def ensure_bridge(self, bridge_name, interface=None, ips=None,
+                      gateway=None):
         """
         Create a bridge unless it already exists.
         """
@@ -259,6 +265,9 @@ class LinuxBridge:
             LOG.debug("Done starting bridge %s for subinterface %s" %
                       (bridge_name, interface))
 
+        if not interface:
+            return
+
         # Update IP info if necessary
         self.update_interface_ip_details(bridge_name, interface, ips, gateway)
 
@@ -272,7 +281,7 @@ class LinuxBridge:
                           bridge_name, e)
                 return
 
-    def add_tap_interface(self, network_id, physical_interface, vlan_id,
+    def add_tap_interface(self, network_id, physical_network, vlan_id,
                           tap_device_name):
         """
         If a VIF has been plugged into a network, this function will
@@ -297,13 +306,25 @@ class LinuxBridge:
                               tap_device_name], root_helper=self.root_helper):
                 return False
 
-        if int(vlan_id) == lconst.FLAT_VLAN_ID:
-            self.ensure_flat_bridge(network_id, physical_interface)
+        if int(vlan_id) == lconst.LOCAL_VLAN_ID:
+            self.ensure_local_bridge(network_id)
         else:
-            self.ensure_vlan_bridge(network_id, physical_interface, vlan_id)
+            physical_interface = self.interface_mappings.get(physical_network)
+            if not physical_interface:
+                LOG.error("No mapping for physical network %s" %
+                          physical_network)
+                return False
+
+            if int(vlan_id) == lconst.FLAT_VLAN_ID:
+                self.ensure_flat_bridge(network_id, physical_interface)
+            else:
+                self.ensure_vlan_bridge(network_id, physical_interface,
+                                        vlan_id)
+
         if utils.execute(['brctl', 'addif', bridge_name, tap_device_name],
                          root_helper=self.root_helper):
             return False
+
         LOG.debug("Done adding device %s to bridge %s" % (tap_device_name,
                                                           bridge_name))
         return True
@@ -317,19 +338,14 @@ class LinuxBridge:
             """
             return False
 
-        physical_interface = self.interface_mappings.get(physical_network)
-        if not physical_interface:
-            LOG.error("No mapping for physical network %s" % physical_network)
-            return False
-
         if interface_id.startswith(GATEWAY_INTERFACE_PREFIX):
             return self.add_tap_interface(network_id,
-                                          physical_interface, vlan_id,
+                                          physical_network, vlan_id,
                                           interface_id)
         else:
             tap_device_name = self.get_tap_device_name(interface_id)
             return self.add_tap_interface(network_id,
-                                          physical_interface, vlan_id,
+                                          physical_network, vlan_id,
                                           tap_device_name)
 
     def delete_vlan_bridge(self, bridge_name):
@@ -613,9 +629,18 @@ class LinuxBridgeQuantumAgentRPC:
         self.setup_rpc(interface_mappings.values())
 
     def setup_rpc(self, physical_interfaces):
-        # REVISIT try until one succeeds?
-        mac = utils.get_interface_mac(physical_interfaces[0])
+        if physical_interfaces:
+            mac = utils.get_interface_mac(physical_interfaces[0])
+        else:
+            devices = ip_lib.IPWrapper(self.root_helper).get_devices(True)
+            if devices:
+                mac = utils.get_interface_mac(devices[0].name)
+            else:
+                LOG.error("Unable to obtain MAC of any device for agent_id")
+                exit(1)
         self.agent_id = '%s%s' % ('lb', (mac.replace(":", "")))
+        LOG.info("RPC agent_id: %s" % self.agent_id)
+
         self.topic = topics.AGENT
         self.plugin_rpc = agent_rpc.PluginApi(topics.PLUGIN)
 
index a73fdca1b152314b4b301eb783da51bef24bcc3e..63dae9d6ec87ff4f533fd93d7630b5f7295bf9cc 100644 (file)
 
 from quantum.openstack.common import cfg
 
-DEFAULT_VLAN_RANGES = ['default:1000:2999']
-DEFAULT_INTERFACE_MAPPINGS = ['default:eth1']
+DEFAULT_VLAN_RANGES = []
+DEFAULT_INTERFACE_MAPPINGS = []
 
 
 vlan_opts = [
+    cfg.StrOpt('tenant_network_type', default='local',
+               help="Network type for tenant networks "
+               "(local, vlan, or none)"),
     cfg.ListOpt('network_vlan_ranges',
                 default=DEFAULT_VLAN_RANGES,
                 help="List of <physical_network>:<vlan_min>:<vlan_max> "
index 87f908898e7554d9616e0d287f3425d1e8f60041..2ae1412abb7297cbebd8c4a798bf88a27d1994d3 100644 (file)
 
 
 FLAT_VLAN_ID = -1
+LOCAL_VLAN_ID = -2
 
-PORT_UP = "ACTIVE"
-PORT_DOWN = "DOWN"
-
-VLANID = 'vlan_id'
-PORT_ID = 'port-id'
-NET_ID = 'net-id'
+# Values for network_type
+TYPE_FLAT = 'flat'
+TYPE_VLAN = 'vlan'
+TYPE_LOCAL = 'local'
+TYPE_NONE = 'none'
index ca840a285fc4c0c73db815008e3e2755819ac783..6841cfb90df7fcc89fc99f13e32db41a00ef502d 100644 (file)
@@ -45,7 +45,7 @@ class NetworkBinding(model_base.BASEV2):
     network_id = sa.Column(sa.String(36),
                            sa.ForeignKey('networks.id', ondelete="CASCADE"),
                            primary_key=True)
-    physical_network = sa.Column(sa.String(64), nullable=False)
+    physical_network = sa.Column(sa.String(64))
     vlan_id = sa.Column(sa.Integer, nullable=False)
 
     def __init__(self, network_id, physical_network, vlan_id):
index da420e59e93027dda177c40322af3b0e9291e840..5aeb687d6cbfcb74aca76a1be9ee8f713182a93c 100644 (file)
@@ -17,7 +17,7 @@ import logging
 import sys
 
 from quantum.api.v2 import attributes
-from quantum.common import constants
+from quantum.common import constants as q_const
 from quantum.common import exceptions as q_exc
 from quantum.common import topics
 from quantum.db import api as db_api
@@ -31,7 +31,7 @@ from quantum.openstack.common import cfg
 from quantum.openstack.common import rpc
 from quantum.openstack.common.rpc import dispatcher
 from quantum.openstack.common.rpc import proxy
-from quantum.plugins.linuxbridge.common import constants as lconst
+from quantum.plugins.linuxbridge.common import constants
 from quantum.plugins.linuxbridge.db import l2network_db_v2 as db
 from quantum import policy
 
@@ -73,7 +73,7 @@ class LinuxBridgeRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin):
                      'port_id': port['id'],
                      'admin_state_up': port['admin_state_up']}
             # Set the port status to UP
-            db.set_port_status(port['id'], constants.PORT_STATUS_ACTIVE)
+            db.set_port_status(port['id'], q_const.PORT_STATUS_ACTIVE)
         else:
             entry = {'device': device}
             LOG.debug("%s can not be found in database", device)
@@ -90,7 +90,7 @@ class LinuxBridgeRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin):
             entry = {'device': device,
                      'exists': True}
             # Set port status to DOWN
-            db.set_port_status(port['id'], constants.PORT_STATUS_DOWN)
+            db.set_port_status(port['id'], q_const.PORT_STATUS_DOWN)
         else:
             entry = {'device': device,
                      'exists': False}
@@ -159,6 +159,13 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
         db.initialize()
         self._parse_network_vlan_ranges()
         db.sync_network_states(self.network_vlan_ranges)
+        self.tenant_network_type = cfg.CONF.VLANS.tenant_network_type
+        if self.tenant_network_type not in [constants.TYPE_LOCAL,
+                                            constants.TYPE_VLAN,
+                                            constants.TYPE_NONE]:
+            LOG.error("Invalid tenant_network_type: %s" %
+                      self.tenant_network_type)
+            sys.exit(1)
         self.agent_rpc = cfg.CONF.AGENT.rpc
         self._setup_rpc()
         LOG.debug("Linux Bridge Plugin initialization complete")
@@ -218,12 +225,17 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
     def _extend_network_dict_provider(self, context, network):
         if self._check_provider_view_auth(context, network):
             binding = db.get_network_binding(context.session, network['id'])
-            network[provider.PHYSICAL_NETWORK] = binding.physical_network
-            if binding.vlan_id == lconst.FLAT_VLAN_ID:
-                network[provider.NETWORK_TYPE] = 'flat'
+            if binding.vlan_id == constants.FLAT_VLAN_ID:
+                network[provider.NETWORK_TYPE] = constants.TYPE_FLAT
+                network[provider.PHYSICAL_NETWORK] = binding.physical_network
+                network[provider.SEGMENTATION_ID] = None
+            elif binding.vlan_id == constants.LOCAL_VLAN_ID:
+                network[provider.NETWORK_TYPE] = constants.TYPE_LOCAL
+                network[provider.PHYSICAL_NETWORK] = None
                 network[provider.SEGMENTATION_ID] = None
             else:
-                network[provider.NETWORK_TYPE] = 'vlan'
+                network[provider.NETWORK_TYPE] = constants.TYPE_VLAN
+                network[provider.PHYSICAL_NETWORK] = binding.physical_network
                 network[provider.SEGMENTATION_ID] = binding.vlan_id
 
     def _process_provider_create(self, context, attrs):
@@ -245,13 +257,13 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
         if not network_type_set:
             msg = _("provider:network_type required")
             raise q_exc.InvalidInput(error_message=msg)
-        elif network_type == 'flat':
+        elif network_type == constants.TYPE_FLAT:
             if segmentation_id_set:
                 msg = _("provider:segmentation_id specified for flat network")
                 raise q_exc.InvalidInput(error_message=msg)
             else:
-                segmentation_id = lconst.FLAT_VLAN_ID
-        elif network_type == 'vlan':
+                segmentation_id = constants.FLAT_VLAN_ID
+        elif network_type == constants.TYPE_VLAN:
             if not segmentation_id_set:
                 msg = _("provider:segmentation_id required")
                 raise q_exc.InvalidInput(error_message=msg)
@@ -259,20 +271,34 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
                 msg = _("provider:segmentation_id out of range "
                         "(1 through 4094)")
                 raise q_exc.InvalidInput(error_message=msg)
+        elif network_type == constants.TYPE_LOCAL:
+            if physical_network_set:
+                msg = _("provider:physical_network specified for local "
+                        "network")
+                raise q_exc.InvalidInput(error_message=msg)
+            else:
+                physical_network = None
+            if segmentation_id_set:
+                msg = _("provider:segmentation_id specified for local "
+                        "network")
+                raise q_exc.InvalidInput(error_message=msg)
+            else:
+                segmentation_id = constants.LOCAL_VLAN_ID
         else:
-            msg = _("invalid provider:network_type %s" % network_type)
+            msg = _("provider:network_type %s not supported" % network_type)
             raise q_exc.InvalidInput(error_message=msg)
 
-        if physical_network_set:
-            if physical_network not in self.network_vlan_ranges:
-                msg = _("unknown provider:physical_network %s" %
-                        physical_network)
+        if network_type in [constants.TYPE_VLAN, constants.TYPE_FLAT]:
+            if physical_network_set:
+                if physical_network not in self.network_vlan_ranges:
+                    msg = _("unknown provider:physical_network %s" %
+                            physical_network)
+                    raise q_exc.InvalidInput(error_message=msg)
+            elif 'default' in self.network_vlan_ranges:
+                physical_network = 'default'
+            else:
+                msg = _("provider:physical_network required")
                 raise q_exc.InvalidInput(error_message=msg)
-        elif 'default' in self.network_vlan_ranges:
-            physical_network = 'default'
-        else:
-            msg = _("provider:physical_network required")
-            raise q_exc.InvalidInput(error_message=msg)
 
         return (network_type, physical_network, segmentation_id)
 
@@ -303,9 +329,20 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
         session = context.session
         with session.begin(subtransactions=True):
             if not network_type:
-                physical_network, vlan_id = db.reserve_network(session)
+                # tenant network
+                network_type = self.tenant_network_type
+                if network_type == constants.TYPE_NONE:
+                    raise q_exc.TenantNetworksDisabled()
+                elif network_type == constants.TYPE_VLAN:
+                    physical_network, vlan_id = db.reserve_network(session)
+                else:  # TYPE_LOCAL
+                    vlan_id = constants.LOCAL_VLAN_ID
             else:
-                db.reserve_specific_network(session, physical_network, vlan_id)
+                # provider network
+                if network_type in [constants.TYPE_VLAN, constants.TYPE_FLAT]:
+                    db.reserve_specific_network(session, physical_network,
+                                                vlan_id)
+                # no reservation needed for TYPE_LOCAL
             net = super(LinuxBridgePluginV2, self).create_network(context,
                                                                   network)
             db.add_network_binding(session, net['id'],
@@ -334,8 +371,9 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
             binding = db.get_network_binding(session, id)
             result = super(LinuxBridgePluginV2, self).delete_network(context,
                                                                      id)
-            db.release_network(session, binding.physical_network,
-                               binding.vlan_id, self.network_vlan_ranges)
+            if binding.vlan_id != constants.LOCAL_VLAN_ID:
+                db.release_network(session, binding.physical_network,
+                                   binding.vlan_id, self.network_vlan_ranges)
             # the network_binding record is deleted via cascade from
             # the network record, so explicit removal is not necessary
         if self.agent_rpc:
index 90d7542c257bf96b8cb1a418e1851fed881633bc..dc46d0d07c070630cc8008d23b36b5e575a933b2 100755 (executable)
@@ -229,7 +229,7 @@ class OVSQuantumAgent(object):
         '''Provisions a local VLAN.
 
         :param net_uuid: the uuid of the network associated with this vlan.
-        :param network_type: the type of the network ('gre', 'vlan', 'flat')
+        :param network_type: the network type ('gre', 'vlan', 'flat', 'local')
         :param physical_network: the physical network for 'vlan' or 'flat'
         :param segmentation_id: the VID for 'vlan' or tunnel ID for 'tunnel'
         '''
@@ -277,6 +277,9 @@ class OVSQuantumAgent(object):
                                  in_port=self.int_ofports[physical_network],
                                  dl_vlan=segmentation_id,
                                  actions="mod_vlan_vid:%s,normal" % lvid)
+        elif network_type == constants.TYPE_LOCAL:
+            # no flows needed for local networks
+            pass
         else:
             LOG.error("provisioning unknown network type %s for net-id=%s" %
                       (network_type, net_uuid))
@@ -311,6 +314,9 @@ class OVSQuantumAgent(object):
             br = self.int_br
             br.delete_flows(in_port=self.int_ofports[lvm.physical_network],
                             dl_vlan=lvm.segmentation_id)
+        elif lvm.network_type == constants.TYPE_LOCAL:
+            # no flows needed for local networks
+            pass
         else:
             LOG.error("reclaiming unknown network type %s for net-id=%s" %
                       (lvm.network_type, net_uuid))
@@ -325,7 +331,7 @@ class OVSQuantumAgent(object):
 
         :param port: a ovslib.VifPort object.
         :param net_uuid: the net_uuid this port is to be associated with.
-        :param network_type: the type of the network ('gre', 'vlan', 'flat')
+        :param network_type: the network type ('gre', 'vlan', 'flat', 'local')
         :param physical_network: the physical network for 'vlan' or 'flat'
         :param segmentation_id: the VID for 'vlan' or tunnel ID for 'tunnel'
         '''
index d89a970eb76bba77497816d7a52b8c8bb7a14290..194650a57ebc40cdc16be1d9f89793ee545e5620 100644 (file)
@@ -17,8 +17,8 @@
 from quantum.openstack.common import cfg
 
 
-DEFAULT_BRIDGE_MAPPINGS = ['default:br-eth1']
-DEFAULT_VLAN_RANGES = ['default:1000:2999']
+DEFAULT_BRIDGE_MAPPINGS = []
+DEFAULT_VLAN_RANGES = []
 DEFAULT_TUNNEL_RANGES = []
 
 database_opts = [
@@ -34,6 +34,9 @@ ovs_opts = [
     cfg.ListOpt('bridge_mappings',
                 default=DEFAULT_BRIDGE_MAPPINGS,
                 help="List of <physical_network>:<bridge>"),
+    cfg.StrOpt('tenant_network_type', default='local',
+               help="Network type for tenant networks "
+               "(local, vlan, gre, or none)"),
     cfg.ListOpt('network_vlan_ranges',
                 default=DEFAULT_VLAN_RANGES,
                 help="List of <physical_network>:<vlan_min>:<vlan_max> "
index d23f2cd0f26345b50a8f3184e29bf5b25918bac4..20a22a8f1661e61867bbfce74b025200b1bf9141 100644 (file)
@@ -23,6 +23,8 @@ TUNNEL = 'tunnel'
 TYPE_FLAT = 'flat'
 TYPE_VLAN = 'vlan'
 TYPE_GRE = 'gre'
+TYPE_LOCAL = 'local'
+TYPE_NONE = 'none'
 
 # Name prefixes for veth device pair linking the integration bridge
 # with the physical bridge for a physical network
index fa8c28c40a2062f0e6dee45e55a3cc2c49078745..119bd8c7af647090ca06937e2735ae7d696a4c4b 100644 (file)
@@ -64,7 +64,8 @@ class NetworkBinding(model_base.BASEV2):
     network_id = Column(String(36),
                         ForeignKey('networks.id', ondelete="CASCADE"),
                         primary_key=True)
-    network_type = Column(String(32), nullable=False)  # 'gre', 'vlan', 'flat'
+    # 'gre', 'vlan', 'flat', 'local'
+    network_type = Column(String(32), nullable=False)
     physical_network = Column(String(64))
     segmentation_id = Column(Integer)  # tunnel_id or vlan_id
 
index a0c6568db2dd703eddee2dff61c6d9bf3aa0d5b1..fde8bd6df3258ab7d687c24cd92fd03a09aaaec6 100644 (file)
@@ -197,6 +197,14 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
         ovs_db_v2.sync_vlan_allocations(self.network_vlan_ranges)
         self._parse_tunnel_id_ranges()
         ovs_db_v2.sync_tunnel_allocations(self.tunnel_id_ranges)
+        self.tenant_network_type = cfg.CONF.OVS.tenant_network_type
+        if self.tenant_network_type not in [constants.TYPE_LOCAL,
+                                            constants.TYPE_VLAN,
+                                            constants.TYPE_GRE,
+                                            constants.TYPE_NONE]:
+            LOG.error("Invalid tenant_network_type: %s" %
+                      self.tenant_network_type)
+            sys.exit(1)
         self.agent_rpc = cfg.CONF.AGENT.rpc
         self.setup_rpc()
 
@@ -280,6 +288,9 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
             elif binding.network_type == constants.TYPE_VLAN:
                 network[provider.PHYSICAL_NETWORK] = binding.physical_network
                 network[provider.SEGMENTATION_ID] = binding.segmentation_id
+            elif binding.network_type == constants.TYPE_LOCAL:
+                network[provider.PHYSICAL_NETWORK] = None
+                network[provider.SEGMENTATION_ID] = None
 
     def _process_provider_create(self, context, attrs):
         network_type = attrs.get(provider.NETWORK_TYPE)
@@ -314,20 +325,44 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
                 msg = _("provider:segmentation_id out of range "
                         "(1 through 4094)")
                 raise q_exc.InvalidInput(error_message=msg)
+        elif network_type == constants.TYPE_GRE:
+            if physical_network_set:
+                msg = _("provider:physical_network specified for GRE "
+                        "network")
+                raise q_exc.InvalidInput(error_message=msg)
+            else:
+                physical_network = None
+            if not segmentation_id_set:
+                msg = _("provider:segmentation_id required")
+                raise q_exc.InvalidInput(error_message=msg)
+        elif network_type == constants.TYPE_LOCAL:
+            if physical_network_set:
+                msg = _("provider:physical_network specified for local "
+                        "network")
+                raise q_exc.InvalidInput(error_message=msg)
+            else:
+                physical_network = None
+            if segmentation_id_set:
+                msg = _("provider:segmentation_id specified for local "
+                        "network")
+                raise q_exc.InvalidInput(error_message=msg)
+            else:
+                segmentation_id = None
         else:
-            msg = _("invalid provider:network_type %s" % network_type)
+            msg = _("provider:network_type %s not supported" % network_type)
             raise q_exc.InvalidInput(error_message=msg)
 
-        if physical_network_set:
-            if physical_network not in self.network_vlan_ranges:
-                msg = _("unknown provider:physical_network %s" %
-                        physical_network)
+        if network_type in [constants.TYPE_VLAN, constants.TYPE_FLAT]:
+            if physical_network_set:
+                if physical_network not in self.network_vlan_ranges:
+                    msg = _("unknown provider:physical_network %s" %
+                            physical_network)
+                    raise q_exc.InvalidInput(error_message=msg)
+            elif 'default' in self.network_vlan_ranges:
+                physical_network = 'default'
+            else:
+                msg = _("provider:physical_network required")
                 raise q_exc.InvalidInput(error_message=msg)
-        elif 'default' in self.network_vlan_ranges:
-            physical_network = 'default'
-        else:
-            msg = _("provider:physical_network required")
-            raise q_exc.InvalidInput(error_message=msg)
 
         return (network_type, physical_network, segmentation_id)
 
@@ -358,16 +393,24 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
         session = context.session
         with session.begin(subtransactions=True):
             if not network_type:
-                try:
+                # tenant network
+                network_type = self.tenant_network_type
+                if network_type == constants.TYPE_NONE:
+                    raise q_exc.TenantNetworksDisabled()
+                elif network_type == constants.TYPE_VLAN:
                     (physical_network,
                      segmentation_id) = ovs_db_v2.reserve_vlan(session)
-                    network_type = constants.TYPE_VLAN
-                except q_exc.NoNetworkAvailable:
+                elif network_type == constants.TYPE_GRE:
                     segmentation_id = ovs_db_v2.reserve_tunnel(session)
-                    network_type = constants.TYPE_GRE
+                # no reservation needed for TYPE_LOCAL
             else:
-                ovs_db_v2.reserve_specific_vlan(session, physical_network,
-                                                segmentation_id)
+                # provider network
+                if network_type in [constants.TYPE_VLAN, constants.TYPE_FLAT]:
+                    ovs_db_v2.reserve_specific_vlan(session, physical_network,
+                                                    segmentation_id)
+                elif network_type == constants.TYPE_GRE:
+                    ovs_db_v2.reserve_specific_tunnel(session, segmentation_id)
+                # no reservation needed for TYPE_LOCAL
             net = super(OVSQuantumPluginV2, self).create_network(context,
                                                                  network)
             ovs_db_v2.add_network_binding(session, net['id'], network_type,
@@ -400,7 +443,8 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
             if binding.network_type == constants.TYPE_GRE:
                 ovs_db_v2.release_tunnel(session, binding.segmentation_id,
                                          self.tunnel_id_ranges)
-            else:
+            elif binding.network_type in [constants.TYPE_VLAN,
+                                          constants.TYPE_FLAT]:
                 ovs_db_v2.release_vlan(session, binding.physical_network,
                                        binding.segmentation_id,
                                        self.network_vlan_ranges)
index f3361e72a3a742a18d8d925fbf6f79a014f5c269..d2532f8533077da70a88b5c738f67bd86c7bf1e2 100644 (file)
@@ -32,11 +32,10 @@ class ConfigurationTest(unittest.TestCase):
                          cfg.CONF.AGENT.polling_interval)
         self.assertEqual('sudo',
                          cfg.CONF.AGENT.root_helper)
-
-        ranges = cfg.CONF.VLANS.network_vlan_ranges
-        self.assertEqual(1, len(ranges))
-        self.assertEqual('default:1000:2999', ranges[0])
-
-        mappings = cfg.CONF.LINUX_BRIDGE.physical_interface_mappings
-        self.assertEqual(1, len(mappings))
-        self.assertEqual('default:eth1', mappings[0])
+        self.assertEqual('local',
+                         cfg.CONF.VLANS.tenant_network_type)
+        self.assertEqual(0,
+                         len(cfg.CONF.VLANS.network_vlan_ranges))
+        self.assertEqual(0,
+                         len(cfg.CONF.LINUX_BRIDGE.
+                             physical_interface_mappings))
index c1d09cde3a26dafd6b09ba333e63960e0e1ab2f1..2a3d4283c4094aa306e7c85cb733c8979925208e 100644 (file)
@@ -29,14 +29,7 @@ class ConfigurationTest(unittest.TestCase):
         self.assertEqual(2, cfg.CONF.DATABASE.reconnect_interval)
         self.assertEqual(2, cfg.CONF.AGENT.polling_interval)
         self.assertEqual('sudo', cfg.CONF.AGENT.root_helper)
-
-        mappings = cfg.CONF.OVS.bridge_mappings
-        self.assertEqual(1, len(mappings))
-        self.assertEqual('default:br-eth1', mappings[0])
-
-        ranges = cfg.CONF.OVS.network_vlan_ranges
-        self.assertEqual(1, len(ranges))
-        self.assertEqual('default:1000:2999', ranges[0])
-
-        ranges = cfg.CONF.OVS.tunnel_id_ranges
-        self.assertEqual(0, len(ranges))
+        self.assertEqual('local', cfg.CONF.OVS.tenant_network_type)
+        self.assertEqual(0, len(cfg.CONF.OVS.bridge_mappings))
+        self.assertEqual(0, len(cfg.CONF.OVS.network_vlan_ranges))
+        self.assertEqual(0, len(cfg.CONF.OVS.tunnel_id_ranges))