Files
quark/quark/allocation_pool.py
insequent 8c61076a2d Removing all references to validate_gateway_excluded
Why? RM9134. We've decided to follow upstream's example
and allow gateway_ip for subnets to exist inside of the
allocation pool.
2014-09-18 04:51:17 +00:00

151 lines
6.3 KiB
Python

# Copyright 2014 Openstack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import netaddr
from neutron.common import exceptions
from neutron.openstack.common import log as logging
LOG = logging.getLogger(__name__)
class AllocationPools(object):
def __init__(self, subnet_cidr, pools=None, policies=None):
self._exclude_cidrs = None
self._subnet_cidr = netaddr.IPNetwork(subnet_cidr)
self._alloc_pools = pools
version = self._subnet_cidr.version
self._subnet_first_ip = netaddr.IPAddress(
self._subnet_cidr.first + 1, version=version)
self._subnet_last_ip = netaddr.IPAddress(
self._subnet_cidr.last - 1, version=version)
# If passed an empty list, the entire subnet is unallocatable.
# If None is passed, the entire subnet is allocatable
if self._alloc_pools is None:
self._alloc_pools = [
{"start": self._subnet_first_ip,
"end": self._subnet_last_ip}]
self._policies = policies or []
# Note(asadoughi): Copied from neutron/db/db_base_plugin_v2.py
def _validate_allocation_pools(self):
"""Validate IP allocation pools.
Verify start and end address for each allocation pool are valid,
ie: constituted by valid and appropriately ordered IP addresses.
Also, verify pools do not overlap among themselves.
Finally, verify that each range fall within the subnet's CIDR.
"""
ip_pools = self._alloc_pools
subnet_cidr = self._subnet_cidr
LOG.debug(_("Performing IP validity checks on allocation pools"))
ip_sets = []
for ip_pool in ip_pools:
try:
start_ip = netaddr.IPAddress(ip_pool['start'])
end_ip = netaddr.IPAddress(ip_pool['end'])
except netaddr.AddrFormatError:
LOG.info(_("Found invalid IP address in pool: "
"%(start)s - %(end)s:"),
{'start': ip_pool['start'],
'end': ip_pool['end']})
raise exceptions.InvalidAllocationPool(pool=ip_pool)
if (start_ip.version != self._subnet_cidr.version or
end_ip.version != self._subnet_cidr.version):
LOG.info(_("Specified IP addresses do not match "
"the subnet IP version"))
raise exceptions.InvalidAllocationPool(pool=ip_pool)
if end_ip < start_ip:
LOG.info(_("Start IP (%(start)s) is greater than end IP "
"(%(end)s)"),
{'start': ip_pool['start'], 'end': ip_pool['end']})
raise exceptions.InvalidAllocationPool(pool=ip_pool)
if (start_ip < self._subnet_first_ip or
end_ip > self._subnet_last_ip):
LOG.info(_("Found pool larger than subnet "
"CIDR:%(start)s - %(end)s"),
{'start': ip_pool['start'],
'end': ip_pool['end']})
raise exceptions.OutOfBoundsAllocationPool(
pool=ip_pool,
subnet_cidr=subnet_cidr)
# Valid allocation pool
# Create an IPSet for it for easily verifying overlaps
ip_sets.append(netaddr.IPSet(netaddr.IPRange(
ip_pool['start'],
ip_pool['end']).cidrs()))
LOG.debug(_("Checking for overlaps among allocation pools "
"and gateway ip"))
ip_ranges = ip_pools[:]
# Use integer cursors as an efficient way for implementing
# comparison and avoiding comparing the same pair twice
for l_cursor in xrange(len(ip_sets)):
for r_cursor in xrange(l_cursor + 1, len(ip_sets)):
if ip_sets[l_cursor] & ip_sets[r_cursor]:
l_range = ip_ranges[l_cursor]
r_range = ip_ranges[r_cursor]
LOG.info(_("Found overlapping ranges: %(l_range)s and "
"%(r_range)s"),
{'l_range': l_range, 'r_range': r_range})
raise exceptions.OverlappingAllocationPools(
pool_1=l_range,
pool_2=r_range,
subnet_cidr=subnet_cidr)
def _build_excludes(self):
self._validate_allocation_pools()
subnet_net = netaddr.IPNetwork(self._subnet_cidr)
version = subnet_net.version
cidrset = netaddr.IPSet(
netaddr.IPRange(
netaddr.IPAddress(subnet_net.first, version=version),
netaddr.IPAddress(subnet_net.last, version=version)).cidrs())
if isinstance(self._alloc_pools, list):
for p in self._alloc_pools:
start = netaddr.IPAddress(p["start"])
end = netaddr.IPAddress(p["end"])
cidrset -= netaddr.IPSet(netaddr.IPRange(
netaddr.IPAddress(start),
netaddr.IPAddress(end)).cidrs())
elif self._alloc_pools is None:
# Empty list is completely unallocatable, None is fully
# allocatable
cidrset = netaddr.IPSet()
for p in self._policies:
cidrset.add(netaddr.IPNetwork(p))
self._exclude_cidrs = cidrset
def _refresh_excludes(self):
if not self._exclude_cidrs:
self._build_excludes()
def add_pool(self, pool):
self._exclude_cidrs = None
self._alloc_pools.append(pool)
def add_policy(self, policy):
self._exclude_cidrs = None
self._policies.append(policy)
def get_policy_cidrs(self):
self._refresh_excludes()
return [str(c) for c in self._exclude_cidrs.iter_cidrs()]