Merge "add local network type and use by default for tenant networks"

This commit is contained in:
Jenkins 2012-09-09 12:07:13 +00:00 committed by Gerrit Code Review
commit 59b9b2577a
16 changed files with 284 additions and 119 deletions

View File

@ -1,9 +1,24 @@
[VLANS] [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 # (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 # of VLAN IDs on named physical networks that are available for
# allocation. # allocation. All physical networks listed are available for flat and
# network_vlan_ranges = default:1000:2999 # 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] [DATABASE]
# This line MUST be changed to actually run the plugin. # This line MUST be changed to actually run the plugin.
@ -21,10 +36,13 @@ reconnect_interval = 2
[LINUX_BRIDGE] [LINUX_BRIDGE]
# (ListOpt) Comma-separated list of # (ListOpt) Comma-separated list of
# <physical_network>:<physical_interface> tuples mapping physical # <physical_network>:<physical_interface> tuples mapping physical
# network names to agent's node-specific physical network # network names to the agent's node-specific physical network
# interfaces. Server uses physical network names for validation but # interfaces to be used for flat and VLAN networks. All physical
# ignores interfaces. # networks listed in network_vlan_ranges on the server should have
# physical_interface_mappings = default:eth1 # mappings to appropriate interfaces on each agent.
#
# Default: physical_interface_mappings =
# Example: physical_interface_mappings = physnet1:eth1
[AGENT] [AGENT]
# Agent's polling interval in seconds # Agent's polling interval in seconds

View File

@ -12,37 +12,63 @@ sql_connection = sqlite://
reconnect_interval = 2 reconnect_interval = 2
[OVS] [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 # (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 # of VLAN IDs on named physical networks that are available for
# allocation. # allocation. All physical networks listed are available for flat and
# network_vlan_ranges = default:1000:2999 # 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 # (ListOpt) Comma-separated list of <tun_min>:<tun_max> tuples
# enumerating ranges of GRE tunnel IDs that are available for # enumerating ranges of GRE tunnel IDs that are available for tenant
# allocation. # network allocation if tenant_network_type is 'gre'.
# tunnel_id_ranges = #
# Default: tunnel_id_ranges =
# Example: tunnel_id_ranges = 1:1000
# Do not change this parameter unless you have a good reason to. # 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. # 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 # attached to this bridge and then "patched" according to their network
# connectivity. # connectivity.
# integration_bridge = br-int #
# Default: integration_bridge = br-int
# Only used if tunnel_id_ranges (above) is not empty. # Only used for the agent if tunnel_id_ranges (above) is not empty for
# In most cases, the default value should be fine. # the server. In most cases, the default value should be fine.
# tunnel_bridge = br-tun #
# 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 # (ListOpt) Comma-separated list of <physical_network>:<bridge> tuples
# mapping physical network names to agent's node-specific OVS bridge # mapping physical network names to the agent's node-specific OVS
# names. Each bridge must exist, and should have physical network # bridge names to be used for flat and VLAN networks. Each bridge must
# interface configured as a port. # exist, and should have a physical network interface configured as a
# bridge_mappings = default:br-eth1 # port. All physical networks listed in network_vlan_ranges on the
# server should have mappings to appropriate bridges on each agent.
# Uncomment this line if tunnel_id_ranges (above) is not empty. #
# Set local-ip to be the local IP address of this hypervisor. # Default: bridge_mappings =
# local_ip = 10.0.0.3 # Example: bridge_mappings = physnet1:br-eth1
[AGENT] [AGENT]
# Agent's polling interval in seconds # Agent's polling interval in seconds

View File

@ -137,6 +137,10 @@ class TunnelIdInUse(InUse):
"The tunnel ID %(tunnel_id)s is in use.") "The tunnel ID %(tunnel_id)s is in use.")
class TenantNetworksDisabled(QuantumException):
message = _("Tenant network creation is not enabled.")
class ResourceExhausted(QuantumException): class ResourceExhausted(QuantumException):
pass pass

View File

