Merge "Added config variable for External Network type in ML2"

This commit is contained in:
Jenkins 2015-04-17 09:13:58 +00:00 committed by Gerrit Code Review
commit c48ba4c7b0
4 changed files with 105 additions and 20 deletions

View File

@ -49,6 +49,15 @@
# Example: physical_network_mtus = physnet1:1550, physnet2:1500 # Example: physical_network_mtus = physnet1:1550, physnet2:1500
# ======== end of items for MTU selection and advertisement ========= # ======== end of items for MTU selection and advertisement =========
# (StrOpt) Default network type for external networks when no provider
# attributes are specified. By default it is None, which means that if
# provider attributes are not specified while creating external networks
# then they will have the same type as tenant networks.
# Allowed values for external_network_type config option depend on the
# network type values configured in type_drivers config option.
# external_network_type =
# Example: external_network_type = local
[ml2_type_flat] [ml2_type_flat]
# (ListOpt) List of physical_network names with which flat networks # (ListOpt) List of physical_network names with which flat networks
# can be created. Use * to allow flat networks with arbitrary # can be created. Use * to allow flat networks with arbitrary

View File

@ -51,6 +51,15 @@ ml2_opts = [
"<physnet>:<mtu val>. This mapping allows " "<physnet>:<mtu val>. This mapping allows "
"specifying a physical network MTU value that " "specifying a physical network MTU value that "
"differs from the default segment_mtu value.")), "differs from the default segment_mtu value.")),
cfg.StrOpt('external_network_type',
help=_("Default network type for external networks when no "
"provider attributes are specified. By default it is "
"None, which means that if provider attributes are not "
"specified while creating external networks then they "
"will have the same type as tenant networks. Allowed "
"values for external_network_type config option depend "
"on the network type values configured in type_drivers "
"config option."))
] ]

View File

