]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Ensure that fixed port IP address is in valid allocation range.
authorGary Kotton <gkotton@redhat.com>
Wed, 7 Nov 2012 00:44:35 +0000 (00:44 +0000)
committerGary Kotton <gkotton@redhat.com>
Sun, 11 Nov 2012 03:06:09 +0000 (03:06 +0000)
Fixes bug 1077292

Change-Id: I587655bece83d0f6aa665e522efbc0ecd5ef1734

quantum/db/db_base_plugin_v2.py
quantum/tests/unit/test_db_plugin.py

index 7f725f3b0a9782f3aad544efa83e934647ae4c12..cce4e07aac1d2c22b98030ae7bd2b6b5e2107ddb 100644 (file)
@@ -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):
index b6fcc5c353314f9835e6731dbb2b1f0ed10628df..281fee836b9f6ee53ea378dc1eb701b6664d6a1b 100644 (file)
@@ -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',