Merge "Make sure that gateway is in CIDR range by default"
This commit is contained in:
commit
5ec2f9e5b4
@ -115,8 +115,10 @@ lock_path = $state_path/lock
|
|||||||
# Attention: the following parameter MUST be set to False if Neutron is
|
# Attention: the following parameter MUST be set to False if Neutron is
|
||||||
# being used in conjunction with nova security groups
|
# being used in conjunction with nova security groups
|
||||||
# allow_overlapping_ips = False
|
# allow_overlapping_ips = False
|
||||||
# Ensure that configured gateway is on subnet
|
# Ensure that configured gateway is on subnet. For IPv6, validate only if
|
||||||
# force_gateway_on_subnet = False
|
# gateway is not a link local address. Deprecated, to be removed during the
|
||||||
|
# K release, at which point the check will be mandatory.
|
||||||
|
# force_gateway_on_subnet = True
|
||||||
|
|
||||||
# Default maximum number of items returned in a single response,
|
# Default maximum number of items returned in a single response,
|
||||||
# value == infinite and value < 0 means no max limit, and value must
|
# value == infinite and value < 0 means no max limit, and value must
|
||||||
|
@ -80,8 +80,12 @@ core_opts = [
|
|||||||
help=_("Allow overlapping IP support in Neutron")),
|
help=_("Allow overlapping IP support in Neutron")),
|
||||||
cfg.StrOpt('host', default=utils.get_hostname(),
|
cfg.StrOpt('host', default=utils.get_hostname(),
|
||||||
help=_("The hostname Neutron is running on")),
|
help=_("The hostname Neutron is running on")),
|
||||||
cfg.BoolOpt('force_gateway_on_subnet', default=False,
|
cfg.BoolOpt('force_gateway_on_subnet', default=True,
|
||||||
help=_("Ensure that configured gateway is on subnet")),
|
help=_("Ensure that configured gateway is on subnet. "
|
||||||
|
"For IPv6, validate only if gateway is not a link "
|
||||||
|
"local address. Deprecated, to be removed during the "
|
||||||
|
"K release, at which point the check will be "
|
||||||
|
"mandatory.")),
|
||||||
cfg.BoolOpt('notify_nova_on_port_status_changes', default=True,
|
cfg.BoolOpt('notify_nova_on_port_status_changes', default=True,
|
||||||
help=_("Send notification to nova when port status changes")),
|
help=_("Send notification to nova when port status changes")),
|
||||||
cfg.BoolOpt('notify_nova_on_port_data_changes', default=True,
|
cfg.BoolOpt('notify_nova_on_port_data_changes', default=True,
|
||||||
|
@ -317,8 +317,16 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def _check_subnet_ip(cidr, ip_address):
|
def _check_gateway_in_subnet(cls, cidr, gateway):
|
||||||
|
"""Validate that the gateway is on the subnet."""
|
||||||
|
ip = netaddr.IPAddress(gateway)
|
||||||
|
if ip.version == 4 or (ip.version == 6 and not ip.is_link_local()):
|
||||||
|
return cls._check_subnet_ip(cidr, gateway)
|
||||||
|
return True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _check_subnet_ip(cls, cidr, ip_address):
|
||||||
"""Validate that the IP address is on the subnet."""
|
"""Validate that the IP address is on the subnet."""
|
||||||
ip = netaddr.IPAddress(ip_address)
|
ip = netaddr.IPAddress(ip_address)
|
||||||
net = netaddr.IPNetwork(cidr)
|
net = netaddr.IPNetwork(cidr)
|
||||||
@ -375,7 +383,7 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
filter = {'network_id': [network_id]}
|
filter = {'network_id': [network_id]}
|
||||||
subnets = self.get_subnets(context, filters=filter)
|
subnets = self.get_subnets(context, filters=filter)
|
||||||
for subnet in subnets:
|
for subnet in subnets:
|
||||||
if NeutronDbPluginV2._check_subnet_ip(subnet['cidr'],
|
if self._check_subnet_ip(subnet['cidr'],
|
||||||
fixed['ip_address']):
|
fixed['ip_address']):
|
||||||
found = True
|
found = True
|
||||||
subnet_id = subnet['id']
|
subnet_id = subnet['id']
|
||||||
@ -405,8 +413,8 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
|
|
||||||
# Ensure that the IP is valid on the subnet
|
# Ensure that the IP is valid on the subnet
|
||||||
if (not found and
|
if (not found and
|
||||||
not NeutronDbPluginV2._check_subnet_ip(
|
not self._check_subnet_ip(subnet['cidr'],
|
||||||
subnet['cidr'], fixed['ip_address'])):
|
fixed['ip_address'])):
|
||||||
msg = _('IP address %s is not a valid IP for the defined '
|
msg = _('IP address %s is not a valid IP for the defined '
|
||||||
'subnet') % fixed['ip_address']
|
'subnet') % fixed['ip_address']
|
||||||
raise n_exc.InvalidInput(error_message=msg)
|
raise n_exc.InvalidInput(error_message=msg)
|
||||||
@ -930,8 +938,8 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
if attributes.is_attr_set(s.get('gateway_ip')):
|
if attributes.is_attr_set(s.get('gateway_ip')):
|
||||||
self._validate_ip_version(ip_ver, s['gateway_ip'], 'gateway_ip')
|
self._validate_ip_version(ip_ver, s['gateway_ip'], 'gateway_ip')
|
||||||
if (cfg.CONF.force_gateway_on_subnet and
|
if (cfg.CONF.force_gateway_on_subnet and
|
||||||
not NeutronDbPluginV2._check_subnet_ip(s['cidr'],
|
not self._check_gateway_in_subnet(
|
||||||
s['gateway_ip'])):
|
s['cidr'], s['gateway_ip'])):
|
||||||
error_message = _("Gateway is not valid on subnet")
|
error_message = _("Gateway is not valid on subnet")
|
||||||
raise n_exc.InvalidInput(error_message=error_message)
|
raise n_exc.InvalidInput(error_message=error_message)
|
||||||
# Ensure the gateway IP is not assigned to any port
|
# Ensure the gateway IP is not assigned to any port
|
||||||
|
@ -550,7 +550,7 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
|
|||||||
'name': 'subnet1',
|
'name': 'subnet1',
|
||||||
'tenant_id':
|
'tenant_id':
|
||||||
network['network']['tenant_id'],
|
network['network']['tenant_id'],
|
||||||
'gateway_ip': '10.0.2.1'}}
|
'gateway_ip': '10.0.20.1'}}
|
||||||
req = self.new_create_request('subnets', data)
|
req = self.new_create_request('subnets', data)
|
||||||
res = req.get_response(self.api)
|
res = req.get_response(self.api)
|
||||||
self.assertEqual(500, res.status_int)
|
self.assertEqual(500, res.status_int)
|
||||||
@ -577,7 +577,7 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
|
|||||||
'name': 'subnet1',
|
'name': 'subnet1',
|
||||||
'tenant_id':
|
'tenant_id':
|
||||||
network['network']['tenant_id'],
|
network['network']['tenant_id'],
|
||||||
'gateway_ip': '10.0.2.1'}}
|
'gateway_ip': '10.0.20.1'}}
|
||||||
subnet_req = self.new_create_request('subnets', data)
|
subnet_req = self.new_create_request('subnets', data)
|
||||||
subnet_res = subnet_req.get_response(self.api)
|
subnet_res = subnet_req.get_response(self.api)
|
||||||
self.assertEqual(201, subnet_res.status_int)
|
self.assertEqual(201, subnet_res.status_int)
|
||||||
@ -608,7 +608,7 @@ class TestFaultyMechansimDriver(Ml2PluginV2FaultyDriverTestCase):
|
|||||||
'name': 'subnet1',
|
'name': 'subnet1',
|
||||||
'tenant_id':
|
'tenant_id':
|
||||||
network['network']['tenant_id'],
|
network['network']['tenant_id'],
|
||||||
'gateway_ip': '10.0.2.1'}}
|
'gateway_ip': '10.0.20.1'}}
|
||||||
subnet_req = self.new_create_request('subnets', data)
|
subnet_req = self.new_create_request('subnets', data)
|
||||||
subnet_res = subnet_req.get_response(self.api)
|
subnet_res = subnet_req.get_response(self.api)
|
||||||
self.assertEqual(201, subnet_res.status_int)
|
self.assertEqual(201, subnet_res.status_int)
|
||||||
|
@ -216,6 +216,10 @@ class TestNuageSubnetsV2(NuagePluginV2TestCase,
|
|||||||
self.skipTest("Plugin does not support "
|
self.skipTest("Plugin does not support "
|
||||||
"Neutron Subnet no-gateway option")
|
"Neutron Subnet no-gateway option")
|
||||||
|
|
||||||
|
def test_create_subnet_nonzero_cidr(self):
|
||||||
|
self.skipTest("Plugin does not support "
|
||||||
|
"Neutron Subnet no-gateway option")
|
||||||
|
|
||||||
def test_create_subnet_with_none_gateway_fully_allocated(self):
|
def test_create_subnet_with_none_gateway_fully_allocated(self):
|
||||||
self.skipTest("Plugin does not support Neutron "
|
self.skipTest("Plugin does not support Neutron "
|
||||||
"Subnet no-gateway option")
|
"Subnet no-gateway option")
|
||||||
@ -235,7 +239,9 @@ class TestNuagePluginPortBinding(NuagePluginV2TestCase,
|
|||||||
|
|
||||||
class TestNuagePortsV2(NuagePluginV2TestCase,
|
class TestNuagePortsV2(NuagePluginV2TestCase,
|
||||||
test_db_plugin.TestPortsV2):
|
test_db_plugin.TestPortsV2):
|
||||||
pass
|
def test_no_more_port_exception(self):
|
||||||
|
self.skipTest("Plugin does not support "
|
||||||
|
"Neutron Subnet no-gateway option")
|
||||||
|
|
||||||
|
|
||||||
class TestNuageL3NatTestCase(NuagePluginV2TestCase,
|
class TestNuageL3NatTestCase(NuagePluginV2TestCase,
|
||||||
|
@ -87,6 +87,12 @@ class TestOneConvergencePluginSubnetsV2(test_plugin.TestSubnetsV2,
|
|||||||
def test_update_subnet_ipv6_inconsistent_address_attribute(self):
|
def test_update_subnet_ipv6_inconsistent_address_attribute(self):
|
||||||
self.skipTest("NVSD Plugin does not support IPV6.")
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_create_subnet_ipv6_out_of_cidr_global(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
def test_create_subnet_ipv6_out_of_cidr_lla(self):
|
||||||
|
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||||
|
|
||||||
|
|
||||||
class TestOneConvergencePluginPortsV2(test_plugin.TestPortsV2,
|
class TestOneConvergencePluginPortsV2(test_plugin.TestPortsV2,
|
||||||
test_bindings.PortBindingsTestCase,
|
test_bindings.PortBindingsTestCase,
|
||||||
|
@ -1148,7 +1148,7 @@ fixed_ips=ip_address%%3D%s&fixed_ips=ip_address%%3D%s&fixed_ips=subnet_id%%3D%s
|
|||||||
data['port']['fixed_ips'])
|
data['port']['fixed_ips'])
|
||||||
|
|
||||||
def test_no_more_port_exception(self):
|
def test_no_more_port_exception(self):
|
||||||
with self.subnet(cidr='10.0.0.0/32') as subnet:
|
with self.subnet(cidr='10.0.0.0/32', gateway_ip=None) as subnet:
|
||||||
id = subnet['subnet']['network_id']
|
id = subnet['subnet']['network_id']
|
||||||
res = self._create_port(self.fmt, id)
|
res = self._create_port(self.fmt, id)
|
||||||
data = self.deserialize(self.fmt, res)
|
data = self.deserialize(self.fmt, res)
|
||||||
@ -2587,7 +2587,7 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
|||||||
self.subnet(cidr='14.129.122.5/22'),
|
self.subnet(cidr='14.129.122.5/22'),
|
||||||
self.subnet(cidr='15.129.122.5/24'),
|
self.subnet(cidr='15.129.122.5/24'),
|
||||||
self.subnet(cidr='16.129.122.5/28'),
|
self.subnet(cidr='16.129.122.5/28'),
|
||||||
self.subnet(cidr='17.129.122.5/32')
|
self.subnet(cidr='17.129.122.5/32', gateway_ip=None)
|
||||||
) as subs:
|
) as subs:
|
||||||
# the API should accept and correct these for users
|
# the API should accept and correct these for users
|
||||||
self.assertEqual(subs[0]['subnet']['cidr'], '10.0.0.0/8')
|
self.assertEqual(subs[0]['subnet']['cidr'], '10.0.0.0/8')
|
||||||
@ -2728,15 +2728,7 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
|||||||
allocation_pools)
|
allocation_pools)
|
||||||
|
|
||||||
def test_create_subnet_gw_values(self):
|
def test_create_subnet_gw_values(self):
|
||||||
# Gateway not in subnet
|
|
||||||
gateway = '100.0.0.1'
|
|
||||||
cidr = '10.0.0.0/24'
|
cidr = '10.0.0.0/24'
|
||||||
allocation_pools = [{'start': '10.0.0.1',
|
|
||||||
'end': '10.0.0.254'}]
|
|
||||||
expected = {'gateway_ip': gateway,
|
|
||||||
'cidr': cidr,
|
|
||||||
'allocation_pools': allocation_pools}
|
|
||||||
self._test_create_subnet(expected=expected, gateway_ip=gateway)
|
|
||||||
# Gateway is last IP in range
|
# Gateway is last IP in range
|
||||||
gateway = '10.0.0.254'
|
gateway = '10.0.0.254'
|
||||||
allocation_pools = [{'start': '10.0.0.1',
|
allocation_pools = [{'start': '10.0.0.1',
|
||||||
@ -2755,8 +2747,7 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
|||||||
self._test_create_subnet(expected=expected,
|
self._test_create_subnet(expected=expected,
|
||||||
gateway_ip=gateway)
|
gateway_ip=gateway)
|
||||||
|
|
||||||
def test_create_subnet_gw_outside_cidr_force_on_returns_400(self):
|
def test_create_subnet_gw_outside_cidr_returns_400(self):
|
||||||
cfg.CONF.set_override('force_gateway_on_subnet', True)
|
|
||||||
with self.network() as network:
|
with self.network() as network:
|
||||||
self._create_subnet(self.fmt,
|
self._create_subnet(self.fmt,
|
||||||
network['network']['id'],
|
network['network']['id'],
|
||||||
@ -2764,8 +2755,7 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
|||||||
webob.exc.HTTPClientError.code,
|
webob.exc.HTTPClientError.code,
|
||||||
gateway_ip='100.0.0.1')
|
gateway_ip='100.0.0.1')
|
||||||
|
|
||||||
def test_create_subnet_gw_of_network_force_on_returns_400(self):
|
def test_create_subnet_gw_of_network_returns_400(self):
|
||||||
cfg.CONF.set_override('force_gateway_on_subnet', True)
|
|
||||||
with self.network() as network:
|
with self.network() as network:
|
||||||
self._create_subnet(self.fmt,
|
self._create_subnet(self.fmt,
|
||||||
network['network']['id'],
|
network['network']['id'],
|
||||||
@ -2773,8 +2763,7 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
|||||||
webob.exc.HTTPClientError.code,
|
webob.exc.HTTPClientError.code,
|
||||||
gateway_ip='10.0.0.0')
|
gateway_ip='10.0.0.0')
|
||||||
|
|
||||||
def test_create_subnet_gw_bcast_force_on_returns_400(self):
|
def test_create_subnet_gw_bcast_returns_400(self):
|
||||||
cfg.CONF.set_override('force_gateway_on_subnet', True)
|
|
||||||
with self.network() as network:
|
with self.network() as network:
|
||||||
self._create_subnet(self.fmt,
|
self._create_subnet(self.fmt,
|
||||||
network['network']['id'],
|
network['network']['id'],
|
||||||
@ -3042,6 +3031,28 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
|||||||
ipv6_ra_mode=mode,
|
ipv6_ra_mode=mode,
|
||||||
ipv6_address_mode=mode)
|
ipv6_address_mode=mode)
|
||||||
|
|
||||||
|
def test_create_subnet_ipv6_out_of_cidr_global(self):
|
||||||
|
gateway_ip = '2000::1'
|
||||||
|
cidr = '2001::/64'
|
||||||
|
|
||||||
|
with testlib_api.ExpectedException(
|
||||||
|
webob.exc.HTTPClientError) as ctx_manager:
|
||||||
|
self._test_create_subnet(
|
||||||
|
gateway_ip=gateway_ip, cidr=cidr, ip_version=6,
|
||||||
|
ipv6_ra_mode=constants.DHCPV6_STATEFUL,
|
||||||
|
ipv6_address_mode=constants.DHCPV6_STATEFUL)
|
||||||
|
self.assertEqual(ctx_manager.exception.code,
|
||||||
|
webob.exc.HTTPClientError.code)
|
||||||
|
|
||||||
|
def test_create_subnet_ipv6_out_of_cidr_lla(self):
|
||||||
|
gateway_ip = 'fe80::1'
|
||||||
|
cidr = '2001::/64'
|
||||||
|
|
||||||
|
self._test_create_subnet(
|
||||||
|
gateway_ip=gateway_ip, cidr=cidr, ip_version=6,
|
||||||
|
ipv6_ra_mode=constants.IPV6_SLAAC,
|
||||||
|
ipv6_address_mode=constants.IPV6_SLAAC)
|
||||||
|
|
||||||
def test_create_subnet_ipv6_attributes_no_dhcp_enabled(self):
|
def test_create_subnet_ipv6_attributes_no_dhcp_enabled(self):
|
||||||
gateway_ip = 'fe80::1'
|
gateway_ip = 'fe80::1'
|
||||||
cidr = 'fe80::/80'
|
cidr = 'fe80::/80'
|
||||||
@ -3126,7 +3137,7 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
|||||||
|
|
||||||
def test_update_subnet_no_gateway(self):
|
def test_update_subnet_no_gateway(self):
|
||||||
with self.subnet() as subnet:
|
with self.subnet() as subnet:
|
||||||
data = {'subnet': {'gateway_ip': '11.0.0.1'}}
|
data = {'subnet': {'gateway_ip': '10.0.0.1'}}
|
||||||
req = self.new_update_request('subnets', data,
|
req = self.new_update_request('subnets', data,
|
||||||
subnet['subnet']['id'])
|
subnet['subnet']['id'])
|
||||||
res = self.deserialize(self.fmt, req.get_response(self.api))
|
res = self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
@ -3140,7 +3151,7 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
|||||||
|
|
||||||
def test_update_subnet(self):
|
def test_update_subnet(self):
|
||||||
with self.subnet() as subnet:
|
with self.subnet() as subnet:
|
||||||
data = {'subnet': {'gateway_ip': '11.0.0.1'}}
|
data = {'subnet': {'gateway_ip': '10.0.0.1'}}
|
||||||
req = self.new_update_request('subnets', data,
|
req = self.new_update_request('subnets', data,
|
||||||
subnet['subnet']['id'])
|
subnet['subnet']['id'])
|
||||||
res = self.deserialize(self.fmt, req.get_response(self.api))
|
res = self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
@ -3186,8 +3197,7 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
|||||||
self.assertEqual(res.status_int,
|
self.assertEqual(res.status_int,
|
||||||
webob.exc.HTTPClientError.code)
|
webob.exc.HTTPClientError.code)
|
||||||
|
|
||||||
def test_update_subnet_gw_outside_cidr_force_on_returns_400(self):
|
def test_update_subnet_gw_outside_cidr_returns_400(self):
|
||||||
cfg.CONF.set_override('force_gateway_on_subnet', True)
|
|
||||||
with self.network() as network:
|
with self.network() as network:
|
||||||
with self.subnet(network=network) as subnet:
|
with self.subnet(network=network) as subnet:
|
||||||
data = {'subnet': {'gateway_ip': '100.0.0.1'}}
|
data = {'subnet': {'gateway_ip': '100.0.0.1'}}
|
||||||
|
@ -943,8 +943,6 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
|
|||||||
try_overlapped_cidr('10.0.1.0/24')
|
try_overlapped_cidr('10.0.1.0/24')
|
||||||
# another subnet with overlapped cidr including s1
|
# another subnet with overlapped cidr including s1
|
||||||
try_overlapped_cidr('10.0.0.0/16')
|
try_overlapped_cidr('10.0.0.0/16')
|
||||||
# another subnet with overlapped cidr included by s1
|
|
||||||
try_overlapped_cidr('10.0.1.1/32')
|
|
||||||
# clean-up
|
# clean-up
|
||||||
self._router_interface_action('remove',
|
self._router_interface_action('remove',
|
||||||
r['router']['id'],
|
r['router']['id'],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user