diff --git a/vmware_nsx/plugins/common_v3/plugin.py b/vmware_nsx/plugins/common_v3/plugin.py index cd320d82e7..82b496b0c5 100644 --- a/vmware_nsx/plugins/common_v3/plugin.py +++ b/vmware_nsx/plugins/common_v3/plugin.py @@ -256,6 +256,30 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, LOG.error("cidr is not supported in allowed address pairs") raise nsx_exc.InvalidIPAddress(ip_address=ip) + def _validate_number_of_address_pairs(self, port): + address_pairs = port.get(addr_apidef.ADDRESS_PAIRS) + num_allowed_on_backend = nsxlib_consts.NUM_ALLOWED_IP_ADDRESSES + # Counting existing ports to take into account. If no fixed ips + # are defined - we set it to 3 in order to reserve 2 fixed and another + # for DHCP. + + existing_fixed_ips = len(port.get('fixed_ips', [])) + if existing_fixed_ips == 0: + existing_fixed_ips = 3 + else: + existing_fixed_ips += 1 + if address_pairs: + if (len(address_pairs) + existing_fixed_ips >= + num_allowed_on_backend): + err_msg = (_( + "Number of Address pairs is limited at the backend to %(" + "backend)s. Existing and requested %(" + "existing_and_requested)s") % + {'backend': nsxlib_consts.NUM_ALLOWED_IP_ADDRESSES, + 'existing_and_requested': existing_fixed_ips + + len(address_pairs)}) + raise n_exc.InvalidInput(error_message=err_msg) + def _create_port_address_pairs(self, context, port_data): (port_security, has_ip) = self._determine_port_security_and_has_ip( context, port_data) @@ -266,6 +290,7 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, raise addr_exc.AddressPairAndPortSecurityRequired() else: self._validate_address_pairs(address_pairs) + self._validate_number_of_address_pairs(port_data) self._process_create_allowed_address_pairs(context, port_data, address_pairs) else: @@ -654,6 +679,7 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, self._validate_max_ips_per_port(context, port_data.get('fixed_ips', []), device_owner) + self._validate_number_of_address_pairs(port_data) self._assert_on_vpn_port_change(original_port) self._assert_on_lb_port_fixed_ip_change(port_data, orig_dev_owner) self._validate_extra_dhcp_options(port_data.get(ext_edo.EXTRADHCPOPTS)) diff --git a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py index 8c9aa966fe..20c671186c 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py @@ -1068,6 +1068,29 @@ class TestPortsV2(test_plugin.TestPortsV2, NsxV3PluginTestCaseMixin, n_exc.InvalidInput, self.plugin.update_port, self.ctx, port['id'], data) + def test_fail_create_allowed_address_pairs_over_limit(self): + with self.network() as network,\ + self.subnet(network=network, enable_dhcp=True) as s1: + data = {'port': { + 'network_id': network['network']['id'], + 'tenant_id': self._tenant_id, + 'name': 'pair_port', + 'admin_state_up': True, + 'device_id': 'fake_device', + 'device_owner': 'fake_owner', + 'fixed_ips': [{'subnet_id': s1['subnet']['id']}] + } + } + count = 1 + address_pairs = [] + while count < 129: + address_pairs.append({'ip_address': '10.0.0.%s' % + count}) + count += 1 + data['port']['allowed_address_pairs'] = address_pairs + self.assertRaises(n_exc.InvalidInput, + self.plugin.create_port, self.ctx, data) + def test_fail_update_lb_port_with_fixed_ip(self): with self.network() as network: data = {'port': {