add local network type and use by default for tenant networks

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
This commit is contained in:
Bob Kukura 2012-09-04 12:30:34 -04:00
parent 363a0579db
commit 88cd4f8504
16 changed files with 284 additions and 119 deletions

View 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

View 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
# 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 <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 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

View 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

View 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":

View File

@ -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)

View File

@ -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 <physical_network>:<vlan_min>:<vlan_max> "

View File

@ -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'

View 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):

View 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:

View File

@ -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'
'''

View 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> "

View 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

View 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

View 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)

View 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))

View 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))