@ -19,11 +19,12 @@ NETWORK_TYPE = 'provider:network_type'
PHYSICAL_NETWORK = 'provider:physical_network' PHYSICAL_NETWORK = 'provider:physical_network'
SEGMENTATION_ID = 'provider:segmentation_id' SEGMENTATION_ID = 'provider:segmentation_id'
NETWORK_TYPE_VALUES = ['flat', 'gre', 'local', 'vlan']
EXTENDED_ATTRIBUTES_2_0 = { EXTENDED_ATTRIBUTES_2_0 = {
'networks': { 'networks': {
NETWORK_TYPE: {'allow_post': True, 'allow_put': True, NETWORK_TYPE: {'allow_post': True, 'allow_put': True,
'validate': {'type:values': ['flat', 'validate': {'type:values': NETWORK_TYPE_VALUES},
'vlan']},
'default': attributes.ATTR_NOT_SPECIFIED, 'default': attributes.ATTR_NOT_SPECIFIED,
'is_visible': True}, 'is_visible': True},
PHYSICAL_NETWORK: {'allow_post': True, 'allow_put': 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: To create a provider VLAN network using the CLI with admin rights:
(shell) net-create --tenant_id <tenant-id> <net-name> \ (shell) net-create --tenant_id <tenant-id> <net-name> \
--provider:network_type vlan \
--provider:physical_network <physical-net> \
--provider:segmentation_id <vlan-id> --provider:segmentation_id <vlan-id>
With admin rights, network dictionaries returned from CLI commands With admin rights, network dictionaries returned from CLI commands
@ -65,7 +68,7 @@ class Providernet(object):
@classmethod @classmethod
def get_description(cls): 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 @classmethod
def get_namespace(cls): def get_namespace(cls):
@ -73,7 +76,7 @@ class Providernet(object):
@classmethod @classmethod
def get_updated(cls): 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): def get_extended_resources(self, version):
if version == "2.0": if version == "2.0":

View File

@ -192,6 +192,11 @@ class LinuxBridge:
self.ensure_bridge(bridge_name, physical_interface, ips, gateway) self.ensure_bridge(bridge_name, physical_interface, ips, gateway)
return physical_interface 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): def ensure_vlan(self, physical_interface, vlan_id):
"""Create a vlan unless it already exists.""" """Create a vlan unless it already exists."""
interface = self.get_subinterface_name(physical_interface, vlan_id) interface = self.get_subinterface_name(physical_interface, vlan_id)
@ -237,7 +242,8 @@ class LinuxBridge:
src_device.addr.delete(ip_version=ip['ip_version'], src_device.addr.delete(ip_version=ip['ip_version'],
cidr=ip['cidr']) 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. Create a bridge unless it already exists.
""" """
@ -259,6 +265,9 @@ class LinuxBridge:
LOG.debug("Done starting bridge %s for subinterface %s" % LOG.debug("Done starting bridge %s for subinterface %s" %
(bridge_name, interface)) (bridge_name, interface))
if not interface:
return
# Update IP info if necessary # Update IP info if necessary
self.update_interface_ip_details(bridge_name, interface, ips, gateway) self.update_interface_ip_details(bridge_name, interface, ips, gateway)
@ -272,7 +281,7 @@ class LinuxBridge:
bridge_name, e) bridge_name, e)
return 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): tap_device_name):
""" """
If a VIF has been plugged into a network, this function will 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): tap_device_name], root_helper=self.root_helper):
return False return False
if int(vlan_id) == lconst.LOCAL_VLAN_ID:
self.ensure_local_bridge(network_id)
else:
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: if int(vlan_id) == lconst.FLAT_VLAN_ID:
self.ensure_flat_bridge(network_id, physical_interface) self.ensure_flat_bridge(network_id, physical_interface)
else: else:
self.ensure_vlan_bridge(network_id, physical_interface, vlan_id) self.ensure_vlan_bridge(network_id, physical_interface,
vlan_id)
if utils.execute(['brctl', 'addif', bridge_name, tap_device_name], if utils.execute(['brctl', 'addif', bridge_name, tap_device_name],
root_helper=self.root_helper): root_helper=self.root_helper):
return False return False
LOG.debug("Done adding device %s to bridge %s" % (tap_device_name, LOG.debug("Done adding device %s to bridge %s" % (tap_device_name,
bridge_name)) bridge_name))
return True return True
@ -317,19 +338,14 @@ class LinuxBridge:
""" """
return False 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): if interface_id.startswith(GATEWAY_INTERFACE_PREFIX):
return self.add_tap_interface(network_id, return self.add_tap_interface(network_id,
physical_interface, vlan_id, physical_network, vlan_id,
interface_id) interface_id)
else: else:
tap_device_name = self.get_tap_device_name(interface_id) tap_device_name = self.get_tap_device_name(interface_id)
return self.add_tap_interface(network_id, return self.add_tap_interface(network_id,
physical_interface, vlan_id, physical_network, vlan_id,
tap_device_name) tap_device_name)
def delete_vlan_bridge(self, bridge_name): def delete_vlan_bridge(self, bridge_name):
@ -613,9 +629,18 @@ class LinuxBridgeQuantumAgentRPC:
self.setup_rpc(interface_mappings.values()) self.setup_rpc(interface_mappings.values())
def setup_rpc(self, physical_interfaces): def setup_rpc(self, physical_interfaces):
# REVISIT try until one succeeds? if physical_interfaces:
mac = utils.get_interface_mac(physical_interfaces[0]) 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(":", ""))) self.agent_id = '%s%s' % ('lb', (mac.replace(":", "")))
LOG.info("RPC agent_id: %s" % self.agent_id)
self.topic = topics.AGENT self.topic = topics.AGENT
self.plugin_rpc = agent_rpc.PluginApi(topics.PLUGIN) self.plugin_rpc = agent_rpc.PluginApi(topics.PLUGIN)

