Improve bottom allocation pool calculation

1. What is the problem
Current bottom allocation pool calculation only merges the top gateway
ip with one ip range, so if the top gateway ip can connect two ip
ranges, the two ranges are not merged. For example,

pools: [x.x.x.2, x.x.x.5], [x.x.x.7, x.x.x.10]
top gateway ip: x.x.x.6

after merge, the pools become: [x.x.x.2, x.x.x.6], [x.x.x.7, x.x.x.10]
while should be: [x.x.x.2, x.x.x.10]

2. What is the solution to the problem
Rewrite the calculation method to merge two ranges if they are connected
by the top gateway ip.

3. What the features need to be implemented to the Tricircle
No new features.

Change-Id: I4d56e9c992a3ad1106918551a3b4c23d09264928
Closes-Bug: #1657621
This commit is contained in:
zhiyuan_cai 2017-02-09 11:30:15 +08:00
parent ed02562d76
commit f0b6233181
4 changed files with 79 additions and 31 deletions

View File

@ -227,47 +227,82 @@ class NetworkHelper(object):
return body
@staticmethod
def get_bottom_subnet_pools(t_subnet, gateway_ip):
"""Get bottom subnet allocation pools
def _find_ip_range(pool, gateway_ip):
ret_pools = []
ip_range = netaddr.IPRange(pool['start'], pool['end'])
ip_num = len(ip_range)
for i, ip in enumerate(ip_range):
if gateway_ip == ip:
if i > 0:
ret_pools.append({'start': ip_range[0].format(),
'end': ip_range[i - 1].format()})
if i < ip_num - 1:
ret_pools.append(
{'start': ip_range[i + 1].format(),
'end': ip_range[ip_num - 1].format()})
return ret_pools
:param t_subnet: top subnet
:param gateway_ip: bottom subnet gateway ip
:return: bottom subnet allocation pools
"""
pools = t_subnet['allocation_pools']
t_gateway_ip = t_subnet['gateway_ip']
@staticmethod
def _split_pools_by_bottom_gateway_ip(pools, gateway_ip):
new_pools = []
g_ip = netaddr.IPAddress(gateway_ip)
ip_found = False
ip_merged = False
for pool in pools:
if ip_found:
new_pools.append({'start': pool['start'],
'end': pool['end']})
continue
ip_range = netaddr.IPRange(pool['start'], pool['end'])
if not ip_merged:
ip_range, ip_merged = NetworkHelper._merge_ip_range(
ip_range, t_gateway_ip)
ip_num = len(ip_range)
for i, ip in enumerate(ip_range):
if g_ip == ip:
ip_found = True
if i > 0:
new_pools.append({'start': ip_range[0].format(),
'end': ip_range[i - 1].format()})
if i < ip_num - 1:
new_pools.append(
{'start': ip_range[i + 1].format(),
'end': ip_range[ip_num - 1].format()})
break
ret_pools = NetworkHelper._find_ip_range(pool, g_ip)
if ret_pools:
ip_found = True
new_pools.extend(ret_pools)
if not ip_found:
new_pools.extend(pools)
if not ip_merged:
new_pools.insert(0, {'start': t_gateway_ip, 'end': t_gateway_ip})
return new_pools
@staticmethod
def _merge_pools_by_top_gateway_ip(pools, gateway_ip):
new_ranges = []
merged_set = netaddr.IPSet()
for pool in pools:
ip_range = netaddr.IPRange(pool['start'], pool['end'])
ip_range, ip_merged = NetworkHelper._merge_ip_range(
ip_range, gateway_ip)
if not ip_merged:
new_ranges.append(ip_range)
else:
# if range1 + gateway_ip is contiguous, range2 + gateway_ip is
# contiguous, then range1 + range2 + gateway_ip is contiguous,
# so we add them in the same ip set
merged_set.add(ip_range)
new_pools = []
for new_range in new_ranges:
new_pools.append({'start': new_range[0].format(),
'end': new_range[len(new_range) - 1].format()})
if merged_set:
merged_range = merged_set.iprange()
new_pools.append(
{'start': merged_range[0].format(),
'end': merged_range[len(merged_range) - 1].format()})
else:
new_pools.append({'start': gateway_ip, 'end': gateway_ip})
return new_pools
@staticmethod
def get_bottom_subnet_pools(t_subnet, b_gateway_ip):
"""Get bottom subnet allocation pools
:param t_subnet: top subnet
:param b_gateway_ip: bottom subnet gateway ip
:return: bottom subnet allocation pools
"""
pools = t_subnet['allocation_pools']
t_gateway_ip = t_subnet['gateway_ip']
new_pools = NetworkHelper._split_pools_by_bottom_gateway_ip(
pools, b_gateway_ip)
return NetworkHelper._merge_pools_by_top_gateway_ip(new_pools,
t_gateway_ip)
@staticmethod
def get_create_subnet_body(project_id, t_subnet, b_net_id, gateway_ip):
"""Get request body to create bottom subnet

View File

@ -1909,8 +1909,9 @@ class PluginTest(unittest.TestCase,
bottom_allocation_pools = [{'start': '10.0.1.2', 'end': '10.0.1.2'},
{'start': '10.0.1.10', 'end': '10.0.1.24'},
{'start': '10.0.1.26', 'end': '10.0.1.254'}]
self.assertEqual(bottom_subnet['allocation_pools'],
bottom_allocation_pools)
six.assertCountEqual(self,
bottom_subnet['allocation_pools'],
bottom_allocation_pools)
six.assertCountEqual(self,
bottom_subnet['host_routes'],
body_copy['subnet']['host_routes'])

View File

@ -76,3 +76,15 @@ class HelperTest(unittest.TestCase):
{'start': '10.0.1.20', 'end': '10.0.1.254'}],
body['subnet']['allocation_pools'])
self.assertEqual('10.0.1.5', body['subnet']['gateway_ip'])
t_subnet['gateway_ip'] = '10.0.1.11'
t_subnet['allocation_pools'] = [
{'start': '10.0.1.2', 'end': '10.0.1.10'},
{'start': '10.0.1.12', 'end': '10.0.1.254'}]
body = self.helper.get_create_subnet_body(project_id, t_subnet,
b_net_id, '10.0.1.5')
six.assertCountEqual(self,
[{'start': '10.0.1.2', 'end': '10.0.1.4'},
{'start': '10.0.1.6', 'end': '10.0.1.254'}],
body['subnet']['allocation_pools'])
self.assertEqual('10.0.1.5', body['subnet']['gateway_ip'])

View File

@ -302,7 +302,7 @@ class PluginTest(unittest.TestCase):
b_port.pop('name')
self.assertDictEqual(net, b_net)
self.assertDictEqual(subnet, b_subnet)
self.assertListEqual(pool_range, b_pool_range)
self.assertSetEqual(set(pool_range), set(b_pool_range))
self.assertEqual('vlan', b_net_type)
self.assertDictEqual(port, b_port)