Disallow external subnets as router interfaces

Upstream neutron doesn't prevent subnets on external networks from
being used for router interfaces. The AIM mechanism driver treats
the boundary between unscoped internal and external networks as
a boundary for NAT. This makes the semantics confusing if subnets
on external networks are used as router interfaces and gateways,
and is therefore disallowed.

Change-Id: I164d655648c77f9a1fa12dc8927d64a5d50be356
This commit is contained in:
Thomas Bachman 2019-07-30 13:06:31 +00:00 committed by Thomas Bachman
parent ae2612a7bf
commit c4bb97aa29
3 changed files with 31 additions and 0 deletions

View File

@ -79,3 +79,9 @@ class ExternalSubnetOverlapInL3Out(exceptions.BadRequest):
class ExhaustedApicRouterIdPool(exceptions.IpAddressGenerationFailure):
message = _("All the IPs in the APIC router ID pool %(pool)s "
"have been taken.")
class ExternalSubnetNotAllowed(exceptions.BadRequest):
message = _("Connecting port or subnet which is on external network "
"%(network_id)s as a router interface is not allowed. "
"External networks can only be used as router gateways.")

View File

@ -1691,6 +1691,12 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
if self._is_preexisting_svi_db(network_db):
raise exceptions.PreExistingSVICannotBeConnectedToRouter()
# We disallow connecting subnets that are on an external network
# as router interfaces (can only use external networks for the
# router gateway).
if network_db.external:
raise exceptions.ExternalSubnetNotAllowed(network_id=network_id)
# Find the address_scope(s) for the new interface.
#
# REVISIT: If dual-stack interfaces allowed, process each

View File

@ -1785,6 +1785,25 @@ class TestAimMapping(ApicAimTestCase):
self.assertRaises(webob.exc.HTTPClientError, self._make_subnet,
self.fmt, net_resp, gw2_ip, '10.0.2.0/24')
def test_no_extneral_subnet_for_router_interface(self):
# Create external network with subnet.
ext_net1 = self._make_ext_network(
'ext-net1', dn=self.dn_t1_l1_n1)
subnet = self._make_subnet(
self.fmt, {'network': ext_net1}, '100.100.100.1',
'100.100.100.0/24')['subnet']
subnet_id = subnet['id']
# Create router.
router = self._make_router(
self.fmt, self._tenant_id, 'router1')['router']
router_id = router['id']
self.assertRaises(exceptions.ExternalSubnetNotAllowed,
self.l3_plugin.add_router_interface,
n_context.get_admin_context(), router_id,
{'subnet_id': subnet_id})
def _test_router_interface_with_address_scope(self, is_svi=False):
# REVISIT(rkukura): Currently follows same workflow as above,
# but might be sufficient to test with a single subnet with