Merge "NSX-V3 Add NO NAT rules for router interfaces"

This commit is contained in:
Zuul 2018-02-28 10:44:22 +00:00 committed by Gerrit Code Review
commit 49e30433ac
3 changed files with 82 additions and 5 deletions

View File

@ -191,7 +191,8 @@ class NsxPluginBase(db_base_plugin_v2.NeutronDbPluginV2,
subnet = subnet_qry.filter_by(id=ip.subnet_id).one()
subnets.append({'id': subnet.id, 'cidr': subnet.cidr,
'subnetpool_id': subnet.subnetpool_id,
'ip_version': subnet.ip_version})
'ip_version': subnet.ip_version,
'network_id': subnet.network_id})
return subnets
def _find_router_gw_subnets(self, context, router):

View File

@ -118,6 +118,7 @@ from vmware_nsx.services.trunk.nsx_v3 import driver as trunk_driver
from vmware_nsxlib.v3 import core_resources as nsx_resources
from vmware_nsxlib.v3 import exceptions as nsx_lib_exc
from vmware_nsxlib.v3 import nsx_constants as nsxlib_consts
from vmware_nsxlib.v3 import router as nsxlib_router
from vmware_nsxlib.v3 import security
from vmware_nsxlib.v3 import utils as nsxlib_utils
@ -3230,6 +3231,9 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
(newaddr != orgaddr or
not new_enable_snat))
# Remove No-DNAT rules if GW was removed
remove_no_dnat_rules = (orgaddr and not newaddr)
# Revocate bgp announce for nonat subnets if tier0 router link is
# changed or enable_snat is updated from False to True
revocate_bgp_announce = (not org_enable_snat and org_tier0_uuid and
@ -3248,6 +3252,9 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
(newaddr != orgaddr or
not org_enable_snat))
# Add No-DNAT rules if GW was added
add_no_dnat_rules = (newaddr and not orgaddr)
# Bgp announce for nonat subnets if tier0 router link is changed or
# enable_snat is updated from True to False
bgp_announce = (not new_enable_snat and new_tier0_uuid and
@ -3259,11 +3266,18 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
advertise_route_nat_flag = True if new_enable_snat else False
advertise_route_connected_flag = True if not new_enable_snat else False
if add_no_dnat_rules or remove_no_dnat_rules or add_snat_rules:
subnets = self._find_router_subnets(context.elevated(),
router_id)
if revocate_bgp_announce:
# TODO(berlin): revocate bgp announce on org tier0 router
pass
if remove_snat_rules:
self.nsxlib.router.delete_gw_snat_rules(nsx_router_id, orgaddr)
if remove_no_dnat_rules:
for subnet in subnets:
self._del_subnet_no_dnat_rule(context, nsx_router_id, subnet)
if remove_router_link_port:
self.nsxlib.router.remove_router_link_port(
nsx_router_id, org_tier0_uuid)
@ -3283,11 +3297,13 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
# than the gw
gw_address_scope = self._get_network_address_scope(
context, router.gw_port.network_id)
subnets = self._find_router_subnets(context.elevated(),
router_id)
for subnet in subnets:
self._add_subnet_snat_rule(context, router_id, nsx_router_id,
subnet, gw_address_scope, newaddr)
if add_no_dnat_rules:
for subnet in subnets:
self._add_subnet_no_dnat_rule(context, nsx_router_id, subnet)
if bgp_announce:
# TODO(berlin): bgp announce on new tier0 router
pass
@ -3316,6 +3332,21 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
source_net=subnet['cidr'],
bypass_firewall=False)
def _add_subnet_no_dnat_rule(self, context, nsx_router_id, subnet):
# Add NO-DNAT rule to allow internal traffic between VMs, even if
# they have floating ips
self.nsxlib.logical_router.add_nat_rule(
nsx_router_id, "NO_DNAT", None,
dest_net=subnet['cidr'],
rule_priority=nsxlib_router.GW_NAT_PRI)
def _del_subnet_no_dnat_rule(self, context, nsx_router_id, subnet):
# Delete the previously created NO-DNAT rules
self.nsxlib.logical_router.delete_nat_rule_by_values(
nsx_router_id,
action="NO_DNAT",
match_destination_network=subnet['cidr'])
def _process_extra_attr_router_create(self, context, router_db, r):
for extra_attr in l3_attrs_db.get_attr_info().keys():
if (extra_attr in r and
@ -3881,7 +3912,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
nsx_rpc.handle_router_metadata_access(self, context, router_id,
interface=info)
# add the SNAT rule for this interface
# add the SNAT/NO_DNAT rules for this interface
if (router_db.enable_snat and gw_network_id and
router_db.gw_port.get('fixed_ips')):
gw_ip = router_db.gw_port['fixed_ips'][0]['ip_address']
@ -3889,6 +3920,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
context, gw_network_id)
self._add_subnet_snat_rule(context, router_id, nsx_router_id,
subnet, gw_address_scope, gw_ip)
if gw_network_id:
self._add_subnet_no_dnat_rule(context, nsx_router_id, subnet)
# update firewall rules
self.update_router_firewall(context, router_id)
except Exception:
@ -3961,13 +3994,15 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
else:
self.nsxlib.logical_router_port.delete_by_lswitch_id(
nsx_net_id)
# try to delete the SNAT rule of this subnet
# try to delete the SNAT/NO_DNAT rules of this subnet
if (router_db.gw_port and router_db.enable_snat and
router_db.gw_port.get('fixed_ips')):
gw_ip = router_db.gw_port['fixed_ips'][0]['ip_address']
self.nsxlib.router.delete_gw_snat_rule_by_source(
nsx_router_id, gw_ip, subnet['cidr'],
skip_not_found=True)
if router_db.gw_port:
self._del_subnet_no_dnat_rule(context, nsx_router_id, subnet)
except nsx_lib_exc.ResourceNotFound:
LOG.error("router port on router %(router_id)s for net "

View File

@ -1319,6 +1319,47 @@ class TestL3NatTestCase(L3NatTest,
gw_info = body['router']['external_gateway_info']
self.assertIsNone(gw_info)
def test_router_on_vlan_net(self):
providernet_args = {pnet.NETWORK_TYPE: 'vlan',
pnet.SEGMENTATION_ID: 10}
with mock.patch('vmware_nsxlib.v3.core_resources.NsxLibTransportZone.'
'get_transport_type', return_value='VLAN'):
result = self._create_network(fmt='json', name='badvlan_net',
admin_state_up=True,
providernet_args=providernet_args,
arg_list=(
pnet.NETWORK_TYPE,
pnet.SEGMENTATION_ID))
vlan_network = self.deserialize('json', result)
with self.router() as r1,\
self.subnet() as ext_subnet,\
self.subnet(cidr='11.0.0.0/24', network=vlan_network) as s1:
self._set_net_external(ext_subnet['subnet']['network_id'])
# adding a vlan interface with no GW should fail
self._router_interface_action(
'add', r1['router']['id'],
s1['subnet']['id'], None,
expected_code=400)
# adding GW
self._add_external_gateway_to_router(
r1['router']['id'],
ext_subnet['subnet']['network_id'])
# adding the vlan interface
self._router_interface_action(
'add', r1['router']['id'],
s1['subnet']['id'], None)
# adding a floating ip
with self.port(subnet=s1) as p:
fip_res = self._create_floatingip(
self.fmt,
ext_subnet['subnet']['network_id'],
subnet_id=ext_subnet['subnet']['id'],
port_id=p['port']['id'])
fip = self.deserialize(self.fmt, fip_res)
self.assertEqual(p['port']['id'],
fip['floatingip']['port_id'])
def test_create_router_gateway_fails(self):
self.skipTest('not supported')