]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Added config variable for External Network type in ML2
authorAman Kumar <amank@hp.com>
Fri, 23 Jan 2015 09:34:00 +0000 (01:34 -0800)
committerAman Kumar <amank@hp.com>
Wed, 15 Apr 2015 04:59:22 +0000 (04:59 +0000)
Description:
With the ML2 Plugin, every network created has segments with
provider:network_types being tenant_network_types.
When applied to external networks, the types that could be in
tenant_network_types parameter (like vxlan or gre) are not appropriate.

Implementation:
Added new config variable 'external_network_type' in ml2_conf.ini
which contains the default network type for external networks
when no provider attributes are specified, by default it is None.

It also includes small code re-factoring/renaming of import statement.

DocImpact

Closes-Bug: #1328991

Co-Authored-By: Romil Gupta <romilg@hp.com>
Change-Id: Idbbe6bced73cfedbe0f8e7abba35f87589b1a004

etc/neutron/plugins/ml2/ml2_conf.ini
neutron/plugins/ml2/config.py
neutron/plugins/ml2/managers.py
neutron/tests/unit/plugins/ml2/test_plugin.py

index 9b8a461920255393f5ed4a39b85d8ab39b0aefa1..ac9a3d0de3ea65c96cda44f79320ce1fe825b098 100644 (file)
 # Example: physical_network_mtus = physnet1:1550, physnet2:1500
 # ======== 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]
 # (ListOpt) List of physical_network names with which flat networks
 # can be created. Use * to allow flat networks with arbitrary
index ddc1547fb8e3e09e1f7686b95896cfe7f1995db1..3eb3b2bd4a097a77b9ac52a461715ac6bc8ea1c0 100644 (file)
@@ -51,6 +51,15 @@ ml2_opts = [
                        "<physnet>:<mtu val>. This mapping allows "
                        "specifying a physical network MTU value that "
                        "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."))
 ]
 
 
index 3d31e8d9c7c596fbdf58cb0809c17e985eb26045..836d89dc5ce1e53345678661373a67a7f2366f53 100644 (file)
@@ -19,6 +19,7 @@ import stevedore
 
 from neutron.api.v2 import attributes
 from neutron.common import exceptions as exc
+from neutron.extensions import external_net
 from neutron.extensions import multiprovidernet as mpnet
 from neutron.extensions import portbindings
 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())
         self._register_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):
         for ext in self:
@@ -75,6 +77,12 @@ class TypeManager(stevedore.named.NamedExtensionManager):
                 raise SystemExit(1)
         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):
         (network_type, physical_network,
          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)):
             segments = [self._process_provider_segment(s)
                         for s in network[mpnet.SEGMENTS]]
-            mpnet.check_duplicate_segments(
-                segments,
-                self.is_partial_segment)
+            mpnet.check_duplicate_segments(segments, self.is_partial_segment)
             return segments
 
     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)
             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):
         """Call type drivers to create network segments."""
         segments = self._process_provider_create(network)
@@ -173,15 +185,15 @@ class TypeManager(stevedore.named.NamedExtensionManager):
                 for segment_index, segment in enumerate(segments):
                     segment = self.reserve_provider_segment(
                         session, segment)
-                    db.add_network_segment(session, network_id,
-                                           segment, segment_index)
-                    if segment.get(api.MTU) > 0:
-                        mtu.append(segment[api.MTU])
+                    self._add_network_segment(session, network_id, segment,
+                                              mtu, segment_index)
+            elif (cfg.CONF.ml2.external_network_type and
+                  self._get_attribute(network, external_net.EXTERNAL)):
+                segment = self._allocate_ext_net_segment(session)
+                self._add_network_segment(session, network_id, segment, mtu)
             else:
-                segment = self.allocate_tenant_segment(session)
-                db.add_network_segment(session, network_id, segment)
-                if segment.get(api.MTU) > 0:
-                    mtu.append(segment[api.MTU])
+                segment = self._allocate_tenant_net_segment(session)
+                self._add_network_segment(session, network_id, segment, mtu)
         network[api.MTU] = min(mtu) if mtu else 0
 
     def is_partial_segment(self, segment):
@@ -207,14 +219,24 @@ class TypeManager(stevedore.named.NamedExtensionManager):
         driver = self.drivers.get(network_type)
         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:
-            driver = self.drivers.get(network_type)
-            segment = driver.obj.allocate_tenant_segment(session)
+            segment = self._allocate_segment(session, network_type)
             if segment:
                 return segment
         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):
         segments = db.get_network_segments(session, network_id,
                                            filter_dynamic=None)
index 1d0d1378f4af74dead4236ea339c448135d40217..82f04ae6cbacdc7f092c1aa4e93cb14f431c7eab 100644 (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 l3_db
 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 portbindings
 from neutron.extensions import providernet as pnet
 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 import config
 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)
 
 
+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,
                        Ml2PluginV2TestCase):
     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):
         l3plugin = manager.NeutronManager.get_service_plugins().get(
-            service_constants.L3_ROUTER_NAT)
+            p_const.L3_ROUTER_NAT)
         kwargs = {'arg_list': (external_net.EXTERNAL,),
                   external_net.EXTERNAL: True}
         with self.network(**kwargs) as n:
@@ -471,7 +516,7 @@ class TestMl2PortsV2(test_plugin.TestPortsV2, Ml2PluginV2TestCase):
         ctx = context.get_admin_context()
         plugin = manager.NeutronManager.get_plugin()
         l3plugin = manager.NeutronManager.get_service_plugins().get(
-            service_constants.L3_ROUTER_NAT)
+            p_const.L3_ROUTER_NAT)
         with contextlib.nested(
             self.port(),
             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):
         ctx = context.get_admin_context()
         l3plugin = manager.NeutronManager.get_service_plugins().get(
-            service_constants.L3_ROUTER_NAT)
+            p_const.L3_ROUTER_NAT)
         with self.port() as port:
 
             port_id = port['port']['id']
@@ -593,7 +638,7 @@ class TestMl2DvrPortsV2(TestMl2PortsV2):
 
     def test_concurrent_csnat_port_delete(self):
         plugin = manager.NeutronManager.get_service_plugins()[
-            service_constants.L3_ROUTER_NAT]
+            p_const.L3_ROUTER_NAT]
         r = plugin.create_router(
             self.context,
             {'router': {'name': 'router', 'admin_state_up': True}})