From 7dbe0d0486ecb5269463a2660f2d040f5879396d Mon Sep 17 00:00:00 2001 From: Pritesh Kothari Date: Mon, 23 Feb 2015 09:52:28 -0800 Subject: [PATCH] Adding VLAN Transparency support for ML2 along with REST API changes * Exposing vlan transparency attributes via the network api calls so POST and GET operations can be performed. * Tied in the vlan transparency attribute with create network call and use the config default. * Update the unit test to cover vlan tranparency. * Add support for ml2 to take advantage of vlan transparency attribute. DocImpact APIImpact Partially Implements: blueprint nfv-vlan-trunks Change-Id: Ie87087a70b83dab589419aa5c17ce7ccafd64cbd --- etc/neutron.conf | 7 +++++++ neutron/api/v2/attributes.py | 3 +++ neutron/common/config.py | 3 +++ neutron/db/db_base_plugin_v2.py | 2 ++ neutron/plugins/ml2/common/exceptions.py | 5 +++++ neutron/plugins/ml2/driver_api.py | 9 +++++++++ neutron/plugins/ml2/managers.py | 14 ++++++++++++++ neutron/tests/functional/api/test_v2_plugin.py | 1 + neutron/tests/unit/test_api_v2.py | 5 ++++- neutron/tests/unit/test_db_plugin.py | 10 ++++++++-- neutron/tests/unit/test_extension_pnet.py | 1 + 11 files changed, 57 insertions(+), 3 deletions(-) diff --git a/etc/neutron.conf b/etc/neutron.conf index eb25c7503..02ce4f1db 100644 --- a/etc/neutron.conf +++ b/etc/neutron.conf @@ -207,6 +207,13 @@ lock_path = $state_path/lock # l3_ha_net_cidr = 169.254.192.0/18 # =========== end of items for l3 extension ======= +# ========== items for VLAN trunking networks ========== +# Setting this flag to True will allow plugins that support it to +# create VLAN transparent networks. This flag has no effect for +# plugins that do not support VLAN transparent networks. +# vlan_transparent = False +# ========== end of items for VLAN trunking networks ========== + # =========== WSGI parameters related to the API server ============== # Number of separate worker processes to spawn. The default, 0, runs the # worker thread in the current process. Greater than 0 launches that number of diff --git a/neutron/api/v2/attributes.py b/neutron/api/v2/attributes.py index 8235e000f..a776ac428 100644 --- a/neutron/api/v2/attributes.py +++ b/neutron/api/v2/attributes.py @@ -698,6 +698,9 @@ RESOURCE_ATTRIBUTE_MAP = { 'validate': {'type:string': None}, 'required_by_policy': True, 'is_visible': True}, + 'vlan_transparent': {'allow_post': True, 'allow_put': False, + 'convert_to': convert_to_boolean, + 'default': False, 'is_visible': True}, SHARED: {'allow_post': True, 'allow_put': True, 'default': False, diff --git a/neutron/common/config.py b/neutron/common/config.py index a0572c94e..11c505997 100644 --- a/neutron/common/config.py +++ b/neutron/common/config.py @@ -125,6 +125,9 @@ core_opts = [ help=_('If True, effort is made to advertise MTU settings ' 'to VMs via network methods (DHCP and RA MTU options) ' 'when the network\'s preferred MTU is known.')), + cfg.BoolOpt('vlan_transparent', default=False, + help=_('If True, then allow plugins that support it to ' + 'create VLAN transparent networks.')), ] core_cli_opts = [ diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py index 8950da5b4..fad9665e7 100644 --- a/neutron/db/db_base_plugin_v2.py +++ b/neutron/db/db_base_plugin_v2.py @@ -784,6 +784,7 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, 'mtu': network.get('mtu', constants.DEFAULT_NETWORK_MTU), 'status': network['status'], 'shared': network['shared'], + 'vlan_transparent': network['vlan_transparent'], 'subnets': [subnet['id'] for subnet in network['subnets']]} # Call auxiliary extend functions, if any @@ -872,6 +873,7 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, 'admin_state_up': n['admin_state_up'], 'mtu': n.get('mtu', constants.DEFAULT_NETWORK_MTU), 'shared': n['shared'], + 'vlan_transparent': n.get('vlan_transparent', False), 'status': n.get('status', constants.NET_STATUS_ACTIVE)} network = models_v2.Network(**args) context.session.add(network) diff --git a/neutron/plugins/ml2/common/exceptions.py b/neutron/plugins/ml2/common/exceptions.py index ed94b1e1f..41f46944f 100644 --- a/neutron/plugins/ml2/common/exceptions.py +++ b/neutron/plugins/ml2/common/exceptions.py @@ -21,3 +21,8 @@ from neutron.common import exceptions class MechanismDriverError(exceptions.NeutronException): """Mechanism driver call failed.""" message = _("%(method)s failed.") + + +class VlanTransparencyError(exceptions.NeutronException): + """Vlan Transparency not supported by all mechanism drivers.""" + message = _("Backend does not support VLAN Transparency.") diff --git a/neutron/plugins/ml2/driver_api.py b/neutron/plugins/ml2/driver_api.py index 894a5c3d3..15503ff36 100644 --- a/neutron/plugins/ml2/driver_api.py +++ b/neutron/plugins/ml2/driver_api.py @@ -811,6 +811,15 @@ class MechanismDriver(object): """ pass + def check_vlan_transparency(self, context): + """Check if the network supports vlan transparency. + + :param context: NetworkContext instance describing the network. + + Check if the network supports vlan transparency or not. + """ + pass + @six.add_metaclass(abc.ABCMeta) class ExtensionDriver(object): diff --git a/neutron/plugins/ml2/managers.py b/neutron/plugins/ml2/managers.py index 1d4a2162b..df932c66b 100644 --- a/neutron/plugins/ml2/managers.py +++ b/neutron/plugins/ml2/managers.py @@ -293,6 +293,19 @@ class MechanismManager(stevedore.named.NamedExtensionManager): LOG.info(_LI("Initializing mechanism driver '%s'"), driver.name) driver.obj.initialize() + def _check_vlan_transparency(self, context): + """Helper method for checking vlan transparecncy support. + + :param context: context parameter to pass to each method call + :raises: neutron.plugins.ml2.common.VlanTransparencyError + if any mechanism driver doesn't support vlan transparency. + """ + if not cfg.CONF.vlan_transparent: + return + for driver in self.ordered_mech_drivers: + if driver.obj.check_vlan_transparency(context) is False: + raise ml2_exc.VlanTransparencyError() + def _call_on_drivers(self, method_name, context, continue_on_failure=False): """Helper method for calling a method across all mechanism drivers. @@ -332,6 +345,7 @@ class MechanismManager(stevedore.named.NamedExtensionManager): to the caller, triggering a rollback. There is no guarantee that all mechanism drivers are called in this case. """ + self._check_vlan_transparency(context) self._call_on_drivers("create_network_precommit", context) def create_network_postcommit(self, context): diff --git a/neutron/tests/functional/api/test_v2_plugin.py b/neutron/tests/functional/api/test_v2_plugin.py index 081f6df74..76eafe5b1 100644 --- a/neutron/tests/functional/api/test_v2_plugin.py +++ b/neutron/tests/functional/api/test_v2_plugin.py @@ -65,6 +65,7 @@ class PluginClient(base_v2.BaseNeutronClient): # Supply defaults that are expected to be set by the api # framwork kwargs.setdefault('admin_state_up', True) + kwargs.setdefault('vlan_transparent', False) kwargs.setdefault('shared', False) data = dict(network=kwargs) result = self.plugin.create_network(self.ctx, data) diff --git a/neutron/tests/unit/test_api_v2.py b/neutron/tests/unit/test_api_v2.py index 75d2a26e2..de9d079c4 100644 --- a/neutron/tests/unit/test_api_v2.py +++ b/neutron/tests/unit/test_api_v2.py @@ -768,6 +768,7 @@ class JSONV2TestCase(APIv2TestBase, testlib_api.WebTestCase): net_id = _uuid() initial_input = {'network': {'name': 'net1', 'tenant_id': _uuid()}} full_input = {'network': {'admin_state_up': True, + 'vlan_transparent': False, 'shared': False}} full_input['network'].update(initial_input['network']) @@ -802,6 +803,7 @@ class JSONV2TestCase(APIv2TestBase, testlib_api.WebTestCase): # tenant_id should be fetched from env initial_input = {'network': {'name': 'net1'}} full_input = {'network': {'admin_state_up': True, + 'vlan_transparent': False, 'shared': False, 'tenant_id': tenant_id}} full_input['network'].update(initial_input['network']) @@ -1411,7 +1413,8 @@ class ExtensionTestCase(base.BaseTestCase, testlib_plugin.PluginSetupHelper): net_id = _uuid() initial_input = {'network': {'name': 'net1', 'tenant_id': _uuid(), 'v2attrs:something_else': "abc"}} - data = {'network': {'admin_state_up': True, 'shared': False}} + data = {'network': {'admin_state_up': True, 'shared': False, + 'vlan_transparent': False}} data['network'].update(initial_input['network']) return_value = {'subnets': [], 'status': "ACTIVE", diff --git a/neutron/tests/unit/test_db_plugin.py b/neutron/tests/unit/test_db_plugin.py index 2e727953e..ff7246212 100644 --- a/neutron/tests/unit/test_db_plugin.py +++ b/neutron/tests/unit/test_db_plugin.py @@ -296,8 +296,8 @@ class NeutronDbPluginV2TestCase(testlib_api.WebTestCase, data = {'network': {'name': name, 'admin_state_up': admin_state_up, 'tenant_id': self._tenant_id}} - for arg in (('admin_state_up', 'tenant_id', 'shared') + - (arg_list or ())): + for arg in (('admin_state_up', 'tenant_id', 'shared', + 'vlan_transparent') + (arg_list or ())): # Arg must be present if arg in kwargs: data['network'][arg] = kwargs[arg] @@ -2033,6 +2033,12 @@ class TestNetworksV2(NeutronDbPluginV2TestCase): self.assertEqual(net['network']['mtu'], constants.DEFAULT_NETWORK_MTU) + def test_create_network_vlan_transparent(self): + name = "vlan_transparent" + cfg.CONF.set_override('vlan_transparent', True) + with self.network(name=name, vlan_transparent=True) as net: + self.assertEqual(net['network']['vlan_transparent'], True) + def test_update_network(self): with self.network() as network: data = {'network': {'name': 'a_brand_new_name'}} diff --git a/neutron/tests/unit/test_extension_pnet.py b/neutron/tests/unit/test_extension_pnet.py index 420745986..a2bf86757 100644 --- a/neutron/tests/unit/test_extension_pnet.py +++ b/neutron/tests/unit/test_extension_pnet.py @@ -141,6 +141,7 @@ class ProvidernetExtensionTestCase(testlib_api.WebTestCase, exp_input = {'network': data} exp_input['network'].update({'admin_state_up': True, 'tenant_id': 'an_admin', + 'vlan_transparent': False, 'shared': False}) instance.create_network.assert_called_with(mock.ANY, network=exp_input) -- 2.45.2