NSX|V: Add allow icmp6 multicast rules in edge firewall

Vsphere7 started to block this traffic so adding those rules to be
backwards compatible.
In addition, add admin utility to fix existing edge firewalls:
nsxadmin -r routers -o nsx-update-fw

Change-Id: Ia5c2832e377a1a17ef279191ee91b6fec8f65443
This commit is contained in:
asarfaty 2020-07-07 14:05:15 +02:00 committed by Adit Sarfaty
parent 44206cac04
commit 0520483e2c
9 changed files with 92 additions and 3 deletions

View File

@ -186,6 +186,10 @@ Routers
nsxadmin -r routers -o migrate-vdr-dhcp nsxadmin -r routers -o migrate-vdr-dhcp
- Recreate the rules in the edge firewall of all routers
nsxadmin -r routers -o nsx-update-fw
Networks Networks
~~~~~~~~ ~~~~~~~~

View File

@ -331,6 +331,9 @@ class RouterSharedDriver(router_driver.RouterBaseDriver):
if self.plugin.metadata_proxy_handler: if self.plugin.metadata_proxy_handler:
fw_rules += nsx_v_md_proxy.get_router_fw_rules() fw_rules += nsx_v_md_proxy.get_router_fw_rules()
# Add ipv6 icmp multicast rule (blocked in Vsphere 7 & up)
fw_rules.extend(self.plugin._get_firewall_icmpv6_rules())
# TODO(asarfaty): Add fwaas rules when fwaas supports shared routers # TODO(asarfaty): Add fwaas rules when fwaas supports shared routers
fw = {'firewall_rule_list': fw_rules} fw = {'firewall_rule_list': fw_rules}
edge_utils.update_firewall(self.nsx_v, context, target_router_id, edge_utils.update_firewall(self.nsx_v, context, target_router_id,

View File

@ -4255,6 +4255,16 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
self.update_router_firewall(context, router_id, router_db) self.update_router_firewall(context, router_id, router_db)
def _get_firewall_icmpv6_rules(self):
# Add ipv6 icmp multicast rule (blocked in Vsphere 7 & up)
application_ids = self.nsx_v.get_icmpv6_multicast_application_ids()
rules = [{
'name': 'IPV6-ICMP-multicast',
'action': 'allow',
'enabled': True,
'application': {'applicationId': application_ids}}]
return rules
def update_router_firewall(self, context, router_id, router_db): def update_router_firewall(self, context, router_id, router_db):
"""Recreate all rules in the router edge firewall """Recreate all rules in the router edge firewall
@ -4280,6 +4290,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
if subnet_rules: if subnet_rules:
fw_rules.extend(subnet_rules) fw_rules.extend(subnet_rules)
# Add ipv6 icmp multicast rule (blocked in Vsphere 7 & up)
fw_rules.extend(self._get_firewall_icmpv6_rules())
# If metadata service is enabled, block access to inter-edge network # If metadata service is enabled, block access to inter-edge network
if self.metadata_proxy_handler and not distributed: if self.metadata_proxy_handler and not distributed:
fw_rules += nsx_v_md_proxy.get_router_fw_rules() fw_rules += nsx_v_md_proxy.get_router_fw_rules()

View File

@ -40,6 +40,7 @@ class EdgeFirewallDriver(object):
def __init__(self): def __init__(self):
super(EdgeFirewallDriver, self).__init__() super(EdgeFirewallDriver, self).__init__()
self._icmp_echo_application_ids = None self._icmp_echo_application_ids = None
self._icmpv6_multicast_application_ids = None
def _convert_firewall_action(self, action): def _convert_firewall_action(self, action):
if action == FWAAS_ALLOW: if action == FWAAS_ALLOW:
@ -429,6 +430,20 @@ class EdgeFirewallDriver(object):
res_name='ICMP Echo', res_id='') res_name='ICMP Echo', res_id='')
return self._icmp_echo_application_ids return self._icmp_echo_application_ids
def get_icmpv6_multicast_application_ids(self):
# check cached list first
# (if backend version changes, neutron should be restarted)
if self._icmpv6_multicast_application_ids:
return self._icmpv6_multicast_application_ids
self._icmpv6_multicast_application_ids = self.get_application_ids(
['IPv6-ICMP Version 2 Multicast Listener',
'IPv6-ICMP Multicast Listener Query'])
if not self._icmpv6_multicast_application_ids:
raise nsx_exc.NsxResourceNotFound(
res_name='ICMPv6 Multicast', res_id='')
return self._icmpv6_multicast_application_ids
def get_application_ids(self, application_names): def get_application_ids(self, application_names):
results = self.vcns.list_applications() results = self.vcns.list_applications()
application_ids = [] application_ids = []

View File

