From c8375cfad251176edfd44956a1d44e56126908b3 Mon Sep 17 00:00:00 2001 From: Gary Kotton Date: Wed, 7 Nov 2012 00:44:35 +0000 Subject: [PATCH] Ensure that fixed port IP address is in valid allocation range. Fixes bug 1077292 Change-Id: I587655bece83d0f6aa665e522efbc0ecd5ef1734 --- quantum/db/db_base_plugin_v2.py | 56 +++++++++++++++++++++------- quantum/tests/unit/test_db_plugin.py | 34 +++++++++++++++++ 2 files changed, 76 insertions(+), 14 deletions(-) diff --git a/quantum/db/db_base_plugin_v2.py b/quantum/db/db_base_plugin_v2.py index 7f725f3b0..cce4e07aa 100644 --- a/quantum/db/db_base_plugin_v2.py +++ b/quantum/db/db_base_plugin_v2.py @@ -485,6 +485,30 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2): return True return False + @staticmethod + def _check_ip_in_allocation_pool(context, subnet_id, gateway_ip, + ip_address): + """Validate IP in allocation pool. + + Validates that the IP address is either the default gateway or + in the allocation pools of the subnet. + """ + # Check if the IP is the gateway + if ip_address == gateway_ip: + return True + + # Check if the requested IP is in a defined allocation pool + pool_qry = context.session.query(models_v2.IPAllocationPool) + allocation_pools = pool_qry.filter_by(subnet_id=subnet_id).all() + ip = netaddr.IPAddress(ip_address) + for allocation_pool in allocation_pools: + allocation_pool_range = netaddr.IPRange( + allocation_pool['first_ip'], + allocation_pool['last_ip']) + if ip in allocation_pool_range: + return True + return False + def _test_fixed_ips_for_port(self, context, network_id, fixed_ips): """Test fixed IPs for port. @@ -1219,27 +1243,31 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2): allocated_qry = context.session.query(models_v2.IPAllocation) # recycle all of the IP's - # NOTE(garyk) this may be have to be addressed differently when - # working with a DHCP server. allocated = allocated_qry.filter_by(port_id=id).all() if allocated: for a in allocated: subnet = self._get_subnet(context, a['subnet_id']) - if a['ip_address'] == subnet['gateway_ip']: - # Gateway address will not be recycled, but we do - # need to delete the allocation from the DB + # Check if IP was allocated from allocation pool + if QuantumDbPluginV2._check_ip_in_allocation_pool( + context, a['subnet_id'], subnet['gateway_ip'], + a['ip_address']): + QuantumDbPluginV2._hold_ip(context, + a['network_id'], + a['subnet_id'], + id, + a['ip_address']) + else: + # IPs out of allocation pool will not be recycled, but + # we do need to delete the allocation from the DB QuantumDbPluginV2._delete_ip_allocation( context, a['network_id'], a['subnet_id'], a['ip_address']) - LOG.debug("Gateway address (%s/%s) is not recycled", - a['ip_address'], a['subnet_id']) - continue - - QuantumDbPluginV2._hold_ip(context, - a['network_id'], - a['subnet_id'], - id, - a['ip_address']) + msg_dict = dict(address=a['ip_address'], + subnet_id=a['subnet_id']) + msg = _("%(address)s (%(subnet_id)s) is not " + "recycled") % msg_dict + LOG.debug(msg) + context.session.delete(port) def get_port(self, context, id, fields=None): diff --git a/quantum/tests/unit/test_db_plugin.py b/quantum/tests/unit/test_db_plugin.py index b6fcc5c35..281fee836 100644 --- a/quantum/tests/unit/test_db_plugin.py +++ b/quantum/tests/unit/test_db_plugin.py @@ -2196,6 +2196,40 @@ class TestSubnetsV2(QuantumDbPluginV2TestCase): cidr=cidr, allocation_pools=allocation_pools) + def test_subnet_with_allocation_range(self): + fmt = 'json' + with self.network() as network: + net_id = network['network']['id'] + data = {'subnet': {'network_id': net_id, + 'cidr': '10.0.0.0/24', + 'ip_version': 4, + 'gateway_ip': '10.0.0.1', + 'tenant_id': network['network']['tenant_id'], + 'allocation_pools': [{'start': '10.0.0.100', + 'end': '10.0.0.120'}]}} + subnet_req = self.new_create_request('subnets', data) + subnet = self.deserialize('json', + subnet_req.get_response(self.api)) + # Check fixed IP not in allocation range + kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id'], + 'ip_address': '10.0.0.10'}]} + res = self._create_port(fmt, net_id=net_id, **kwargs) + self.assertEquals(res.status_int, 201) + port = self.deserialize('json', res) + port_id = port['port']['id'] + # delete the port + self._delete('ports', port['port']['id']) + + # Check when fixed IP is gateway + kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id'], + 'ip_address': '10.0.0.1'}]} + res = self._create_port(fmt, net_id=net_id, **kwargs) + self.assertEquals(res.status_int, 201) + port = self.deserialize('json', res) + port_id = port['port']['id'] + # delete the port + self._delete('ports', port['port']['id']) + def test_create_subnet_with_none_gateway_allocation_pool(self): cidr = '10.0.0.0/24' allocation_pools = [{'start': '10.0.0.2', -- 2.45.2