From be6f7e2bc0fce4e5ecb6a09dda225f9f70a75934 Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Thu, 9 Nov 2017 10:50:24 +0200 Subject: [PATCH] Logical switch trunk vlan support Adding support for trunk vlan for logical switches in NSX 2.2 and up This flag can be used for guest vlan, and is mutual exclusive from the vlan id. Change-Id: I0d08a84df796c226678a27c29cdd1e637f356e72 --- vmware_nsxlib/tests/unit/v3/test_resources.py | 55 ++++++++++++++++++- vmware_nsxlib/v3/__init__.py | 3 +- vmware_nsxlib/v3/core_resources.py | 38 ++++++++++++- vmware_nsxlib/v3/nsx_constants.py | 1 + 4 files changed, 94 insertions(+), 3 deletions(-) diff --git a/vmware_nsxlib/tests/unit/v3/test_resources.py b/vmware_nsxlib/tests/unit/v3/test_resources.py index 8a71bfb7..5252ca1a 100644 --- a/vmware_nsxlib/tests/unit/v3/test_resources.py +++ b/vmware_nsxlib/tests/unit/v3/test_resources.py @@ -1164,7 +1164,7 @@ class NsxLibSwitchTestCase(BaseTestResource): self._tz_id = uuidutils.generate_uuid() def _create_body(self, admin_state=nsx_constants.ADMIN_STATE_UP, - vlan_id=None, description=None): + vlan_id=None, description=None, trunk_vlan=None): body = { "transport_zone_id": self._tz_id, "replication_mode": "MTEP", @@ -1176,6 +1176,10 @@ class NsxLibSwitchTestCase(BaseTestResource): body['vlan'] = vlan_id if description is not None: body['description'] = description + if trunk_vlan: + body['vlan_trunk_spec'] = { + 'vlan_ranges': [{'start': trunk_vlan[0], + 'end': trunk_vlan[1]}]} return body def test_create_logical_switch(self): @@ -1218,6 +1222,55 @@ class NsxLibSwitchTestCase(BaseTestResource): data=jsonutils.dumps(data, sort_keys=True), headers=self.default_headers()) + def test_create_logical_switch_trunk(self): + """Test creating switch with trunk vlan""" + ls = self.get_mocked_resource() + trunk_vlan = [10, 20] + with mock.patch("vmware_nsxlib.v3.NsxLib.get_version", + return_value='2.2.0'): + ls.create(mocks.FAKE_NAME, self._tz_id, [], + trunk_vlan_range=trunk_vlan) + data = self._create_body(trunk_vlan=trunk_vlan) + test_client.assert_json_call( + 'post', ls, + 'https://1.2.3.4/api/v1/logical-switches', + data=jsonutils.dumps(data, sort_keys=True), + headers=self.default_headers()) + + def test_create_logical_switch_trunk_not_supported(self): + """Test creating switch with trunk vlan without the support""" + ls = self.get_mocked_resource() + trunk_vlan = [10, 20] + with mock.patch("vmware_nsxlib.v3.NsxLib.get_version", + return_value='2.0.0'): + self.assertRaises(exceptions.InvalidInput, + ls.create, + mocks.FAKE_NAME, self._tz_id, [], + trunk_vlan_range=trunk_vlan) + + def test_create_logical_switch_trunk_with_vlan(self): + """Test creating switch with trunk vlan and vlan tag""" + ls = self.get_mocked_resource() + trunk_vlan = [10, 20] + with mock.patch("vmware_nsxlib.v3.NsxLib.get_version", + return_value='2.2.0'): + self.assertRaises(exceptions.InvalidInput, + ls.create, + mocks.FAKE_NAME, self._tz_id, [], + trunk_vlan_range=trunk_vlan, + vlan_id='111') + + def test_create_logical_switch_illegal_trunk(self): + """Test creating switch with illegal trunk vlan""" + ls = self.get_mocked_resource() + trunk_vlan = [10] + with mock.patch("vmware_nsxlib.v3.NsxLib.get_version", + return_value='2.2.0'): + self.assertRaises(exceptions.InvalidInput, + ls.create, + mocks.FAKE_NAME, self._tz_id, [], + trunk_vlan_range=trunk_vlan) + def test_delete_resource(self): """Test deleting switch""" super(NsxLibSwitchTestCase, self).test_delete_resource( diff --git a/vmware_nsxlib/v3/__init__.py b/vmware_nsxlib/v3/__init__.py index 4d9ef592..97b1d992 100644 --- a/vmware_nsxlib/v3/__init__.py +++ b/vmware_nsxlib/v3/__init__.py @@ -274,7 +274,8 @@ class NsxLib(NsxLibBase): # Features available since 2.2 if (feature == nsx_constants.FEATURE_VLAN_ROUTER_INTERFACE or feature == nsx_constants.FEATURE_IPSEC_VPN or - feature == nsx_constants.FEATURE_ON_BEHALF_OF): + feature == nsx_constants.FEATURE_ON_BEHALF_OF or + feature == nsx_constants.FEATURE_TRUNK_VLAN): return True if (version.LooseVersion(self.get_version()) >= diff --git a/vmware_nsxlib/v3/core_resources.py b/vmware_nsxlib/v3/core_resources.py index 1677503e..d19c5013 100644 --- a/vmware_nsxlib/v3/core_resources.py +++ b/vmware_nsxlib/v3/core_resources.py @@ -121,7 +121,9 @@ class NsxLibLogicalSwitch(utils.NsxLibApiBase): def create(self, display_name, transport_zone_id, tags, replication_mode=nsx_constants.MTEP, admin_state=True, vlan_id=None, ip_pool_id=None, - mac_pool_id=None, description=None): + mac_pool_id=None, description=None, + trunk_vlan_range=None): + operation = "Create logical switch" # TODO(salv-orlando): Validate Replication mode and admin_state # NOTE: These checks might be moved to the API client library if one # that performs such checks in the client is available @@ -138,6 +140,40 @@ class NsxLibLogicalSwitch(utils.NsxLibApiBase): if vlan_id: body['vlan'] = vlan_id + # trunk_vlan_range is mutually exclusive with vlan_id + # For guest vlan tagging it is allowed for overlay networks + # TODO(asarfaty): check network type? different for ENS? + if trunk_vlan_range: + failed = False + if (self.nsxlib and + self.nsxlib.feature_supported( + nsx_constants.FEATURE_TRUNK_VLAN)): + if vlan_id is not None: + failed = True + LOG.error("Failed to create logical switch %(name)s with " + "trunk vlan: vlan id %(vlan)s is used.", + {'name': display_name, 'vlan': vlan_id}) + elif (len(trunk_vlan_range) != 2 or + trunk_vlan_range[0] > trunk_vlan_range[1]): + failed = True + LOG.error("Failed to create logical switch %(name)s with " + "trunk vlan: illegal range (%(trunk)s) is used.", + {'name': display_name, + 'trunk': trunk_vlan_range}) + else: + body['vlan_trunk_spec'] = {'vlan_ranges': [ + {'start': trunk_vlan_range[0], + 'end': trunk_vlan_range[1]}]} + else: + LOG.error("Failed to create logical switch %s with trunk " + "vlan: this feature is not supported.", display_name) + failed = True + if failed: + raise exceptions.InvalidInput( + operation=operation, + arg_val=trunk_vlan_range, + arg_name='trunk_vlan_range') + if ip_pool_id: body['ip_pool_id'] = ip_pool_id diff --git a/vmware_nsxlib/v3/nsx_constants.py b/vmware_nsxlib/v3/nsx_constants.py index c7aae5e3..116f0463 100644 --- a/vmware_nsxlib/v3/nsx_constants.py +++ b/vmware_nsxlib/v3/nsx_constants.py @@ -137,3 +137,4 @@ FEATURE_NSX_POLICY = 'NSX Policy' FEATURE_VLAN_ROUTER_INTERFACE = 'VLAN Router Interface' FEATURE_IPSEC_VPN = 'IPSec VPN' FEATURE_ON_BEHALF_OF = 'On Behalf Of' +FEATURE_TRUNK_VLAN = 'Trunk Vlan'