Merge "NSX-V3: Enhance VPNaaS related validations"
This commit is contained in:
commit
4277b21c5a
@ -3741,7 +3741,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
|
||||
# VPNaaS need to be notified on router GW changes (there is
|
||||
# currentlyno matching upstream registration for this)
|
||||
# currently no matching upstream registration for this)
|
||||
vpn_plugin = directory.get_plugin(plugin_const.VPN)
|
||||
if vpn_plugin:
|
||||
vpn_driver = vpn_plugin.drivers[vpn_plugin.default_provider]
|
||||
|
@ -38,7 +38,7 @@ from vmware_nsxlib.v3 import vpn_ipsec
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
IPSEC = 'ipsec'
|
||||
VPN_PORT_OWNER = constants.DEVICE_OWNER_NEUTRON_PREFIX + 'vpnservice'
|
||||
VPN_PORT_OWNER = 'vpnservice'
|
||||
|
||||
|
||||
class RouterWithSNAT(nexception.BadRequest):
|
||||
@ -46,6 +46,16 @@ class RouterWithSNAT(nexception.BadRequest):
|
||||
"SNAT")
|
||||
|
||||
|
||||
class RouterWithOverlapNoSnat(nexception.BadRequest):
|
||||
message = _("Router %(router_id)s has a subnet overlapping with a VPN "
|
||||
"local subnet, and cannot disable SNAT")
|
||||
|
||||
|
||||
class RouterOverlapping(nexception.BadRequest):
|
||||
message = _("Router %(router_id)s interface is overlapping with a VPN "
|
||||
"local subnet and cannot be added")
|
||||
|
||||
|
||||
class NSXv3IPsecVpnDriver(service_drivers.VpnDriver):
|
||||
|
||||
def __init__(self, service_plugin):
|
||||
@ -63,6 +73,10 @@ class NSXv3IPsecVpnDriver(service_drivers.VpnDriver):
|
||||
self._delete_local_endpoint, resources.ROUTER_GATEWAY,
|
||||
events.AFTER_DELETE)
|
||||
|
||||
registry.subscribe(
|
||||
self._verify_overlap_subnet, resources.ROUTER_INTERFACE,
|
||||
events.BEFORE_CREATE)
|
||||
|
||||
@property
|
||||
def l3_plugin(self):
|
||||
return self._core_plugin
|
||||
@ -364,7 +378,7 @@ class NSXv3IPsecVpnDriver(service_drivers.VpnDriver):
|
||||
|
||||
def _find_vpn_service_port(self, context, router_id):
|
||||
"""Look for the neutron port created for the vpnservice of a router"""
|
||||
filters = {'device_id': [router_id],
|
||||
filters = {'device_id': ['router-' + router_id],
|
||||
'device_owner': [VPN_PORT_OWNER]}
|
||||
ports = self.l3_plugin.get_ports(context, filters=filters)
|
||||
if ports:
|
||||
@ -383,18 +397,68 @@ class NSXv3IPsecVpnDriver(service_drivers.VpnDriver):
|
||||
if port:
|
||||
self.l3_plugin.delete_port(ctx, port['id'])
|
||||
|
||||
def _check_subnets_overlap_with_all_conns(self, context, subnets):
|
||||
# find all vpn services with connections
|
||||
filters = {'status': [constants.ACTIVE]}
|
||||
connections = self.vpn_plugin.get_ipsec_site_connections(
|
||||
context, filters=filters)
|
||||
for conn in connections:
|
||||
srv_id = conn.get('vpnservice_id')
|
||||
srv = self.vpn_plugin._get_vpnservice(context, srv_id)
|
||||
srv_subnet = self.l3_plugin.get_subnet(
|
||||
context, srv['subnet_id'])
|
||||
if netaddr.IPSet(subnets) & netaddr.IPSet([srv_subnet['cidr']]):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _verify_overlap_subnet(self, resource, event, trigger, **kwargs):
|
||||
"""Upon router interface creation validation overlapping with vpn"""
|
||||
router_db = kwargs.get('router_db')
|
||||
port = kwargs.get('port')
|
||||
if not port or not router_db:
|
||||
LOG.warning("NSX V3 VPNaaS ROUTER_INTERFACE BEFORE_CRAETE "
|
||||
"callback didn't get all the relevant information")
|
||||
return
|
||||
|
||||
if router_db.enable_snat:
|
||||
# checking only no-snat routers
|
||||
return
|
||||
|
||||
admin_con = n_context.get_admin_context()
|
||||
subnet_id = port['fixed_ips'][0].get('subnet_id')
|
||||
if subnet_id:
|
||||
subnet = self._core_plugin.get_subnet(admin_con, subnet_id)
|
||||
# find all vpn services with connections
|
||||
if not self._check_subnets_overlap_with_all_conns(
|
||||
admin_con, [subnet['cidr']]):
|
||||
raise RouterOverlapping(router_id=kwargs.get('router_id'))
|
||||
|
||||
def validate_router_gw_info(self, context, router_id, gw_info):
|
||||
"""Upon router gw update - verify no-snat"""
|
||||
# ckeck if this router has a vpn service
|
||||
# check if this router has a vpn service
|
||||
admin_con = context.elevated()
|
||||
filters = {'router_id': [router_id],
|
||||
'status': [constants.ACTIVE]}
|
||||
services = self.vpn_plugin.get_vpnservices(
|
||||
context.elevated(), filters=filters)
|
||||
services = self.vpn_plugin.get_vpnservices(admin_con, filters=filters)
|
||||
if services:
|
||||
# do not allow enable-snat
|
||||
if (gw_info and
|
||||
gw_info.get('enable_snat', cfg.CONF.enable_snat_by_default)):
|
||||
raise RouterWithSNAT(router_id=router_id)
|
||||
else:
|
||||
# if this is a non-vpn router. if snat was disabled, should check
|
||||
# there is no overlapping with vpn connections
|
||||
if (gw_info and
|
||||
not gw_info.get('enable_snat',
|
||||
cfg.CONF.enable_snat_by_default)):
|
||||
# get router subnets
|
||||
subnets = self._core_plugin._find_router_subnets_cidrs(
|
||||
context, router_id)
|
||||
# find all vpn services with connections
|
||||
if not self._check_subnets_overlap_with_all_conns(
|
||||
admin_con, subnets):
|
||||
raise RouterWithOverlapNoSnat(router_id=router_id)
|
||||
|
||||
def _get_session_rules(self, context, connection, vpnservice):
|
||||
# TODO(asarfaty): support vpn-endpoint-groups too
|
||||
@ -600,7 +664,7 @@ class NSXv3IPsecVpnDriver(service_drivers.VpnDriver):
|
||||
def _create_vpn_service(self, tier0_uuid):
|
||||
try:
|
||||
service = self._nsx_vpn.service.create(
|
||||
'Neutron VPN service for router ' + tier0_uuid,
|
||||
'Neutron VPN service for T0 router ' + tier0_uuid,
|
||||
tier0_uuid,
|
||||
enabled=True,
|
||||
ike_log_level=ipsec_utils.DEFAULT_LOG_LEVEL,
|
||||
@ -658,13 +722,15 @@ class NSXv3IPsecVpnDriver(service_drivers.VpnDriver):
|
||||
port = self._find_vpn_service_port(context, router_id)
|
||||
if not port:
|
||||
# create a new port, on the external network of the router
|
||||
# Note(asarfaty): using a unique device owner and device id to
|
||||
# make sure tis port will be ignored in certain queries
|
||||
ext_net = vpnservice.router.gw_port['network_id']
|
||||
port_data = {
|
||||
'port': {
|
||||
'network_id': ext_net,
|
||||
'name': None,
|
||||
'name': 'VPN local address port',
|
||||
'admin_state_up': True,
|
||||
'device_id': vpnservice.router['id'],
|
||||
'device_id': 'router-' + vpnservice.router['id'],
|
||||
'device_owner': VPN_PORT_OWNER,
|
||||
'fixed_ips': constants.ATTR_NOT_SPECIFIED,
|
||||
'mac_address': constants.ATTR_NOT_SPECIFIED,
|
||||
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
import netaddr
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from neutron_lib import constants
|
||||
@ -235,7 +236,8 @@ class IPsecV3Validator(vpn_validator.VpnReferenceValidator):
|
||||
if (rtr['id'] != this_router and
|
||||
rtr.get('external_gateway_info') and
|
||||
not rtr['external_gateway_info'].get(
|
||||
'enable_snat', True))]
|
||||
'enable_snat',
|
||||
cfg.CONF.enable_snat_by_default))]
|
||||
for rtr in nosnat_routers:
|
||||
if rtr['id'] == this_router:
|
||||
continue
|
||||
@ -271,9 +273,6 @@ class IPsecV3Validator(vpn_validator.VpnReferenceValidator):
|
||||
'conn': conn['id']})
|
||||
raise nsx_exc.NsxVpnValidationError(details=msg)
|
||||
|
||||
# TODO(asarfaty): also add this validation when adding an interface
|
||||
# or no-snat to a router through the nsx-v3 plugin
|
||||
|
||||
def validate_ipsec_site_connection(self, context, ipsec_site_conn):
|
||||
"""Called upon create/update of a connection"""
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user