Merge "Fix validation of IPv6 subnets with external RAs" into stable/rocky

This commit is contained in:
Zuul 2020-08-07 11:06:25 +00:00 committed by Gerrit Code Review
commit 7bc6864626
2 changed files with 44 additions and 6 deletions

View File

@ -116,6 +116,15 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
if l3plugin and port_check: if l3plugin and port_check:
l3plugin.prevent_l3_port_deletion(context, port_id) l3plugin.prevent_l3_port_deletion(context, port_id)
@staticmethod
def _validate_subnet_address_mode(subnet):
if (subnet['ip_version'] == 6 and subnet['ipv6_ra_mode'] is None and
subnet['ipv6_address_mode'] is not None):
msg = (_('IPv6 subnet %s configured to receive RAs from an '
'external router cannot be added to Neutron Router.') %
subnet['id'])
raise n_exc.BadRequest(resource='router', msg=msg)
@property @property
def _is_dns_integration_supported(self): def _is_dns_integration_supported(self):
if self._dns_integration is None: if self._dns_integration is None:
@ -703,6 +712,13 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
if not port['fixed_ips']: if not port['fixed_ips']:
msg = _('Router port must have at least one fixed IP') msg = _('Router port must have at least one fixed IP')
raise n_exc.BadRequest(resource='router', msg=msg) raise n_exc.BadRequest(resource='router', msg=msg)
fixed_ips = [ip for ip in port['fixed_ips']]
for fixed_ip in fixed_ips:
subnet = self._core_plugin.get_subnet(
context, fixed_ip['subnet_id'])
self._validate_subnet_address_mode(subnet)
return port return port
def _validate_port_in_range_or_admin(self, context, subnets, port): def _validate_port_in_range_or_admin(self, context, subnets, port):
@ -827,12 +843,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
msg = (_('Cannot add interface to router because subnet %s is not ' msg = (_('Cannot add interface to router because subnet %s is not '
'owned by project making the request') % subnet_id) 'owned by project making the request') % subnet_id)
raise n_exc.BadRequest(resource='router', msg=msg) raise n_exc.BadRequest(resource='router', msg=msg)
if (subnet['ip_version'] == 6 and subnet['ipv6_ra_mode'] is None and self._validate_subnet_address_mode(subnet)
subnet['ipv6_address_mode'] is not None):
msg = (_('IPv6 subnet %s configured to receive RAs from an '
'external router cannot be added to Neutron Router.') %
subnet['id'])
raise n_exc.BadRequest(resource='router', msg=msg)
self._check_for_dup_router_subnets(context, router, self._check_for_dup_router_subnets(context, router,
subnet['network_id'], [subnet]) subnet['network_id'], [subnet])
fixed_ip = {'ip_address': subnet['gateway_ip'], fixed_ip = {'ip_address': subnet['gateway_ip'],

View File

@ -1418,6 +1418,33 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
None, None,
p['port']['id']) p['port']['id'])
def test_update_router_interface_port_ipv6_subnet_ext_ra(self):
use_cases = [{'msg': 'IPv6 Subnet Modes (none, slaac)',
'ra_mode': None,
'address_mode': lib_constants.IPV6_SLAAC},
{'msg': 'IPv6 Subnet Modes (none, dhcpv6-stateful)',
'ra_mode': None,
'address_mode': lib_constants.DHCPV6_STATEFUL},
{'msg': 'IPv6 Subnet Modes (none, dhcpv6-stateless)',
'ra_mode': None,
'address_mode': lib_constants.DHCPV6_STATELESS}]
for uc in use_cases:
with self.network() as network, self.router() as router:
with self.subnet(
network=network, cidr='fd00::/64',
ip_version=lib_constants.IP_VERSION_6,
ipv6_ra_mode=uc['ra_mode'],
ipv6_address_mode=uc['address_mode']) as subnet:
fixed_ips = [{'subnet_id': subnet['subnet']['id']}]
with self.port(subnet=subnet, fixed_ips=fixed_ips) as port:
self._router_interface_action(
'add',
router['router']['id'],
None,
port['port']['id'],
expected_code=exc.HTTPBadRequest.code,
msg=uc['msg'])
def _assert_body_port_id_and_update_port(self, body, mock_update_port, def _assert_body_port_id_and_update_port(self, body, mock_update_port,
port_id, device_id): port_id, device_id):
self.assertNotIn('port_id', body) self.assertNotIn('port_id', body)