From: David Edery Date: Sun, 21 Jun 2015 12:59:49 +0000 (+0300) Subject: Fix subnet creation failure on IPv6 valid gateway X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=ee51ef72d37a02005a7733b7f2faf7236db850a1;p=openstack-build%2Fneutron-build.git Fix subnet creation failure on IPv6 valid gateway Currently a valid IPv6 address gateway of the "*::ffff:ffff:ffff:ffff" pattern is failing due to netaddr.broadcast returning value for both IPv6 and IPv4 addresses. IPv6 has no broadcast address so the fix checks if the gateway is the subnet broadcast address only in the case of IPv4 subnet Change-Id: I849f95b30343d0b1c90cf91203df220bf731d8d5 Closes-Bug: 1466322 --- diff --git a/neutron/ipam/subnet_alloc.py b/neutron/ipam/subnet_alloc.py index dc38f4375..d1a6f681f 100644 --- a/neutron/ipam/subnet_alloc.py +++ b/neutron/ipam/subnet_alloc.py @@ -126,13 +126,19 @@ class SubnetAllocator(driver.Pool): self._check_subnetpool_tenant_quota(request.tenant_id, request.prefixlen) cidr = request.subnet_cidr + gateway = request.gateway_ip + if gateway and not ipam_utils.check_subnet_ip(cidr, gateway): + msg = _("Cannot allocate requested subnet due to bad gateway " + "address") + raise n_exc.SubnetAllocationError(reason=msg) + available = self._get_available_prefix_list() matched = netaddr.all_matching_cidrs(cidr, available) if len(matched) is 1 and matched[0].prefixlen <= cidr.prefixlen: return IpamSubnet(request.tenant_id, request.subnet_id, cidr, - gateway_ip=request.gateway_ip, + gateway_ip=gateway, allocation_pools=request.allocation_pools) msg = _("Cannot allocate requested subnet from the available " "set of prefixes") diff --git a/neutron/ipam/utils.py b/neutron/ipam/utils.py index 74927769a..3f0bda173 100644 --- a/neutron/ipam/utils.py +++ b/neutron/ipam/utils.py @@ -21,8 +21,9 @@ def check_subnet_ip(cidr, ip_address): ip = netaddr.IPAddress(ip_address) net = netaddr.IPNetwork(cidr) # Check that the IP is valid on subnet. This cannot be the - # network or the broadcast address - return (ip != net.network and ip != net.broadcast + # network or the broadcast address (which exists only in IPv4) + return (ip != net.network + and (net.version == 6 or ip != net.broadcast) and net.netmask & ip == net.network) diff --git a/neutron/tests/unit/ipam/test_subnet_alloc.py b/neutron/tests/unit/ipam/test_subnet_alloc.py index 25021af2f..8923ef8de 100644 --- a/neutron/tests/unit/ipam/test_subnet_alloc.py +++ b/neutron/tests/unit/ipam/test_subnet_alloc.py @@ -146,6 +146,37 @@ class TestSubnetAllocation(testlib_api.SqlTestCase): self.assertEqual(detail.gateway_ip, netaddr.IPAddress('10.1.2.254')) + def test_allocate_specific_ipv6_subnet_specific_gateway(self): + # Same scenario as described in bug #1466322 + sp = self._create_subnet_pool(self.plugin, self.ctx, 'test-sp', + ['2210::/64'], + 64, 6) + sp = self.plugin._get_subnetpool(self.ctx, sp['id']) + with self.ctx.session.begin(subtransactions=True): + sa = subnet_alloc.SubnetAllocator(sp, self.ctx) + req = ipam.SpecificSubnetRequest(self._tenant_id, + uuidutils.generate_uuid(), + '2210::/64', + '2210::ffff:ffff:ffff:ffff') + res = sa.allocate_subnet(req) + detail = res.get_details() + self.assertEqual(detail.gateway_ip, + netaddr.IPAddress('2210::ffff:ffff:ffff:ffff')) + + def test_allocate_specific_ipv4_subnet_specific_broadcast_gateway(self): + # Valid failure in subnet creation due to gateway==broadcast ip + sp = self._create_subnet_pool(self.plugin, self.ctx, 'test-sp', + ['10.1.0.0/24'], + 24, 4) + sa = subnet_alloc.SubnetAllocator(sp, self.ctx) + req = ipam.SpecificSubnetRequest(self._tenant_id, + uuidutils.generate_uuid(), + '10.1.0.0/24', + gateway_ip='10.1.0.255') + self.assertRaises(n_exc.SubnetAllocationError, + sa.allocate_subnet, + req) + def test__allocation_value_for_tenant_no_allocations(self): sp = self._create_subnet_pool(self.plugin, self.ctx, 'test-sp', ['10.1.0.0/16', '192.168.1.0/24'],