Merge "NSX|P: Make sure service router exists for vlan interface" into stable/train

This commit is contained in:
Zuul 2020-05-06 12:53:09 +00:00 committed by Gerrit Code Review
commit f9058967da
2 changed files with 103 additions and 4 deletions

View File

@ -2347,10 +2347,22 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
return self.nsxpolicy.tier0.get_edge_cluster_path(
tier0_uuid)
def _get_router_vlan_interfaces(self, context, router_id):
# return data about VLAN subnet connected to the router
rtr_subnets = self._load_router_subnet_cidrs_from_db(
context, router_id)
vlan_subnets = []
for sub in rtr_subnets:
net_id = sub['network_id']
if not self._is_overlay_network(context, net_id):
vlan_subnets.append(sub)
return vlan_subnets
def service_router_has_services(self, context, router_id, router=None):
"""Check if the neutron router has any services
which require a backend service router
currently those are: SNAT, Loadbalancer, Edge firewall
currently those are: SNAT, Loadbalancer, Edge firewall,
VPNaaS & Vlan interfaces
"""
if not router:
router = self._get_router(context, router_id)
@ -2358,10 +2370,15 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
fw_exist = self._router_has_edge_fw_rules(context, router)
vpn_exist = self.service_router_has_vpnaas(context, router_id)
lb_exist = False
vlan_interfaces = []
if not (fw_exist or snat_exist or vpn_exist):
lb_exist = self.service_router_has_loadbalancers(
context, router_id)
return snat_exist or lb_exist or fw_exist or vpn_exist
vlan_interfaces = self._get_router_vlan_interfaces(
context.elevated(), router_id)
if not vlan_interfaces:
lb_exist = self.service_router_has_loadbalancers(
context, router_id)
return (snat_exist or lb_exist or fw_exist or vpn_exist or
vlan_interfaces)
def service_router_has_loadbalancers(self, context, router_id):
tags_to_search = [{'scope': lb_const.LR_ROUTER_TYPE, 'tag': router_id}]
@ -2956,6 +2973,12 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
ip_addresses=[rtr_subnet['gateway_ip']],
prefix_len=prefix_len))
# Service router is mandatory for VLAN interfaces
if not self.verify_sr_at_backend(router_id):
self.create_service_router(
context, router_id, router=router_db,
update_firewall=False)
ndra_profile_id = self._get_subnet_ndra_profile(subnet)
self.nsxpolicy.tier1.add_segment_interface(
router_id, segment_id,
@ -3063,6 +3086,10 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
self.nsxpolicy.tier1.remove_segment_interface(
router_id, segment_id)
if not self._core_plugin.service_router_has_services(
context.elevated(), router_id):
self.delete_service_router(router_id)
# try to delete the SNAT/NO_DNAT rules of this subnet
router_db = self._get_router(context, router_id)
if (subnet and router_db.gw_port and router_db.enable_snat and

View File

@ -2615,6 +2615,78 @@ class NsxPTestL3NatTestCase(NsxPTestL3NatTest,
nsx_plugin.STATELESS_DHCP_NDRA_PROFILE_ID,
sub2_ipversion=4)
def _add_external_gateway_to_router(self, router_id, network_id,
expected_code=exc.HTTPOk.code,
neutron_context=None, ext_ips=None,
**kwargs):
# Copy the neutron api to add support for disabled SNAT
ext_ips = ext_ips or []
body = {'router':
{'external_gateway_info': {'network_id': network_id}}}
if ext_ips:
body['router']['external_gateway_info'][
'external_fixed_ips'] = ext_ips
if 'policy_id' in kwargs:
body['router']['external_gateway_info'][
'qos_policy_id'] = kwargs.get('policy_id')
if 'enable_snat' in kwargs:
body['router']['external_gateway_info'][
'enable_snat'] = kwargs.get('enable_snat')
return self._update('routers', router_id, body,
expected_code=expected_code,
neutron_context=neutron_context)
def test_router_vlan_interface_sr(self):
providernet_args = {pnet.NETWORK_TYPE: 'vlan',
pnet.SEGMENTATION_ID: 11}
with mock.patch('vmware_nsxlib.v3.policy.core_resources.'
'NsxPolicyTransportZoneApi.get_transport_type',
return_value=nsx_constants.TRANSPORT_TYPE_VLAN), \
self.network(name='vlan_net',
providernet_args=providernet_args,
arg_list=(pnet.NETWORK_TYPE,
pnet.SEGMENTATION_ID)) as net,\
self.router() as r,\
self.subnet(cidr='2001::/64', network=net,
ip_version=6, enable_dhcp=False,
ipv6_address_mode=None,
ipv6_ra_mode=None) as if_subnet,\
self._create_l3_ext_network() as ext_net,\
self.subnet(network=ext_net, cidr='10.0.0.0/16',
enable_dhcp=False) as ext_sub,\
mock.patch("vmware_nsxlib.v3.policy.core_resources."
"NsxPolicyTier1Api.get_edge_cluster_path",
return_value=None),\
mock.patch("vmware_nsxlib.v3.policy.core_resources."
"NsxPolicyTier1Api.get_realized_id"),\
mock.patch("vmware_nsxlib.v3.policy.core_resources."
"NsxPolicyTier1Api.set_edge_cluster_path"
) as add_srv_router,\
mock.patch("vmware_nsxlib.v3.policy.core_resources."
"NsxPolicyTier1Api.remove_edge_cluster"
) as del_srv_router:
# Add router GW
self._add_external_gateway_to_router(
r['router']['id'],
ext_sub['subnet']['network_id'],
enable_snat=False)
# Adding subnet interface
self._router_interface_action(
'add', r['router']['id'],
if_subnet['subnet']['id'], None)
# verify service router was created
add_srv_router.assert_called_once_with(r['router']['id'], mock.ANY)
# Removing subnet interface
self._router_interface_action(
'remove', r['router']['id'],
if_subnet['subnet']['id'], None)
# verify service router was removed
del_srv_router.assert_called_once_with(r['router']['id'])
def _test_router_vlan_interface_ndprofile(self, profile_with,
enable_dhcp=True, mode='slaac'):
providernet_args = {pnet.NETWORK_TYPE: 'vlan',