# Attention: the following parameter MUST be set to False if Neutron is
# being used in conjunction with nova security groups
# allow_overlapping_ips = False
-# Ensure that configured gateway is on subnet
-# force_gateway_on_subnet = False
+# 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.
+# force_gateway_on_subnet = True
# Default maximum number of items returned in a single response,
# value == infinite and value < 0 means no max limit, and value must
help=_("Allow overlapping IP support in Neutron")),
cfg.StrOpt('host', default=utils.get_hostname(),
help=_("The hostname Neutron is running on")),
- cfg.BoolOpt('force_gateway_on_subnet', default=False,
- help=_("Ensure that configured gateway is on subnet")),
+ cfg.BoolOpt('force_gateway_on_subnet', default=True,
+ 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,
help=_("Send notification to nova when port status changes")),
cfg.BoolOpt('notify_nova_on_port_data_changes', default=True,
return True
return False
- @staticmethod
- def _check_subnet_ip(cidr, ip_address):
+ @classmethod
+ 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."""
ip = netaddr.IPAddress(ip_address)
net = netaddr.IPNetwork(cidr)
filter = {'network_id': [network_id]}
subnets = self.get_subnets(context, filters=filter)
for subnet in subnets:
- if NeutronDbPluginV2._check_subnet_ip(subnet['cidr'],
- fixed['ip_address']):
+ if self._check_subnet_ip(subnet['cidr'],
+ fixed['ip_address']):
found = True
subnet_id = subnet['id']
break
# Ensure that the IP is valid on the subnet
if (not found and
- not NeutronDbPluginV2._check_subnet_ip(
- subnet['cidr'], fixed['ip_address'])):
+ not self._check_subnet_ip(subnet['cidr'],
+ fixed['ip_address'])):
msg = _('IP address %s is not a valid IP for the defined '
'subnet') % fixed['ip_address']
raise n_exc.InvalidInput(error_message=msg)
if attributes.is_attr_set(s.get('gateway_ip')):
self._validate_ip_version(ip_ver, s['gateway_ip'], 'gateway_ip')
if (cfg.CONF.force_gateway_on_subnet and
- not NeutronDbPluginV2._check_subnet_ip(s['cidr'],
- s['gateway_ip'])):
+ not self._check_gateway_in_subnet(
+ s['cidr'], s['gateway_ip'])):
error_message = _("Gateway is not valid on subnet")
raise n_exc.InvalidInput(error_message=error_message)
# Ensure the gateway IP is not assigned to any port
'name': 'subnet1',
'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)
res = req.get_response(self.api)
self.assertEqual(500, res.status_int)
'name': 'subnet1',
'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_res = subnet_req.get_response(self.api)
self.assertEqual(201, subnet_res.status_int)
'name': 'subnet1',
'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_res = subnet_req.get_response(self.api)
self.assertEqual(201, subnet_res.status_int)
self.skipTest("Plugin does not support "
"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):
self.skipTest("Plugin does not support Neutron "
"Subnet no-gateway option")
class TestNuagePortsV2(NuagePluginV2TestCase,
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,
def test_update_subnet_ipv6_inconsistent_address_attribute(self):
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,
test_bindings.PortBindingsTestCase,
data['port']['fixed_ips'])
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']
res = self._create_port(self.fmt, id)
data = self.deserialize(self.fmt, res)
self.subnet(cidr='14.129.122.5/22'),
self.subnet(cidr='15.129.122.5/24'),
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:
# the API should accept and correct these for users
self.assertEqual(subs[0]['subnet']['cidr'], '10.0.0.0/8')
allocation_pools)
def test_create_subnet_gw_values(self):
- # Gateway not in subnet
- gateway = '100.0.0.1'
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 = '10.0.0.254'
allocation_pools = [{'start': '10.0.0.1',
self._test_create_subnet(expected=expected,
gateway_ip=gateway)
- def test_create_subnet_gw_outside_cidr_force_on_returns_400(self):
- cfg.CONF.set_override('force_gateway_on_subnet', True)
+ def test_create_subnet_gw_outside_cidr_returns_400(self):
with self.network() as network:
self._create_subnet(self.fmt,
network['network']['id'],
webob.exc.HTTPClientError.code,
gateway_ip='100.0.0.1')
- def test_create_subnet_gw_of_network_force_on_returns_400(self):
- cfg.CONF.set_override('force_gateway_on_subnet', True)
+ def test_create_subnet_gw_of_network_returns_400(self):
with self.network() as network:
self._create_subnet(self.fmt,
network['network']['id'],
webob.exc.HTTPClientError.code,
gateway_ip='10.0.0.0')
- def test_create_subnet_gw_bcast_force_on_returns_400(self):
- cfg.CONF.set_override('force_gateway_on_subnet', True)
+ def test_create_subnet_gw_bcast_returns_400(self):
with self.network() as network:
self._create_subnet(self.fmt,
network['network']['id'],
ipv6_ra_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):
gateway_ip = 'fe80::1'
cidr = 'fe80::/80'
def test_update_subnet_no_gateway(self):
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,
subnet['subnet']['id'])
res = self.deserialize(self.fmt, req.get_response(self.api))
def test_update_subnet(self):
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,
subnet['subnet']['id'])
res = self.deserialize(self.fmt, req.get_response(self.api))
self.assertEqual(res.status_int,
webob.exc.HTTPClientError.code)
- def test_update_subnet_gw_outside_cidr_force_on_returns_400(self):
- cfg.CONF.set_override('force_gateway_on_subnet', True)
+ def test_update_subnet_gw_outside_cidr_returns_400(self):
with self.network() as network:
with self.subnet(network=network) as subnet:
data = {'subnet': {'gateway_ip': '100.0.0.1'}}
try_overlapped_cidr('10.0.1.0/24')
# another subnet with overlapped cidr including s1
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
self._router_interface_action('remove',
r['router']['id'],