From 4a95ba95f8b25d28f1c6b757c9e72676fe9151cf Mon Sep 17 00:00:00 2001 From: Boden R Date: Tue, 9 Feb 2016 15:29:56 -0700 Subject: [PATCH] NSX-v3 disable psec per port The current impl of NSX v3 port security does not remove the spoofguard profile from the respective NSX port when port security is disabled from neutron. In addition the address pairs are removed upon port security disablement. Unit tests are also included. backport: liberty Change-Id: Iad716b19a9a9439be0f372ef35f33d9c4ec39600 Closes-Bug: #1543694 --- vmware_nsx/nsxlib/v3/resources.py | 6 ++++ vmware_nsx/plugins/nsx_v3/plugin.py | 12 +++++++- vmware_nsx/tests/unit/nsx_v3/test_plugin.py | 17 +++++++---- .../tests/unit/nsxlib/v3/test_resources.py | 29 +++++++++++++++++++ 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/vmware_nsx/nsxlib/v3/resources.py b/vmware_nsx/nsxlib/v3/resources.py index e531d7f103..fdd4bb677c 100644 --- a/vmware_nsx/nsxlib/v3/resources.py +++ b/vmware_nsx/nsxlib/v3/resources.py @@ -88,6 +88,9 @@ class SwitchingProfile(AbstractRESTResource): def uri_segment(self): return 'switching-profiles' + def list(self): + return self._client.url_get('?include_system_owned=True') + def create(self, profile_type, display_name=None, description=None, **api_args): body = { @@ -202,6 +205,9 @@ class LogicalPort(AbstractRESTResource): address_classifier['vlan'] = int(binding.vlan) bindings.append(address_classifier) body['address_bindings'] = bindings + elif address_bindings == []: + # explicitly clear out address bindings + body['address_bindings'] = [] if switch_profile_ids: profiles = [] diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py index b801f5a0ef..980dc55c51 100644 --- a/vmware_nsx/plugins/nsx_v3/plugin.py +++ b/vmware_nsx/plugins/nsx_v3/plugin.py @@ -78,6 +78,7 @@ from vmware_nsx.nsxlib.v3 import security LOG = log.getLogger(__name__) NSX_V3_PSEC_PROFILE_NAME = 'neutron_port_spoof_guard_profile' +NSX_V3_NO_PSEC_PROFILE_NAME = 'nsx-default-spoof-guard-vif-profile' NSX_V3_DHCP_PROFILE_NAME = 'neutron_port_dhcp_profile' @@ -149,6 +150,11 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, msg = _("Unable to initialize NSX v3 port spoofguard " "switching profile: %s") % NSX_V3_PSEC_PROFILE_NAME raise nsx_exc.NsxPluginException(msg) + profiles = nsx_resources.SwitchingProfile + self._no_psec_profile_id = profiles.build_switch_profile_ids( + self._switching_profiles, + self._switching_profiles.find_by_display_name( + NSX_V3_NO_PSEC_PROFILE_NAME)[0])[0] LOG.debug("Initializing NSX v3 DHCP switching profile") self._dhcp_profile = None self._dhcp_profile = self._init_dhcp_switching_profile() @@ -651,7 +657,8 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, parent_name, tag = self._get_data_from_binding_profile( context, port_data) - address_bindings = self._build_address_bindings(port_data) + address_bindings = (self._build_address_bindings(port_data) + if psec_is_on else []) vif_uuid = port_data['id'] attachment_type = nsx_constants.ATTACHMENT_VIF if not device_owner or device_owner == l3_db.DEVICE_OWNER_ROUTER_INTF: @@ -1000,6 +1007,9 @@ class NsxV3Plugin(addr_pair_db.AllowedAddressPairsMixin, address_bindings = self._build_address_bindings(updated_port) if port_security and address_bindings: switch_profile_ids = [self._get_port_security_profile_id()] + else: + switch_profile_ids = [self._no_psec_profile_id] + address_bindings = [] try: self._update_port_on_backend(context, nsx_lport_id, diff --git a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py index 5165d350be..b54c881060 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py @@ -94,11 +94,6 @@ class NsxV3PluginTestCaseMixin(test_plugin.NeutronDbPluginV2TestCase, _patch_object(nsx_plugin, 'nsx_client', new=mock_client_module) _patch_object(nsx_plugin, 'nsx_cluster', new=mock_cluster_module) - super(NsxV3PluginTestCaseMixin, self).setUp(plugin=plugin, - ext_mgr=ext_mgr) - - self.maxDiff = None - # populate pre-existing mock resources cluster_id = uuidutils.generate_uuid() self.mock_api.post( @@ -120,6 +115,18 @@ class NsxV3PluginTestCaseMixin(test_plugin.NeutronDbPluginV2TestCase, ]}), headers=nsx_client.JSONRESTClient._DEFAULT_HEADERS) + self.mock_api.post( + 'api/v1/switching-profiles', + data=jsonutils.dumps({ + 'id': uuidutils.generate_uuid(), + 'display_name': nsx_plugin.NSX_V3_NO_PSEC_PROFILE_NAME + }), headers=nsx_client.JSONRESTClient._DEFAULT_HEADERS) + + super(NsxV3PluginTestCaseMixin, self).setUp(plugin=plugin, + ext_mgr=ext_mgr) + + self.maxDiff = None + def tearDown(self): for patcher in self._patchers: patcher.stop() diff --git a/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py b/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py index 0b16f54bdc..678c50b20b 100644 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py +++ b/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py @@ -13,6 +13,8 @@ # License for the specific language governing permissions and limitations # under the License. # +import copy + import mock from oslo_serialization import jsonutils @@ -184,6 +186,15 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): self.assertEqual(resp_resources['results'], mocked_resource.find_by_display_name('resource-1')) + def test_list_all_profiles(self): + mocked_resource = self._mocked_switching_profile() + mocked_resource.list() + test_client.assert_json_call( + 'get', mocked_resource, + 'https://1.2.3.4/api/v1/switching-profiles/' + '?include_system_owned=True', + data=None) + class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase): @@ -272,6 +283,24 @@ class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase): 'delete', mocked_resource, 'https://1.2.3.4/api/v1/logical-ports/%s?detach=true' % uuid) + def test_clear_port_bindings(self): + fake_port = copy.copy(test_constants_v3.FAKE_PORT) + fake_port['address_bindings'] = ['a', 'b'] + mocked_resource = self._mocked_lport() + + def get_fake_port(*args): + return fake_port + + mocked_resource.get = get_fake_port + mocked_resource.update( + fake_port['id'], fake_port['id'], address_bindings=[]) + + fake_port['address_bindings'] = [] + test_client.assert_json_call( + 'put', mocked_resource, + 'https://1.2.3.4/api/v1/logical-ports/%s' % fake_port['id'], + data=jsonutils.dumps(fake_port, sort_keys=True)) + class LogicalRouterTestCase(nsxlib_testcase.NsxClientTestCase):