diff --git a/etc/quantum/plugins/linuxbridge/linuxbridge_conf.ini b/etc/quantum/plugins/linuxbridge/linuxbridge_conf.ini index b571cc0a6..2523a658a 100644 --- a/etc/quantum/plugins/linuxbridge/linuxbridge_conf.ini +++ b/etc/quantum/plugins/linuxbridge/linuxbridge_conf.ini @@ -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 -# :: tuples enumerating ranges +# [::] 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 # : 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 diff --git a/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini b/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini index 1b1b87087..ea3db361d 100644 --- a/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini +++ b/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini @@ -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 -# :: tuples enumerating ranges +# [::] 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 : 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 + +# 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 # (ListOpt) Comma-separated list of : 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 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 +# 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 diff --git a/quantum/common/exceptions.py b/quantum/common/exceptions.py index 0a117c3a2..bed98faff 100644 --- a/quantum/common/exceptions.py +++ b/quantum/common/exceptions.py @@ -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 diff --git a/quantum/extensions/providernet.py b/quantum/extensions/providernet.py index 0b41494e0..204b7164c 100644 --- a/quantum/extensions/providernet.py +++ b/quantum/extensions/providernet.py @@ -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 \ + --provider:network_type vlan \ + --provider:physical_network \ --provider:segmentation_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": diff --git a/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py b/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py index 5b467a86e..2cb25c32d 100755 --- a/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py +++ b/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py @@ -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) diff --git a/quantum/plugins/linuxbridge/common/config.py b/quantum/plugins/linuxbridge/common/config.py index a73fdca1b..63dae9d6e 100644 --- a/quantum/plugins/linuxbridge/common/config.py +++ b/quantum/plugins/linuxbridge/common/config.py @@ -19,11 +19,14 @@ 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 :: " diff --git a/quantum/plugins/linuxbridge/common/constants.py b/quantum/plugins/linuxbridge/common/constants.py index 87f908898..2ae1412ab 100644 --- a/quantum/plugins/linuxbridge/common/constants.py +++ b/quantum/plugins/linuxbridge/common/constants.py @@ -18,10 +18,10 @@ 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' diff --git a/quantum/plugins/linuxbridge/db/l2network_models_v2.py b/quantum/plugins/linuxbridge/db/l2network_models_v2.py index ca840a285..6841cfb90 100644 --- a/quantum/plugins/linuxbridge/db/l2network_models_v2.py +++ b/quantum/plugins/linuxbridge/db/l2network_models_v2.py @@ -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): diff --git a/quantum/plugins/linuxbridge/lb_quantum_plugin.py b/quantum/plugins/linuxbridge/lb_quantum_plugin.py index da420e59e..5aeb687d6 100644 --- a/quantum/plugins/linuxbridge/lb_quantum_plugin.py +++ b/quantum/plugins/linuxbridge/lb_quantum_plugin.py @@ -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: diff --git a/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py b/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py index 90d7542c2..dc46d0d07 100755 --- a/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py +++ b/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py @@ -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' ''' diff --git a/quantum/plugins/openvswitch/common/config.py b/quantum/plugins/openvswitch/common/config.py index d89a970eb..194650a57 100644 --- a/quantum/plugins/openvswitch/common/config.py +++ b/quantum/plugins/openvswitch/common/config.py @@ -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 :"), + 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 :: " diff --git a/quantum/plugins/openvswitch/common/constants.py b/quantum/plugins/openvswitch/common/constants.py index d23f2cd0f..20a22a8f1 100644 --- a/quantum/plugins/openvswitch/common/constants.py +++ b/quantum/plugins/openvswitch/common/constants.py @@ -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 diff --git a/quantum/plugins/openvswitch/ovs_models_v2.py b/quantum/plugins/openvswitch/ovs_models_v2.py index fa8c28c40..119bd8c7a 100644 --- a/quantum/plugins/openvswitch/ovs_models_v2.py +++ b/quantum/plugins/openvswitch/ovs_models_v2.py @@ -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 diff --git a/quantum/plugins/openvswitch/ovs_quantum_plugin.py b/quantum/plugins/openvswitch/ovs_quantum_plugin.py index a0c6568db..fde8bd6df 100644 --- a/quantum/plugins/openvswitch/ovs_quantum_plugin.py +++ b/quantum/plugins/openvswitch/ovs_quantum_plugin.py @@ -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) diff --git a/quantum/tests/unit/linuxbridge/test_defaults.py b/quantum/tests/unit/linuxbridge/test_defaults.py index f3361e72a..d2532f853 100644 --- a/quantum/tests/unit/linuxbridge/test_defaults.py +++ b/quantum/tests/unit/linuxbridge/test_defaults.py @@ -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)) diff --git a/quantum/tests/unit/openvswitch/test_ovs_defaults.py b/quantum/tests/unit/openvswitch/test_ovs_defaults.py index c1d09cde3..2a3d4283c 100644 --- a/quantum/tests/unit/openvswitch/test_ovs_defaults.py +++ b/quantum/tests/unit/openvswitch/test_ovs_defaults.py @@ -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))