@ -19,6 +19,7 @@ import stevedore
from neutron.api.v2 import attributes from neutron.api.v2 import attributes
from neutron.common import exceptions as exc from neutron.common import exceptions as exc
from neutron.extensions import external_net
from neutron.extensions import multiprovidernet as mpnet from neutron.extensions import multiprovidernet as mpnet
from neutron.extensions import portbindings from neutron.extensions import portbindings
from neutron.extensions import providernet as provider from neutron.extensions import providernet as provider
@ -49,6 +50,7 @@ class TypeManager(stevedore.named.NamedExtensionManager):
LOG.info(_LI("Loaded type driver names: %s"), self.names()) LOG.info(_LI("Loaded type driver names: %s"), self.names())
self._register_types() self._register_types()
self._check_tenant_network_types(cfg.CONF.ml2.tenant_network_types) self._check_tenant_network_types(cfg.CONF.ml2.tenant_network_types)
self._check_external_network_type(cfg.CONF.ml2.external_network_type)
def _register_types(self): def _register_types(self):
for ext in self: for ext in self:
@ -75,6 +77,12 @@ class TypeManager(stevedore.named.NamedExtensionManager):
raise SystemExit(1) raise SystemExit(1)
LOG.info(_LI("Tenant network_types: %s"), self.tenant_network_types) LOG.info(_LI("Tenant network_types: %s"), self.tenant_network_types)
def _check_external_network_type(self, ext_network_type):
if ext_network_type and ext_network_type not in self.drivers:
LOG.error(_LE("No type driver for external network_type: %s. "
"Service terminated!"), ext_network_type)
raise SystemExit(1)
def _process_provider_segment(self, segment): def _process_provider_segment(self, segment):
(network_type, physical_network, (network_type, physical_network,
segmentation_id) = (self._get_attribute(segment, attr) segmentation_id) = (self._get_attribute(segment, attr)
@ -102,9 +110,7 @@ class TypeManager(stevedore.named.NamedExtensionManager):
elif attributes.is_attr_set(network.get(mpnet.SEGMENTS)): elif attributes.is_attr_set(network.get(mpnet.SEGMENTS)):
segments = [self._process_provider_segment(s) segments = [self._process_provider_segment(s)
for s in network[mpnet.SEGMENTS]] for s in network[mpnet.SEGMENTS]]
mpnet.check_duplicate_segments( mpnet.check_duplicate_segments(segments, self.is_partial_segment)
segments,
self.is_partial_segment)
return segments return segments
def _match_segment(self, segment, filters): def _match_segment(self, segment, filters):
@ -162,6 +168,12 @@ class TypeManager(stevedore.named.NamedExtensionManager):
LOG.info(_LI("Initializing driver for type '%s'"), network_type) LOG.info(_LI("Initializing driver for type '%s'"), network_type)
driver.obj.initialize() driver.obj.initialize()
def _add_network_segment(self, session, network_id, segment, mtu,
segment_index=0):
db.add_network_segment(session, network_id, segment, segment_index)
if segment.get(api.MTU) > 0:
mtu.append(segment[api.MTU])
def create_network_segments(self, context, network, tenant_id): def create_network_segments(self, context, network, tenant_id):
"""Call type drivers to create network segments.""" """Call type drivers to create network segments."""
segments = self._process_provider_create(network) segments = self._process_provider_create(network)
@ -173,15 +185,15 @@ class TypeManager(stevedore.named.NamedExtensionManager):
for segment_index, segment in enumerate(segments): for segment_index, segment in enumerate(segments):
segment = self.reserve_provider_segment( segment = self.reserve_provider_segment(
session, segment) session, segment)
db.add_network_segment(session, network_id, self._add_network_segment(session, network_id, segment,
segment, segment_index) mtu, segment_index)
if segment.get(api.MTU) > 0: elif (cfg.CONF.ml2.external_network_type and
mtu.append(segment[api.MTU]) self._get_attribute(network, external_net.EXTERNAL)):
segment = self._allocate_ext_net_segment(session)
self._add_network_segment(session, network_id, segment, mtu)
else: else:
segment = self.allocate_tenant_segment(session) segment = self._allocate_tenant_net_segment(session)
db.add_network_segment(session, network_id, segment) self._add_network_segment(session, network_id, segment, mtu)
if segment.get(api.MTU) > 0:
mtu.append(segment[api.MTU])
network[api.MTU] = min(mtu) if mtu else 0 network[api.MTU] = min(mtu) if mtu else 0
def is_partial_segment(self, segment): def is_partial_segment(self, segment):
@ -207,14 +219,24 @@ class TypeManager(stevedore.named.NamedExtensionManager):
driver = self.drivers.get(network_type) driver = self.drivers.get(network_type)
return driver.obj.reserve_provider_segment(session, segment) return driver.obj.reserve_provider_segment(session, segment)
def allocate_tenant_segment(self, session): def _allocate_segment(self, session, network_type):
driver = self.drivers.get(network_type)
return driver.obj.allocate_tenant_segment(session)
def _allocate_tenant_net_segment(self, session):
for network_type in self.tenant_network_types: for network_type in self.tenant_network_types:
driver = self.drivers.get(network_type) segment = self._allocate_segment(session, network_type)
segment = driver.obj.allocate_tenant_segment(session)
if segment: if segment:
return segment return segment
raise exc.NoNetworkAvailable() raise exc.NoNetworkAvailable()
def _allocate_ext_net_segment(self, session):
network_type = cfg.CONF.ml2.external_network_type
segment = self._allocate_segment(session, network_type)
if segment:
return segment
raise exc.NoNetworkAvailable()
def release_network_segments(self, session, network_id): def release_network_segments(self, session, network_id):
segments = db.get_network_segments(session, network_id, segments = db.get_network_segments(session, network_id,
filter_dynamic=None) filter_dynamic=None)

View File

@ -33,12 +33,12 @@ from neutron.db import api as db_api
from neutron.db import db_base_plugin_v2 as base_plugin from neutron.db import db_base_plugin_v2 as base_plugin
from neutron.db import l3_db from neutron.db import l3_db
from neutron.db import models_v2 from neutron.db import models_v2
from neutron.extensions import external_net as external_net from neutron.extensions import external_net
from neutron.extensions import multiprovidernet as mpnet from neutron.extensions import multiprovidernet as mpnet
from neutron.extensions import portbindings from neutron.extensions import portbindings
from neutron.extensions import providernet as pnet from neutron.extensions import providernet as pnet
from neutron import manager from neutron import manager
from neutron.plugins.common import constants as service_constants from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2.common import exceptions as ml2_exc from neutron.plugins.ml2.common import exceptions as ml2_exc
from neutron.plugins.ml2 import config from neutron.plugins.ml2 import config
from neutron.plugins.ml2 import db as ml2_db from neutron.plugins.ml2 import db as ml2_db
@ -267,6 +267,51 @@ class TestMl2NetworksV2(test_plugin.TestNetworksV2,
self.assertEqual(db_api.MAX_RETRIES + 1, f.call_count) self.assertEqual(db_api.MAX_RETRIES + 1, f.call_count)
class TestExternalNetwork(Ml2PluginV2TestCase):
def _create_external_network(self):
data = {'network': {'name': 'net1',
'router:external': 'True',
'tenant_id': 'tenant_one'}}
network_req = self.new_create_request('networks', data)
network = self.deserialize(self.fmt,
network_req.get_response(self.api))
return network
def test_external_network_type_none(self):
config.cfg.CONF.set_default('external_network_type',
None,
group='ml2')
network = self._create_external_network()
# For external network, expected network type to be
# tenant_network_types which is by default 'local'.
self.assertEqual(p_const.TYPE_LOCAL,
network['network'][pnet.NETWORK_TYPE])
# No physical network specified, expected 'None'.
self.assertIsNone(network['network'][pnet.PHYSICAL_NETWORK])
# External network will not have a segmentation id.
self.assertIsNone(network['network'][pnet.SEGMENTATION_ID])
# External network will not have multiple segments.
self.assertNotIn(mpnet.SEGMENTS, network['network'])
def test_external_network_type_vlan(self):
config.cfg.CONF.set_default('external_network_type',
p_const.TYPE_VLAN,
group='ml2')
network = self._create_external_network()
# For external network, expected network type to be 'vlan'.
self.assertEqual(p_const.TYPE_VLAN,
network['network'][pnet.NETWORK_TYPE])
# Physical network is expected.
self.assertIsNotNone(network['network'][pnet.PHYSICAL_NETWORK])
# External network will have a segmentation id.
self.assertIsNotNone(network['network'][pnet.SEGMENTATION_ID])
# External network will not have multiple segments.
self.assertNotIn(mpnet.SEGMENTS, network['network'])
class TestMl2SubnetsV2(test_plugin.TestSubnetsV2, class TestMl2SubnetsV2(test_plugin.TestSubnetsV2,
Ml2PluginV2TestCase): Ml2PluginV2TestCase):
def test_delete_subnet_race_with_dhcp_port_creation(self): def test_delete_subnet_race_with_dhcp_port_creation(self):
@ -352,7 +397,7 @@ class TestMl2PortsV2(test_plugin.TestPortsV2, Ml2PluginV2TestCase):
def test_l3_cleanup_on_net_delete(self): def test_l3_cleanup_on_net_delete(self):
l3plugin = manager.NeutronManager.get_service_plugins().get( l3plugin = manager.NeutronManager.get_service_plugins().get(
service_constants.L3_ROUTER_NAT) p_const.L3_ROUTER_NAT)
kwargs = {'arg_list': (external_net.EXTERNAL,), kwargs = {'arg_list': (external_net.EXTERNAL,),
external_net.EXTERNAL: True} external_net.EXTERNAL: True}
with self.network(**kwargs) as n: with self.network(**kwargs) as n:
@ -471,7 +516,7 @@ class TestMl2PortsV2(test_plugin.TestPortsV2, Ml2PluginV2TestCase):
ctx = context.get_admin_context() ctx = context.get_admin_context()
plugin = manager.NeutronManager.get_plugin() plugin = manager.NeutronManager.get_plugin()
l3plugin = manager.NeutronManager.get_service_plugins().get( l3plugin = manager.NeutronManager.get_service_plugins().get(
service_constants.L3_ROUTER_NAT) p_const.L3_ROUTER_NAT)
with contextlib.nested( with contextlib.nested(
self.port(), self.port(),
mock.patch.object(l3plugin, 'disassociate_floatingips'), mock.patch.object(l3plugin, 'disassociate_floatingips'),
@ -507,7 +552,7 @@ class TestMl2PortsV2(test_plugin.TestPortsV2, Ml2PluginV2TestCase):
def test_disassociate_floatingips_do_notify_returns_nothing(self): def test_disassociate_floatingips_do_notify_returns_nothing(self):
ctx = context.get_admin_context() ctx = context.get_admin_context()
l3plugin = manager.NeutronManager.get_service_plugins().get( l3plugin = manager.NeutronManager.get_service_plugins().get(
service_constants.L3_ROUTER_NAT) p_const.L3_ROUTER_NAT)
with self.port() as port: with self.port() as port:
port_id = port['port']['id'] port_id = port['port']['id']
@ -593,7 +638,7 @@ class TestMl2DvrPortsV2(TestMl2PortsV2):
def test_concurrent_csnat_port_delete(self): def test_concurrent_csnat_port_delete(self):
plugin = manager.NeutronManager.get_service_plugins()[ plugin = manager.NeutronManager.get_service_plugins()[
service_constants.L3_ROUTER_NAT] p_const.L3_ROUTER_NAT]
r = plugin.create_router( r = plugin.create_router(
self.context, self.context,
{'router': {'name': 'router', 'admin_state_up': True}}) {'router': {'name': 'router', 'admin_state_up': True}})