Browse Source

Merge "Update the processing of assigned addresses when assigning addresses" into stable/rocky

changes/64/742364/1
Zuul 3 weeks ago
committed by Gerrit Code Review
parent
commit
5a5a152984
2 changed files with 67 additions and 16 deletions
  1. +42
    -16
      neutron/ipam/drivers/neutrondb_ipam/driver.py
  2. +25
    -0
      neutron/tests/unit/ipam/drivers/neutrondb_ipam/test_driver.py

+ 42
- 16
neutron/ipam/drivers/neutrondb_ipam/driver.py View File

@@ -159,9 +159,16 @@ class NeutronDbSubnet(ipam_base.Subnet):

def _generate_ips(self, context, prefer_next=False, num_addresses=1):
"""Generate a set of IPs from the set of available addresses."""
ip_allocations = netaddr.IPSet()
for ipallocation in self.subnet_manager.list_allocations(context):
ip_allocations.add(ipallocation.ip_address)
allocated_ips = []
requested_num_addresses = num_addresses

allocations = self.subnet_manager.list_allocations(context)
# It is better not to use 'netaddr.IPSet.add',
# because _compact_single_network in 'IPSet.add'
# is quite time consuming.
ip_allocations = netaddr.IPSet(
[netaddr.IPAddress(allocation.ip_address)
for allocation in allocations])

for ip_pool in self.subnet_manager.list_pools(context):
ip_set = netaddr.IPSet()
@@ -170,34 +177,53 @@ class NeutronDbSubnet(ipam_base.Subnet):
if av_set.size == 0:
continue

if av_set.size < num_addresses:
# Not enough addresses in pool to perform validation
# TODO(njohnston): How to handle when there are enough IPs but
# not enough in a single pool to satisfy the request?
continue
if av_set.size < requested_num_addresses:
# All addresses of the address pool are allocated
# for the first time and the remaining addresses
# will be allocated in the next address pools.
allocated_num_addresses = av_set.size
else:
# All expected addresses can be assigned in this loop.
allocated_num_addresses = requested_num_addresses

if prefer_next:
allocated_ip_pool = list(itertools.islice(av_set,
num_addresses))
return [str(allocated_ip)
for allocated_ip in allocated_ip_pool]
allocated_num_addresses))
allocated_ips.extend([str(allocated_ip)
for allocated_ip in allocated_ip_pool])

requested_num_addresses -= allocated_num_addresses
if requested_num_addresses:
# More addresses need to be allocated in the next loop.
continue
return allocated_ips

window = min(av_set.size, MAX_WIN)

# NOTE(gryf): If there is more than one address, make the window
# bigger, so that are chances to fulfill demanded amount of IPs.
if num_addresses > 1:
window = min(av_set.size, num_addresses * MULTIPLIER,
if allocated_num_addresses > 1:
window = min(av_set.size,
allocated_num_addresses * MULTIPLIER,
MAX_WIN_MULTI)

if window < num_addresses:
if window < allocated_num_addresses:
continue
else:
# Maximize randomness by using the random module's built in
# sampling function
av_ips = list(itertools.islice(av_set, 0, window))
allocated_ip_pool = random.sample(av_ips, num_addresses)
return [str(allocated_ip) for allocated_ip in allocated_ip_pool]
allocated_ip_pool = random.sample(av_ips,
allocated_num_addresses)
allocated_ips.extend([str(allocated_ip)
for allocated_ip in allocated_ip_pool])

requested_num_addresses -= allocated_num_addresses
if requested_num_addresses:
# More addresses need to be allocated in the next loop.
continue

return allocated_ips

raise ipam_exc.IpAddressGenerationFailure(
subnet_id=self.subnet_manager.neutron_id)


+ 25
- 0
neutron/tests/unit/ipam/drivers/neutrondb_ipam/test_driver.py View File

@@ -381,6 +381,31 @@ class TestNeutronDbIpamSubnet(testlib_api.SqlTestCase,
ipam_subnet.bulk_allocate,
ipam_req.BulkAddressRequest(target_ip_count))

def test_bulk_allocate_multiple_address_pools(self):
target_ip_count = 10
# 11 addresses available
allocation_pools = [{'start': '192.168.0.5', 'end': '192.168.0.9'},
{'start': '192.168.0.15', 'end': '192.168.0.20'}]
ipam_subnet = self._create_and_allocate_ipam_subnet(
'192.168.0.0/24', allocation_pools=allocation_pools,
ip_version=constants.IP_VERSION_4)[0]
ip_addresses = ipam_subnet.bulk_allocate(
ipam_req.BulkAddressRequest(target_ip_count))
self.assertEqual(target_ip_count, len(ip_addresses))
self.assertRaises(ipam_exc.IpAddressGenerationFailure,
ipam_subnet.bulk_allocate,
ipam_req.BulkAddressRequest(2))

def test_prefernext_allocate_multiple_address_pools(self):
ipam_subnet = self._create_and_allocate_ipam_subnet(
'192.168.0.0/30', ip_version=constants.IP_VERSION_4)[0]

ipam_subnet.allocate(ipam_req.PreferNextAddressRequest())
# The second address generation request on a /30 for v4 net must fail
self.assertRaises(ipam_exc.IpAddressGenerationFailure,
ipam_subnet.allocate,
ipam_req.PreferNextAddressRequest)

def _test_deallocate_address(self, cidr, ip_version):
ipam_subnet = self._create_and_allocate_ipam_subnet(
cidr, ip_version=ip_version)[0]


Loading…
Cancel
Save