Boot a VM in a subnet without gateway

1. What is the problem
We can create a subnet without gateway in the central Neutron, but when
we boot a VM in that subnet, the request fails since local Neutron is
trying to calculate the IP allocation pool based on the central subnet
gateway IP, which is None.

2. What is the solution for the problem
If a central subnet doesn't have gateway, do not re-calculate local IP
allocation pool when creating local subnet.

3. What features need to be implemented to the Tricircle to
realize the solution
Support booting a VM in a subnet that has not gateway

Change-Id: I04f7f9f9926f22bca3490ee46e2163b9c17bb8fe
Closes-Bug: #1693446
This commit is contained in:
zhiyuan_cai 2017-05-25 17:35:32 +08:00
parent 3f2480027d
commit ed79a4d738
5 changed files with 47 additions and 14 deletions

@ -364,6 +364,9 @@ class NetworkHelper(object):
"""
pools = t_subnet['allocation_pools']
t_gateway_ip = t_subnet['gateway_ip']
if not t_gateway_ip:
# gateway is None, so we don't need to split allocation pools
return pools
new_pools = NetworkHelper._split_pools_by_bottom_gateway_ip(
pools, b_gateway_ip)
if t_gateway_ip == b_gateway_ip:

@ -342,10 +342,14 @@ class TricirclePlugin(plugin.Ml2Plugin):
return b_subnet
def _create_bottom_subnet(self, t_ctx, q_ctx, t_subnet):
gateway_port = self._ensure_gateway_port(t_ctx, t_subnet)
if t_subnet['gateway_ip']:
gateway_port = self._ensure_gateway_port(t_ctx, t_subnet)
b_gateway_ip = gateway_port['fixed_ips'][0]['ip_address']
else:
b_gateway_ip = None
subnet_body = helper.NetworkHelper.get_create_subnet_body(
gateway_port['tenant_id'], t_subnet, t_subnet['network_id'],
gateway_port['fixed_ips'][0]['ip_address'])['subnet']
t_subnet['tenant_id'], t_subnet, t_subnet['network_id'],
b_gateway_ip)['subnet']
t_subnet['gateway_ip'] = subnet_body['gateway_ip']
t_subnet['allocation_pools'] = subnet_body['allocation_pools']

@ -73,6 +73,16 @@ $openstackpod2 server create --flavor 1 --image $image2_id --nic net-id=$net2_id
echo attach subnet2 to router
$openstacktop router add subnet router subnet2
echo create network4
net4_id=$($openstacktop network create net4 -c id -f value)
echo create subnet4 that has no gateway
$openstacktop subnet create --subnet-range 10.0.4.0/24 --network net4 \
--gateway None subnet4
echo create server3
$openstackpod1 server create --flavor 1 --image $image1_id --nic net-id=$net4_id vm3
sleep 20
TOP_DIR=$DEVSTACK_DIR

@ -30,8 +30,10 @@ class ContainedString(object):
CONDITIONS = {
'1': {'server': [{'Name': 'vm1', 'Status': 'ACTIVE'}],
'subnet': [{'Subnet': '100.0.0.0/24'}, {'Subnet': '10.0.1.0/24'}],
'1': {'server': [{'Name': 'vm1', 'Status': 'ACTIVE'},
{'Name': 'vm3', 'Status': 'ACTIVE'}],
'subnet': [{'Subnet': '100.0.0.0/24'}, {'Subnet': '10.0.1.0/24'},
{'Subnet': '10.0.4.0/24'}],
'router_port': [{'Fixed IP Addresses': ContainedString('10.0.1')},
{'Fixed IP Addresses': ContainedString('100.0.0')}],
'router': [

@ -337,15 +337,23 @@ class PluginTest(unittest.TestCase):
def ip_to_digit(ip):
return int(ip[ip.rindex('.') + 1:])
pool_range = list(range(ip_to_digit(t_gateway_ip),
ip_to_digit(pool['end']) + 1))
# we include the top gateway ip in the bottom ip allocation pool
b_pool_range1 = list(range(ip_to_digit(b_pools[0]['start']),
ip_to_digit(b_pools[0]['end']) + 1))
b_pool_range2 = list(range(ip_to_digit(b_pools[1]['start']),
ip_to_digit(b_pools[1]['end']) + 1))
b_pool_range = b_pool_range1 + [
ip_to_digit(b_gateway_ip)] + b_pool_range2
if t_gateway_ip:
pool_range = list(range(ip_to_digit(t_gateway_ip),
ip_to_digit(pool['end']) + 1))
# we include the top gateway ip in the bottom ip allocation pool
b_pool_range1 = list(range(ip_to_digit(b_pools[0]['start']),
ip_to_digit(b_pools[0]['end']) + 1))
b_pool_range2 = list(range(ip_to_digit(b_pools[1]['start']),
ip_to_digit(b_pools[1]['end']) + 1))
b_pool_range = b_pool_range1 + [
ip_to_digit(b_gateway_ip)] + b_pool_range2
else:
self.assertIsNone(t_gateway_ip)
self.assertIsNone(b_gateway_ip)
pool_range = list(range(ip_to_digit(pool['start']),
ip_to_digit(pool['end'])))
b_pool_range = list(range(ip_to_digit(b_pools[0]['start']),
ip_to_digit(b_pools[0]['end'])))
port.pop('name')
b_port.pop('name')
self.assertDictEqual(net, b_net)
@ -376,6 +384,12 @@ class PluginTest(unittest.TestCase):
t_net, t_subnet, t_port, _ = self._prepare_resource()
self._validate(t_net, t_subnet, t_port)
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
def test_get_network_no_gateway(self):
t_net, t_subnet, t_port, _ = self._prepare_resource()
update_resource('subnet', True, t_subnet['id'], {'gateway_ip': None})
self._validate(t_net, t_subnet, t_port)
@patch.object(t_context, 'get_context_from_neutron_context', new=mock.Mock)
@patch.object(client.Client, 'get_admin_token', new=mock.Mock)
def test_get_networks(self):