@ -224,6 +224,43 @@ def migrate_distributed_routers_dhcp(resource, event, trigger, **kwargs):
_update_vdr_fw_config(nsxv, binding['edge_id']) _update_vdr_fw_config(nsxv, binding['edge_id'])
@admin_utils.output_header
def update_edge_firewalls(resource, event, trigger, **kwargs):
context = n_context.get_admin_context()
updated_routers = []
with utils.NsxVPluginWrapper() as plugin:
shared_dr = plugin._router_managers.get_tenant_router_driver(
context, 'shared')
routers = plugin.get_routers(context)
for router in routers:
if router['id'] in updated_routers:
continue
if router.get('distributed', False):
# Distributes firewall - Update plr and tlr
router_db = plugin._get_router(context, router['id'])
plugin._update_subnets_and_dnat_firewall(context, router_db)
plr_id = plugin.edge_manager.get_plr_by_tlr_id(
context, router['id'])
if plr_id:
plugin._update_subnets_and_dnat_firewall(
context, router, router_id=plr_id)
updated_routers.append(router['id'])
elif router.get('router_type') == 'shared':
# Shared router
router_ids = shared_dr.edge_manager.get_routers_on_same_edge(
context, router['id'])
shared_dr._update_subnets_and_dnat_firewall_on_routers(
context, router['id'], router_ids)
updated_routers.extend(router_ids)
else:
# Exclusive router
router_db = plugin._get_router(context, router['id'])
plugin._update_subnets_and_dnat_firewall(context, router_db)
updated_routers.append(router['id'])
LOG.info("Updated edge firewall rules for routers: %s", updated_routers)
def _update_vdr_fw_config(nsxv, edge_id): def _update_vdr_fw_config(nsxv, edge_id):
fw_config = nsxv.get_firewall(edge_id)[1] fw_config = nsxv.get_firewall(edge_id)[1]
@ -374,6 +411,10 @@ registry.subscribe(redistribute_routers,
constants.ROUTERS, constants.ROUTERS,
shell.Operations.NSX_REDISTRIBURE.value) shell.Operations.NSX_REDISTRIBURE.value)
registry.subscribe(update_edge_firewalls,
constants.ROUTERS,
shell.Operations.NSX_UPDATE_FW.value)
registry.subscribe(list_orphaned_vnics, registry.subscribe(list_orphaned_vnics,
constants.ORPHANED_VNICS, constants.ORPHANED_VNICS,
shell.Operations.NSX_LIST.value) shell.Operations.NSX_LIST.value)

View File

@ -56,6 +56,7 @@ class Operations(enum.Enum):
NSX_ENABLE_STANDBY_RELOCATION = 'nsx-enable-standby-relocation' NSX_ENABLE_STANDBY_RELOCATION = 'nsx-enable-standby-relocation'
NSX_UPDATE_IP = 'nsx-update-ip' NSX_UPDATE_IP = 'nsx-update-ip'
NSX_UPDATE_TAGS = 'nsx-update-tags' NSX_UPDATE_TAGS = 'nsx-update-tags'
NSX_UPDATE_FW = 'nsx-update-fw'
NSX_RECREATE = 'nsx-recreate' NSX_RECREATE = 'nsx-recreate'
NSX_REDISTRIBURE = 'nsx-redistribute' NSX_REDISTRIBURE = 'nsx-redistribute'
NSX_REORDER = 'nsx-reorder' NSX_REORDER = 'nsx-reorder'
@ -234,7 +235,8 @@ nsxv_resources = {
constants.ROUTERS: Resource(constants.ROUTERS, constants.ROUTERS: Resource(constants.ROUTERS,
[Operations.NSX_RECREATE.value, [Operations.NSX_RECREATE.value,
Operations.NSX_REDISTRIBURE.value, Operations.NSX_REDISTRIBURE.value,
Operations.MIGRATE_VDR_DHCP.value]), Operations.MIGRATE_VDR_DHCP.value,
Operations.NSX_UPDATE_FW.value]),
constants.ORPHANED_VNICS: Resource(constants.ORPHANED_VNICS, constants.ORPHANED_VNICS: Resource(constants.ORPHANED_VNICS,
[Operations.NSX_LIST.value, [Operations.NSX_LIST.value,
Operations.NSX_CLEAN.value]), Operations.NSX_CLEAN.value]),

View File

@ -67,6 +67,8 @@ class NsxvFwaasTestCase(test_v_plugin.NsxVPluginV2TestCase):
return_value=self.port).start() return_value=self.port).start()
mock.patch.object(self.plugin, '_get_subnet_fw_rules', mock.patch.object(self.plugin, '_get_subnet_fw_rules',
return_value=[]).start() return_value=[]).start()
mock.patch.object(self.plugin, '_get_firewall_icmpv6_rules',
return_value=[]).start()
mock.patch.object(self.plugin, '_get_dnat_fw_rule', mock.patch.object(self.plugin, '_get_dnat_fw_rule',
return_value=[]).start() return_value=[]).start()
mock.patch.object(self.plugin, '_get_allocation_pools_fw_rule', mock.patch.object(self.plugin, '_get_allocation_pools_fw_rule',

View File

@ -2506,6 +2506,11 @@ class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxVPluginV2TestCase):
class L3NatTestCaseBase(test_l3_plugin.L3NatTestCaseMixin): class L3NatTestCaseBase(test_l3_plugin.L3NatTestCaseMixin):
def setUp(self, **kwargs):
super(L3NatTestCaseBase, self).setUp(**kwargs)
mock.patch.object(self.plugin, '_get_firewall_icmpv6_rules',
return_value=[]).start()
def test_create_floatingip_with_specific_ip(self): def test_create_floatingip_with_specific_ip(self):
with self.subnet(cidr='10.0.0.0/24', with self.subnet(cidr='10.0.0.0/24',
enable_dhcp=False) as s: enable_dhcp=False) as s:

View File

@ -1467,9 +1467,13 @@ class FakeVcns(object):
return {'policies': policies} return {'policies': policies}
def list_applications(self): def list_applications(self):
applications = [{'name': 'ICMP Echo', 'objectID': 'application-333'}, applications = [{'name': 'ICMP Echo', 'objectId': 'application-333'},
{'name': 'IPv6-ICMP Echo', {'name': 'IPv6-ICMP Echo',
'objectID': 'application-1001'}] 'objectId': 'application-1001'},
{'name': 'IPv6-ICMP Version 2 Multicast Listener',
'objectId': 'application-3'},
{'name': 'IPv6-ICMP Multicast Listener Query',
'objectId': 'application-4'}]
return applications return applications