NSXv: Enforce address scopes for no-NAT routers

Change-Id: I087dbde530d14c5cd2b96629b34aef94666ebbc8
This commit is contained in:
Roey Chen 2017-05-07 07:52:53 -07:00
parent 31f03e1caa
commit f016eb2bdd
3 changed files with 58 additions and 18 deletions

View File

@ -181,3 +181,9 @@ class NsxBgpSpeakerUnableToAddGatewayNetwork(n_exc.BadRequest):
message = _("Unable to add gateway network %(network_id)s to BGP speaker "
"%(bgp_speaker_id)s, network may be associated with one BGP "
"speaker at most.")
class NsxRouterInterfaceDoesNotMatchAddressScope(n_exc.BadRequest):
message = _("Unable to update no-NAT router %(router_id)s, "
"only subnets allocated from address-scope "
"%(address_scope_id)s can be connected.")

View File

@ -233,8 +233,8 @@ class RouterDistributedDriver(router_driver.RouterBaseDriver):
def _validate_multiple_subnets_routers(self, context, router_id,
interface_info):
_nsxv_plugin = self.plugin
net_id = _nsxv_plugin._get_interface_info_net_id(context,
interface_info)
net_id, subnet_id = _nsxv_plugin._get_interface_info(context,
interface_info)
port_filters = {'device_owner': [l3_db.DEVICE_OWNER_ROUTER_INTF],
'network_id': [net_id]}

View File

@ -65,6 +65,7 @@ from neutron.db import portsecurity_db
from neutron.db import quota_db # noqa
from neutron.db import securitygroups_db
from neutron.db import vlantransparent_db
from neutron.extensions import address_scope as ext_address_scope
from neutron.extensions import allowedaddresspairs as addr_pair
from neutron.extensions import availability_zone as az_ext
from neutron.extensions import external_net as ext_net_extn
@ -2969,7 +2970,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
def update_router(self, context, router_id, router):
# Validate that the gateway information is relevant
self._extract_external_gw(context, router, is_extract=False)
gw_info = self._extract_external_gw(context, router, is_extract=False)
# Toggling the distributed flag is not supported
if 'distributed' in router['router']:
r = self.get_router(context, router_id)
@ -3017,6 +3018,15 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# but remove the router-size that was already updated
router['router'].pop(ROUTER_SIZE, None)
if (validators.is_attr_set(gw_info) and
not gw_info.get('enable_snat', cfg.CONF.enable_snat_by_default)):
router_ports = self._get_router_interfaces(context, router_id)
for port in router_ports:
for fip in port['fixed_ips']:
self._validate_address_scope_for_router_interface(
context, router_id,
gw_info['network_id'], fip['subnet_id'])
router_driver = self._find_router_driver(context, router_id)
return router_driver.update_router(context, router_id, router)
@ -3266,6 +3276,11 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
'network_id': [network_id]}
return self.get_ports(context, filters=port_filters)
def _get_router_interfaces(self, context, router_id):
port_filters = {'device_id': [router_id],
'device_owner': [l3_db.DEVICE_OWNER_ROUTER_INTF]}
return self.get_ports(context, filters=port_filters)
def _get_address_groups(self, context, router_id, network_id):
address_groups = []
ports = self._get_router_interface_ports_by_network(
@ -3380,31 +3395,50 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
else:
edge_utils.update_internal_interface(*update_args)
def _get_interface_info_net_id(self, context, interface_info):
def _get_interface_info(self, context, interface_info):
is_port, is_sub = self._validate_interface_info(interface_info)
if is_port:
net_id = self.get_port(
context, interface_info['port_id'])['network_id']
port = self._check_router_port(context,
interface_info['port_id'], '')
subnet_id = port['fixed_ips'][0]['subnet_id']
net_id = port['network_id']
elif is_sub:
subnet_id = interface_info['subnet_id']
net_id = self.get_subnet(
context, interface_info['subnet_id'])['network_id']
return net_id
context, subnet_id)['network_id']
return net_id, subnet_id
def _is_external_interface_info(self, context, interface_info):
net_id = self._get_interface_info_net_id(context, interface_info)
network = self.get_network(context, net_id)
if (network.get(ext_net_extn.EXTERNAL)):
return True
return False
def _validate_address_scope_for_router_interface(self, context, router_id,
gw_network_id, subnet_id):
network = self.get_network(context, gw_network_id)
subnet = self.get_subnet(context, subnet_id)
address_scope = network.get(ext_address_scope.IPV4_ADDRESS_SCOPE)
if not address_scope:
return
if not subnet['subnetpool_id']:
raise nsx_exc.NsxRouterInterfaceDoesNotMatchAddressScope(
router_id=router_id, address_scope_id=address_scope)
subnetpool = self.get_subnetpool(context, subnet['subnetpool_id'])
if subnetpool.get('address_scope_id', '') != address_scope:
raise nsx_exc.NsxRouterInterfaceDoesNotMatchAddressScope(
router_id=router_id, address_scope_id=address_scope)
def add_router_interface(self, context, router_id, interface_info):
router = self.get_router(context, router_id)
net_id, subnet_id = self._get_interface_info(context, interface_info)
network = self.get_network(context.elevated(), net_id)
# Do not support external subnet/port as a router interface
if self._is_external_interface_info(context.elevated(),
interface_info):
msg = (_('cannot add an external subnet/port as a router '
'interface'))
if network.get(ext_net_extn.EXTERNAL):
msg = _("cannot add an external subnet/port as a router interface")
raise n_exc.InvalidInput(error_message=msg)
snat_disabled = (router[l3.EXTERNAL_GW_INFO] and
not router[l3.EXTERNAL_GW_INFO]['enable_snat'])
if snat_disabled and subnet_id:
gw_network_id = router[l3.EXTERNAL_GW_INFO]['network_id']
self._validate_address_scope_for_router_interface(
context, router_id, gw_network_id, subnet_id)
router_driver = self._find_router_driver(context, router_id)
try:
return router_driver.add_router_interface(