]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Add IPv6 Prefix Delegation compatibility to ipam_pluggable_backend
authorJohn Davidge <jodavidg@cisco.com>
Thu, 13 Aug 2015 17:51:57 +0000 (18:51 +0100)
committerJohn Davidge <jodavidg@cisco.com>
Tue, 25 Aug 2015 16:01:22 +0000 (17:01 +0100)
This patch makes the necessary changes for IPv6 PD to function when
pluggable ipam is enabled with the reference driver.

Includes a unit test for this functionality.

Change-Id: I4227cc08fdd62922632629c424dbeb542a48a67f
Partially-Implements: blueprint ipv6-prefix-delegation

neutron/db/ipam_pluggable_backend.py
neutron/ipam/drivers/neutrondb_ipam/driver.py
neutron/tests/unit/db/test_ipam_pluggable_backend.py

index 17e1371c375d81743e1d1f6751895dc2c3d4f090..7abd621a95cf24794f97571c9ecfffd7c3c90fc1 100644 (file)
@@ -407,7 +407,7 @@ class IpamPluggableBackend(ipam_backend_mixin.IpamBackendMixin):
     def allocate_subnet(self, context, network, subnet, subnetpool_id):
         subnetpool = None
 
-        if subnetpool_id:
+        if subnetpool_id and not subnetpool_id == constants.IPV6_PD_POOL_ID:
             subnetpool = self._get_subnetpool(context, subnetpool_id)
             self._validate_ip_version_with_subnetpool(subnet, subnetpool)
 
index 1ddab84340facafe1f8673036aa472acdbb852e3..da2da230fd83a6ccf0dd0eb88b6f556c4ede922c 100644 (file)
@@ -44,12 +44,16 @@ class NeutronDbSubnet(ipam_base.Subnet):
     """
 
     @classmethod
-    def create_allocation_pools(cls, subnet_manager, session, pools):
+    def create_allocation_pools(cls, subnet_manager, session, pools, cidr):
         for pool in pools:
+            # IPv6 addresses that start '::1', '::2', etc cause IP version
+            # ambiguity when converted to integers by pool.first and pool.last.
+            # Infer the IP version from the subnet cidr.
+            ip_version = cidr.version
             subnet_manager.create_pool(
                 session,
-                netaddr.IPAddress(pool.first).format(),
-                netaddr.IPAddress(pool.last).format())
+                netaddr.IPAddress(pool.first, ip_version).format(),
+                netaddr.IPAddress(pool.last, ip_version).format())
 
     @classmethod
     def create_from_subnet_request(cls, subnet_request, ctx):
@@ -68,7 +72,8 @@ class NeutronDbSubnet(ipam_base.Subnet):
         else:
             pools = subnet_request.allocation_pools
         # Create IPAM allocation pools and availability ranges
-        cls.create_allocation_pools(subnet_manager, session, pools)
+        cls.create_allocation_pools(subnet_manager, session, pools,
+                                    subnet_request.subnet_cidr)
 
         return cls(ipam_subnet_id,
                    ctx,
@@ -347,13 +352,13 @@ class NeutronDbSubnet(ipam_base.Subnet):
                 subnet_id=self.subnet_manager.neutron_id,
                 ip_address=address)
 
-    def update_allocation_pools(self, pools):
+    def update_allocation_pools(self, pools, cidr):
         # Pools have already been validated in the subnet request object which
         # was sent to the subnet pool driver. Further validation should not be
         # required.
         session = db_api.get_session()
         self.subnet_manager.delete_allocation_pools(session)
-        self.create_allocation_pools(self.subnet_manager, session, pools)
+        self.create_allocation_pools(self.subnet_manager, session, pools, cidr)
         self._pools = pools
 
     def get_details(self):
@@ -414,7 +419,8 @@ class NeutronDbPool(subnet_alloc.SubnetAllocator):
                       subnet_request.subnet_id)
             return
         subnet = NeutronDbSubnet.load(subnet_request.subnet_id, self._context)
-        subnet.update_allocation_pools(subnet_request.allocation_pools)
+        cidr = netaddr.IPNetwork(subnet._cidr)
+        subnet.update_allocation_pools(subnet_request.allocation_pools, cidr)
         return subnet
 
     def remove_subnet(self, subnet_id):
index 80d826c7977a8d360d66216c3c71b5711002283d..dd5d111123f703a8b37ac80e8441a4b092e9d32c 100644 (file)
@@ -20,6 +20,7 @@ import webob.exc
 from oslo_config import cfg
 from oslo_utils import uuidutils
 
+from neutron.common import constants
 from neutron.common import exceptions as n_exc
 from neutron.common import ipv6_utils
 from neutron.db import ipam_backend_mixin
@@ -283,6 +284,23 @@ class TestDbBasePluginIpam(test_db_base.NeutronDbPluginV2TestCase):
             self.assertIsInstance(request, ipam_req.SpecificSubnetRequest)
             self.assertEqual(netaddr.IPNetwork(cidr), request.subnet_cidr)
 
+    @mock.patch('neutron.ipam.driver.Pool')
+    def test_create_ipv6_pd_subnet_over_ipam(self, pool_mock):
+        mocks = self._prepare_mocks_with_pool_mock(pool_mock)
+        cfg.CONF.set_override('default_ipv6_subnet_pool',
+                              constants.IPV6_PD_POOL_ID)
+        cidr = constants.PROVISIONAL_IPV6_PD_PREFIX
+        allocation_pools = [netaddr.IPRange('::2', '::ffff:ffff:ffff:ffff')]
+        with self.subnet(cidr=None, ip_version=6,
+                         ipv6_ra_mode=constants.IPV6_SLAAC,
+                         ipv6_address_mode=constants.IPV6_SLAAC):
+            pool_mock.get_instance.assert_called_once_with(None, mock.ANY)
+            self.assertTrue(mocks['driver'].allocate_subnet.called)
+            request = mocks['driver'].allocate_subnet.call_args[0][0]
+            self.assertIsInstance(request, ipam_req.SpecificSubnetRequest)
+            self.assertEqual(netaddr.IPNetwork(cidr), request.subnet_cidr)
+            self.assertEqual(allocation_pools, request.allocation_pools)
+
     @mock.patch('neutron.ipam.driver.Pool')
     def test_create_subnet_over_ipam_with_rollback(self, pool_mock):
         mocks = self._prepare_mocks_with_pool_mock(pool_mock)