View File

@ -19,11 +19,14 @@
from quantum.openstack.common import cfg from quantum.openstack.common import cfg
DEFAULT_VLAN_RANGES = ['default:1000:2999'] DEFAULT_VLAN_RANGES = []
DEFAULT_INTERFACE_MAPPINGS = ['default:eth1'] DEFAULT_INTERFACE_MAPPINGS = []
vlan_opts = [ vlan_opts = [
cfg.StrOpt('tenant_network_type', default='local',
help="Network type for tenant networks "
"(local, vlan, or none)"),
cfg.ListOpt('network_vlan_ranges', cfg.ListOpt('network_vlan_ranges',
default=DEFAULT_VLAN_RANGES, default=DEFAULT_VLAN_RANGES,
help="List of <physical_network>:<vlan_min>:<vlan_max> " help="List of <physical_network>:<vlan_min>:<vlan_max> "

View File

@ -18,10 +18,10 @@
FLAT_VLAN_ID = -1 FLAT_VLAN_ID = -1
LOCAL_VLAN_ID = -2
PORT_UP = "ACTIVE" # Values for network_type
PORT_DOWN = "DOWN" TYPE_FLAT = 'flat'
TYPE_VLAN = 'vlan'
VLANID = 'vlan_id' TYPE_LOCAL = 'local'
PORT_ID = 'port-id' TYPE_NONE = 'none'
NET_ID = 'net-id'

View File

@ -45,7 +45,7 @@ class NetworkBinding(model_base.BASEV2):
network_id = sa.Column(sa.String(36), network_id = sa.Column(sa.String(36),
sa.ForeignKey('networks.id', ondelete="CASCADE"), sa.ForeignKey('networks.id', ondelete="CASCADE"),
primary_key=True) 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) vlan_id = sa.Column(sa.Integer, nullable=False)
def __init__(self, network_id, physical_network, vlan_id): def __init__(self, network_id, physical_network, vlan_id):

View File

@ -17,7 +17,7 @@ import logging
import sys import sys
from quantum.api.v2 import attributes 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 exceptions as q_exc
from quantum.common import topics from quantum.common import topics
from quantum.db import api as db_api 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 import rpc
from quantum.openstack.common.rpc import dispatcher from quantum.openstack.common.rpc import dispatcher
from quantum.openstack.common.rpc import proxy 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.plugins.linuxbridge.db import l2network_db_v2 as db
from quantum import policy from quantum import policy
@ -73,7 +73,7 @@ class LinuxBridgeRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin):
'port_id': port['id'], 'port_id': port['id'],
'admin_state_up': port['admin_state_up']} 'admin_state_up': port['admin_state_up']}
# Set the port status to 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: else:
entry = {'device': device} entry = {'device': device}
LOG.debug("%s can not be found in database", device) LOG.debug("%s can not be found in database", device)
@ -90,7 +90,7 @@ class LinuxBridgeRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin):
entry = {'device': device, entry = {'device': device,
'exists': True} 'exists': True}
# Set port status to DOWN # 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: else:
entry = {'device': device, entry = {'device': device,
'exists': False} 'exists': False}
@ -159,6 +159,13 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
db.initialize() db.initialize()
self._parse_network_vlan_ranges() self._parse_network_vlan_ranges()
db.sync_network_states(self.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.agent_rpc = cfg.CONF.AGENT.rpc
self._setup_rpc() self._setup_rpc()
LOG.debug("Linux Bridge Plugin initialization complete") 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): def _extend_network_dict_provider(self, context, network):
if self._check_provider_view_auth(context, network): if self._check_provider_view_auth(context, network):
binding = db.get_network_binding(context.session, network['id']) binding = db.get_network_binding(context.session, network['id'])
if binding.vlan_id == constants.FLAT_VLAN_ID:
network[provider.NETWORK_TYPE] = constants.TYPE_FLAT
network[provider.PHYSICAL_NETWORK] = binding.physical_network network[provider.PHYSICAL_NETWORK] = binding.physical_network
if binding.vlan_id == lconst.FLAT_VLAN_ID: network[provider.SEGMENTATION_ID] = None
network[provider.NETWORK_TYPE] = 'flat' 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 network[provider.SEGMENTATION_ID] = None
else: 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 network[provider.SEGMENTATION_ID] = binding.vlan_id
def _process_provider_create(self, context, attrs): def _process_provider_create(self, context, attrs):
@ -245,13 +257,13 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
if not network_type_set: if not network_type_set:
msg = _("provider:network_type required") msg = _("provider:network_type required")
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
elif network_type == 'flat': elif network_type == constants.TYPE_FLAT:
if segmentation_id_set: if segmentation_id_set:
msg = _("provider:segmentation_id specified for flat network") msg = _("provider:segmentation_id specified for flat network")
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
else: else:
segmentation_id = lconst.FLAT_VLAN_ID segmentation_id = constants.FLAT_VLAN_ID
elif network_type == 'vlan': elif network_type == constants.TYPE_VLAN:
if not segmentation_id_set: if not segmentation_id_set:
msg = _("provider:segmentation_id required") msg = _("provider:segmentation_id required")
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
@ -259,10 +271,24 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
msg = _("provider:segmentation_id out of range " msg = _("provider:segmentation_id out of range "
"(1 through 4094)") "(1 through 4094)")
raise q_exc.InvalidInput(error_message=msg) 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: else:
msg = _("invalid provider:network_type %s" % network_type) 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 = _("provider:network_type %s not supported" % network_type)
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
if network_type in [constants.TYPE_VLAN, constants.TYPE_FLAT]:
if physical_network_set: if physical_network_set:
if physical_network not in self.network_vlan_ranges: if physical_network not in self.network_vlan_ranges:
msg = _("unknown provider:physical_network %s" % msg = _("unknown provider:physical_network %s" %
@ -303,9 +329,20 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
session = context.session session = context.session
with session.begin(subtransactions=True): with session.begin(subtransactions=True):
if not network_type: if not network_type:
# 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) physical_network, vlan_id = db.reserve_network(session)
else: # TYPE_LOCAL
vlan_id = constants.LOCAL_VLAN_ID
else: 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, net = super(LinuxBridgePluginV2, self).create_network(context,
network) network)
db.add_network_binding(session, net['id'], db.add_network_binding(session, net['id'],
@ -334,6 +371,7 @@ class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2,
binding = db.get_network_binding(session, id) binding = db.get_network_binding(session, id)
result = super(LinuxBridgePluginV2, self).delete_network(context, result = super(LinuxBridgePluginV2, self).delete_network(context,
id) id)
if binding.vlan_id != constants.LOCAL_VLAN_ID:
db.release_network(session, binding.physical_network, db.release_network(session, binding.physical_network,
binding.vlan_id, self.network_vlan_ranges) binding.vlan_id, self.network_vlan_ranges)
# the network_binding record is deleted via cascade from # the network_binding record is deleted via cascade from

View File

@ -229,7 +229,7 @@ class OVSQuantumAgent(object):
'''Provisions a local VLAN. '''Provisions a local VLAN.
:param net_uuid: the uuid of the network associated with this 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 physical_network: the physical network for 'vlan' or 'flat'
:param segmentation_id: the VID for 'vlan' or tunnel ID for 'tunnel' :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], in_port=self.int_ofports[physical_network],
dl_vlan=segmentation_id, dl_vlan=segmentation_id,
actions="mod_vlan_vid:%s,normal" % lvid) actions="mod_vlan_vid:%s,normal" % lvid)
elif network_type == constants.TYPE_LOCAL:
# no flows needed for local networks
pass
else: else:
LOG.error("provisioning unknown network type %s for net-id=%s" % LOG.error("provisioning unknown network type %s for net-id=%s" %
(network_type, net_uuid)) (network_type, net_uuid))
@ -311,6 +314,9 @@ class OVSQuantumAgent(object):
br = self.int_br br = self.int_br
br.delete_flows(in_port=self.int_ofports[lvm.physical_network], br.delete_flows(in_port=self.int_ofports[lvm.physical_network],
dl_vlan=lvm.segmentation_id) dl_vlan=lvm.segmentation_id)
elif lvm.network_type == constants.TYPE_LOCAL:
# no flows needed for local networks
pass
else: else:
LOG.error("reclaiming unknown network type %s for net-id=%s" % LOG.error("reclaiming unknown network type %s for net-id=%s" %
(lvm.network_type, net_uuid)) (lvm.network_type, net_uuid))
@ -325,7 +331,7 @@ class OVSQuantumAgent(object):
:param port: a ovslib.VifPort object. :param port: a ovslib.VifPort object.
:param net_uuid: the net_uuid this port is to be associated with. :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 physical_network: the physical network for 'vlan' or 'flat'
:param segmentation_id: the VID for 'vlan' or tunnel ID for 'tunnel' :param segmentation_id: the VID for 'vlan' or tunnel ID for 'tunnel'
''' '''

