Skip to content

Commit

Permalink
Ensure that fixed port IP address is in valid allocation range.
Browse files Browse the repository at this point in the history
Fixes bug 1077292

Change-Id: I587655bece83d0f6aa665e522efbc0ecd5ef1734
  • Loading branch information
Gary Kotton committed Nov 15, 2012
1 parent a112840 commit aca8b4a
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 14 deletions.
56 changes: 42 additions & 14 deletions quantum/db/db_base_plugin_v2.py
Expand Up @@ -486,6 +486,30 @@ def _check_subnet_ip(cidr, ip_address):
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.
Expand Down Expand Up @@ -1215,27 +1239,31 @@ def _delete_port(self, context, id):

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):
Expand Down
34 changes: 34 additions & 0 deletions quantum/tests/unit/test_db_plugin.py
Expand Up @@ -2193,6 +2193,40 @@ def test_create_subnet_with_none_gateway_fully_allocated(self):
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',
Expand Down

0 comments on commit aca8b4a

Please sign in to comment.