diff --git a/vmware_nsx/plugins/nsx_p/plugin.py b/vmware_nsx/plugins/nsx_p/plugin.py index 7b45789fdf..13b875a19d 100644 --- a/vmware_nsx/plugins/nsx_p/plugin.py +++ b/vmware_nsx/plugins/nsx_p/plugin.py @@ -1670,6 +1670,12 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base): self._format_mac_address(pair['mac_address'])) address_bindings.append(binding) + for binding1 in address_bindings[:]: + for binding2 in address_bindings[:]: + cidr1 = netaddr.IPNetwork(binding1.ip_address) + cidr2 = netaddr.IPNetwork(binding2.ip_address) + if cidr1 != cidr2 and cidr1 in cidr2: + address_bindings.remove(binding1) return address_bindings def _get_network_nsx_id(self, context, network_id): diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py index 1c6e48b2fb..dd432bf7c2 100644 --- a/vmware_nsx/plugins/nsx_v3/plugin.py +++ b/vmware_nsx/plugins/nsx_v3/plugin.py @@ -1200,6 +1200,13 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base, address_bindings.append(nsx_resources.PacketAddressClassifier( pair['ip_address'], pair['mac_address'], None)) + for binding1 in address_bindings[:]: + for binding2 in address_bindings[:]: + cidr1 = netaddr.IPNetwork(binding1.ip_address) + cidr2 = netaddr.IPNetwork(binding2.ip_address) + if cidr1 != cidr2 and cidr1 in cidr2: + address_bindings.remove(binding1) + return address_bindings def _get_qos_profile_id(self, context, policy_id): diff --git a/vmware_nsx/tests/unit/nsx_p/test_plugin.py b/vmware_nsx/tests/unit/nsx_p/test_plugin.py index 377d852ad9..dd52d6fc21 100644 --- a/vmware_nsx/tests/unit/nsx_p/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_p/test_plugin.py @@ -1263,6 +1263,77 @@ class NsxPTestPorts(common_v3.NsxV3TestPorts, mock_list_bindings.assert_not_called() mock_create_bindings.assert_not_called() + def test_update_port_ip_in_allowed_pair_cidr(self): + with self.subnet() as subnet: + post_data = { + 'port': { + 'network_id': subnet['subnet']['network_id'], + 'tenant_id': subnet['subnet']['tenant_id'], + 'device_owner': 'compute:meh', + 'fixed_ips': [{'subnet_id': + subnet['subnet']['id']}]}} + post_req = self.new_create_request('ports', post_data) + res = post_req.get_response(self.api) + self.assertEqual(201, res.status_int) + port = self.deserialize('json', res) + with mock.patch.object( + self.plugin.nsxpolicy.segment_port, + 'create_or_overwrite') as mock_port: + put_data = { + 'port': { + 'allowed_address_pairs': [ + {'ip_address': subnet['subnet']['cidr']} + ] + } + } + put_req = self.new_update_request( + 'ports', put_data, port['port']['id']) + put_res = put_req.get_response(self.api) + self.assertEqual(200, put_res.status_int) + self.assertEqual(1, len(mock_port.mock_calls)) + _n, _a, kwargs = mock_port.mock_calls[0] + actual_binding = kwargs['address_bindings'][0] + self.assertEqual( + subnet['subnet']['cidr'], + actual_binding.ip_address) + + def test_update_port_ip_not_in_allowed_pair_cidr(self): + with self.subnet() as subnet: + post_data = { + 'port': { + 'network_id': subnet['subnet']['network_id'], + 'tenant_id': subnet['subnet']['tenant_id'], + 'device_owner': 'compute:meh', + 'fixed_ips': [{'subnet_id': + subnet['subnet']['id']}]}} + post_req = self.new_create_request('ports', post_data) + res = post_req.get_response(self.api) + self.assertEqual(201, res.status_int) + port = self.deserialize('json', res) + fixed_ip = ( + port['port']['fixed_ips'][0]['ip_address']) + with mock.patch.object( + self.plugin.nsxpolicy.segment_port, + 'create_or_overwrite') as mock_port: + put_data = { + 'port': { + 'allowed_address_pairs': [ + {'ip_address': '1.2.3.0/24'} + ] + } + } + put_req = self.new_update_request( + 'ports', put_data, port['port']['id']) + put_res = put_req.get_response(self.api) + self.assertEqual(200, put_res.status_int) + self.assertEqual(1, len(mock_port.mock_calls)) + _n, _a, kwargs = mock_port.mock_calls[0] + actual_bindings = kwargs['address_bindings'] + addresses = set([b.ip_address for b in actual_bindings]) + self.assertEqual( + set([fixed_ip, '1.2.3.0/24']), + addresses) + class NsxPTestSubnets(common_v3.NsxV3TestSubnets, NsxPPluginTestCaseMixin): diff --git a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py index 0e8f4a2ffe..c83b1fd8c2 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py @@ -1503,6 +1503,68 @@ class TestPortsV2(common_v3.NsxV3SubnetMixin, self.plugin.update_port(self.ctx, port['id'], data) get_profile.assert_called_once_with(self.ctx, policy_id) + def test_update_port_ip_in_allowed_pair_cidr(self): + with self.network() as network: + with self.subnet(network) as subnet: + data = {'port': { + 'network_id': network['network']['id'], + 'tenant_id': self._tenant_id, + 'admin_state_up': True, + 'name': 'meh', + 'device_id': 'fake_device', + 'device_owner': 'fake_owner', + 'fixed_ips': [ + {'subnet_id': subnet['subnet']['id']}], + 'mac_address': '00:00:00:00:00:01'} + } + port = self.plugin.create_port(self.ctx, data) + with mock.patch.object(self.plugin.nsxlib.logical_port, + 'update') as mock_port: + self.plugin.update_port( + self.ctx, port['id'], + {'port': { + 'allowed_address_pairs': [ + {'ip_address': subnet['subnet']['cidr']} + ]}}) + self.assertEqual(1, len(mock_port.mock_calls)) + _n, _a, kwargs = mock_port.mock_calls[0] + actual_binding = kwargs['address_bindings'][0] + self.assertEqual( + subnet['subnet']['cidr'], + actual_binding.ip_address) + + def test_update_port_ip_not_in_allowed_pair_cidr(self): + with self.network() as network: + with self.subnet(network) as subnet: + data = {'port': { + 'network_id': network['network']['id'], + 'tenant_id': self._tenant_id, + 'admin_state_up': True, + 'name': 'meh', + 'device_id': 'fake_device', + 'device_owner': 'fake_owner', + 'fixed_ips': [ + {'subnet_id': subnet['subnet']['id']}], + 'mac_address': '00:00:00:00:00:01'} + } + port = self.plugin.create_port(self.ctx, data) + fixed_ip = port['fixed_ips'][0]['ip_address'] + with mock.patch.object(self.plugin.nsxlib.logical_port, + 'update') as mock_port: + self.plugin.update_port( + self.ctx, port['id'], + {'port': { + 'allowed_address_pairs': [ + {'ip_address': '1.2.3.0/24'} + ]}}) + self.assertEqual(1, len(mock_port.mock_calls)) + _n, _a, kwargs = mock_port.mock_calls[0] + actual_bindings = kwargs['address_bindings'] + addresses = set([b.ip_address for b in actual_bindings]) + self.assertEqual( + set([fixed_ip, '1.2.3.0/24']), + addresses) + def _get_ports_with_fields(self, tenid, fields, expected_count): pl = directory.get_plugin() ctx = context.Context(user_id=None, tenant_id=tenid,