View File

@ -17,8 +17,8 @@
from quantum.openstack.common import cfg from quantum.openstack.common import cfg
DEFAULT_BRIDGE_MAPPINGS = ['default:br-eth1'] DEFAULT_BRIDGE_MAPPINGS = []
DEFAULT_VLAN_RANGES = ['default:1000:2999'] DEFAULT_VLAN_RANGES = []
DEFAULT_TUNNEL_RANGES = [] DEFAULT_TUNNEL_RANGES = []
database_opts = [ database_opts = [
@ -34,6 +34,9 @@ ovs_opts = [
cfg.ListOpt('bridge_mappings', cfg.ListOpt('bridge_mappings',
default=DEFAULT_BRIDGE_MAPPINGS, default=DEFAULT_BRIDGE_MAPPINGS,
help="List of <physical_network>:<bridge>"), 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', cfg.ListOpt('network_vlan_ranges',
default=DEFAULT_VLAN_RANGES, default=DEFAULT_VLAN_RANGES,
help="List of <physical_network>:<vlan_min>:<vlan_max> " help="List of <physical_network>:<vlan_min>:<vlan_max> "

View File

@ -23,6 +23,8 @@ TUNNEL = 'tunnel'
TYPE_FLAT = 'flat' TYPE_FLAT = 'flat'
TYPE_VLAN = 'vlan' TYPE_VLAN = 'vlan'
TYPE_GRE = 'gre' TYPE_GRE = 'gre'
TYPE_LOCAL = 'local'
TYPE_NONE = 'none'
# Name prefixes for veth device pair linking the integration bridge # Name prefixes for veth device pair linking the integration bridge
# with the physical bridge for a physical network # with the physical bridge for a physical network

View File

@ -64,7 +64,8 @@ class NetworkBinding(model_base.BASEV2):
network_id = Column(String(36), network_id = Column(String(36),
ForeignKey('networks.id', ondelete="CASCADE"), ForeignKey('networks.id', ondelete="CASCADE"),
primary_key=True) 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)) physical_network = Column(String(64))
segmentation_id = Column(Integer) # tunnel_id or vlan_id 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) ovs_db_v2.sync_vlan_allocations(self.network_vlan_ranges)
self._parse_tunnel_id_ranges() self._parse_tunnel_id_ranges()
ovs_db_v2.sync_tunnel_allocations(self.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.agent_rpc = cfg.CONF.AGENT.rpc
self.setup_rpc() self.setup_rpc()
@ -280,6 +288,9 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
elif binding.network_type == constants.TYPE_VLAN: elif binding.network_type == constants.TYPE_VLAN:
network[provider.PHYSICAL_NETWORK] = binding.physical_network network[provider.PHYSICAL_NETWORK] = binding.physical_network
network[provider.SEGMENTATION_ID] = binding.segmentation_id 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): def _process_provider_create(self, context, attrs):
network_type = attrs.get(provider.NETWORK_TYPE) network_type = attrs.get(provider.NETWORK_TYPE)
@ -314,10 +325,34 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
msg = _("provider:segmentation_id out of range " msg = _("provider:segmentation_id out of range "
"(1 through 4094)") "(1 through 4094)")
raise q_exc.InvalidInput(error_message=msg) 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: else:
msg = _("invalid provider:network_type %s" % network_type) 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 = _("provider:network_type %s not supported" % network_type)
raise q_exc.InvalidInput(error_message=msg) raise q_exc.InvalidInput(error_message=msg)
if network_type in [constants.TYPE_VLAN, constants.TYPE_FLAT]:
if physical_network_set: if physical_network_set:
if physical_network not in self.network_vlan_ranges: if physical_network not in self.network_vlan_ranges:
msg = _("unknown provider:physical_network %s" % msg = _("unknown provider:physical_network %s" %
@ -358,16 +393,24 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
session = context.session session = context.session
with session.begin(subtransactions=True): with session.begin(subtransactions=True):
if not network_type: 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, (physical_network,
segmentation_id) = ovs_db_v2.reserve_vlan(session) segmentation_id) = ovs_db_v2.reserve_vlan(session)
network_type = constants.TYPE_VLAN elif network_type == constants.TYPE_GRE:
except q_exc.NoNetworkAvailable:
segmentation_id = ovs_db_v2.reserve_tunnel(session) segmentation_id = ovs_db_v2.reserve_tunnel(session)
network_type = constants.TYPE_GRE # no reservation needed for TYPE_LOCAL
else: else:
# provider network
if network_type in [constants.TYPE_VLAN, constants.TYPE_FLAT]:
ovs_db_v2.reserve_specific_vlan(session, physical_network, ovs_db_v2.reserve_specific_vlan(session, physical_network,
segmentation_id) 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, net = super(OVSQuantumPluginV2, self).create_network(context,
network) network)
ovs_db_v2.add_network_binding(session, net['id'], network_type, 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: if binding.network_type == constants.TYPE_GRE:
ovs_db_v2.release_tunnel(session, binding.segmentation_id, ovs_db_v2.release_tunnel(session, binding.segmentation_id,
self.tunnel_id_ranges) 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, ovs_db_v2.release_vlan(session, binding.physical_network,
binding.segmentation_id, binding.segmentation_id,
self.network_vlan_ranges) self.network_vlan_ranges)

View File

@ -32,11 +32,10 @@ class ConfigurationTest(unittest.TestCase):
cfg.CONF.AGENT.polling_interval) cfg.CONF.AGENT.polling_interval)
self.assertEqual('sudo', self.assertEqual('sudo',
cfg.CONF.AGENT.root_helper) cfg.CONF.AGENT.root_helper)
self.assertEqual('local',
ranges = cfg.CONF.VLANS.network_vlan_ranges cfg.CONF.VLANS.tenant_network_type)
self.assertEqual(1, len(ranges)) self.assertEqual(0,
self.assertEqual('default:1000:2999', ranges[0]) len(cfg.CONF.VLANS.network_vlan_ranges))
self.assertEqual(0,
mappings = cfg.CONF.LINUX_BRIDGE.physical_interface_mappings len(cfg.CONF.LINUX_BRIDGE.
self.assertEqual(1, len(mappings)) physical_interface_mappings))
self.assertEqual('default:eth1', mappings[0])

View File

@ -29,14 +29,7 @@ class ConfigurationTest(unittest.TestCase):
self.assertEqual(2, cfg.CONF.DATABASE.reconnect_interval) self.assertEqual(2, cfg.CONF.DATABASE.reconnect_interval)
self.assertEqual(2, cfg.CONF.AGENT.polling_interval) self.assertEqual(2, cfg.CONF.AGENT.polling_interval)
self.assertEqual('sudo', cfg.CONF.AGENT.root_helper) self.assertEqual('sudo', cfg.CONF.AGENT.root_helper)
self.assertEqual('local', cfg.CONF.OVS.tenant_network_type)
mappings = cfg.CONF.OVS.bridge_mappings self.assertEqual(0, len(cfg.CONF.OVS.bridge_mappings))
self.assertEqual(1, len(mappings)) self.assertEqual(0, len(cfg.CONF.OVS.network_vlan_ranges))
self.assertEqual('default:br-eth1', mappings[0]) self.assertEqual(0, len(cfg.CONF.OVS.tunnel_id_ranges))
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))