From 2defc5e7acc39086310c195b7a631e46d73b5e01 Mon Sep 17 00:00:00 2001 From: asarfaty Date: Tue, 7 Jul 2020 14:05:15 +0200 Subject: [PATCH] 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 --- doc/source/admin_util.rst | 4 ++ .../nsx_v/drivers/shared_router_driver.py | 3 ++ vmware_nsx/plugins/nsx_v/plugin.py | 13 ++++++ .../nsx_v/vshield/edge_firewall_driver.py | 15 +++++++ .../admin/plugins/nsxv/resources/routers.py | 41 +++++++++++++++++++ vmware_nsx/shell/resources.py | 4 +- .../tests/unit/nsx_v/test_fwaas_v2_driver.py | 2 + vmware_nsx/tests/unit/nsx_v/test_plugin.py | 5 +++ .../tests/unit/nsx_v/vshield/fake_vcns.py | 8 +++- 9 files changed, 92 insertions(+), 3 deletions(-) diff --git a/doc/source/admin_util.rst b/doc/source/admin_util.rst index 2c4a35ec19..3e64521218 100644 --- a/doc/source/admin_util.rst +++ b/doc/source/admin_util.rst @@ -186,6 +186,10 @@ Routers 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 ~~~~~~~~ diff --git a/vmware_nsx/plugins/nsx_v/drivers/shared_router_driver.py b/vmware_nsx/plugins/nsx_v/drivers/shared_router_driver.py index e354c718f1..4ba4c31964 100644 --- a/vmware_nsx/plugins/nsx_v/drivers/shared_router_driver.py +++ b/vmware_nsx/plugins/nsx_v/drivers/shared_router_driver.py @@ -331,6 +331,9 @@ class RouterSharedDriver(router_driver.RouterBaseDriver): if self.plugin.metadata_proxy_handler: 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 fw = {'firewall_rule_list': fw_rules} edge_utils.update_firewall(self.nsx_v, context, target_router_id, diff --git a/vmware_nsx/plugins/nsx_v/plugin.py b/vmware_nsx/plugins/nsx_v/plugin.py index 112e5348e8..60adedac60 100644 --- a/vmware_nsx/plugins/nsx_v/plugin.py +++ b/vmware_nsx/plugins/nsx_v/plugin.py @@ -4255,6 +4255,16 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin, 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): """Recreate all rules in the router edge firewall @@ -4280,6 +4290,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin, if 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 self.metadata_proxy_handler and not distributed: fw_rules += nsx_v_md_proxy.get_router_fw_rules() diff --git a/vmware_nsx/plugins/nsx_v/vshield/edge_firewall_driver.py b/vmware_nsx/plugins/nsx_v/vshield/edge_firewall_driver.py index b9d7414f2b..d916548ea9 100644 --- a/vmware_nsx/plugins/nsx_v/vshield/edge_firewall_driver.py +++ b/vmware_nsx/plugins/nsx_v/vshield/edge_firewall_driver.py @@ -40,6 +40,7 @@ class EdgeFirewallDriver(object): def __init__(self): super(EdgeFirewallDriver, self).__init__() self._icmp_echo_application_ids = None + self._icmpv6_multicast_application_ids = None def _convert_firewall_action(self, action): if action == FWAAS_ALLOW: @@ -429,6 +430,20 @@ class EdgeFirewallDriver(object): res_name='ICMP Echo', res_id='') 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): results = self.vcns.list_applications() application_ids = [] diff --git a/vmware_nsx/shell/admin/plugins/nsxv/resources/routers.py b/vmware_nsx/shell/admin/plugins/nsxv/resources/routers.py index 0a7e286222..efb4740caf 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv/resources/routers.py +++ b/vmware_nsx/shell/admin/plugins/nsxv/resources/routers.py @@ -224,6 +224,43 @@ def migrate_distributed_routers_dhcp(resource, event, trigger, **kwargs): _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): fw_config = nsxv.get_firewall(edge_id)[1] @@ -374,6 +411,10 @@ registry.subscribe(redistribute_routers, constants.ROUTERS, shell.Operations.NSX_REDISTRIBURE.value) +registry.subscribe(update_edge_firewalls, + constants.ROUTERS, + shell.Operations.NSX_UPDATE_FW.value) + registry.subscribe(list_orphaned_vnics, constants.ORPHANED_VNICS, shell.Operations.NSX_LIST.value) diff --git a/vmware_nsx/shell/resources.py b/vmware_nsx/shell/resources.py index 9ddbe56fae..51737020bf 100644 --- a/vmware_nsx/shell/resources.py +++ b/vmware_nsx/shell/resources.py @@ -56,6 +56,7 @@ class Operations(enum.Enum): NSX_ENABLE_STANDBY_RELOCATION = 'nsx-enable-standby-relocation' NSX_UPDATE_IP = 'nsx-update-ip' NSX_UPDATE_TAGS = 'nsx-update-tags' + NSX_UPDATE_FW = 'nsx-update-fw' NSX_RECREATE = 'nsx-recreate' NSX_REDISTRIBURE = 'nsx-redistribute' NSX_REORDER = 'nsx-reorder' @@ -229,7 +230,8 @@ nsxv_resources = { constants.ROUTERS: Resource(constants.ROUTERS, [Operations.NSX_RECREATE.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, [Operations.NSX_LIST.value, Operations.NSX_CLEAN.value]), diff --git a/vmware_nsx/tests/unit/nsx_v/test_fwaas_v2_driver.py b/vmware_nsx/tests/unit/nsx_v/test_fwaas_v2_driver.py index b89fd1fc56..128f5b5524 100644 --- a/vmware_nsx/tests/unit/nsx_v/test_fwaas_v2_driver.py +++ b/vmware_nsx/tests/unit/nsx_v/test_fwaas_v2_driver.py @@ -67,6 +67,8 @@ class NsxvFwaasTestCase(test_v_plugin.NsxVPluginV2TestCase): return_value=self.port).start() mock.patch.object(self.plugin, '_get_subnet_fw_rules', return_value=[]).start() + mock.patch.object(self.plugin, '_get_firewall_icmpv6_rules', + return_value=[]).start() mock.patch.object(self.plugin, '_get_dnat_fw_rule', return_value=[]).start() mock.patch.object(self.plugin, '_get_allocation_pools_fw_rule', diff --git a/vmware_nsx/tests/unit/nsx_v/test_plugin.py b/vmware_nsx/tests/unit/nsx_v/test_plugin.py index e0ca78572e..c5ed58ce6f 100644 --- a/vmware_nsx/tests/unit/nsx_v/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v/test_plugin.py @@ -2510,6 +2510,11 @@ class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxVPluginV2TestCase): 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): with self.subnet(cidr='10.0.0.0/24', enable_dhcp=False) as s: diff --git a/vmware_nsx/tests/unit/nsx_v/vshield/fake_vcns.py b/vmware_nsx/tests/unit/nsx_v/vshield/fake_vcns.py index 9eed5eafab..09789cc7d4 100644 --- a/vmware_nsx/tests/unit/nsx_v/vshield/fake_vcns.py +++ b/vmware_nsx/tests/unit/nsx_v/vshield/fake_vcns.py @@ -1467,9 +1467,13 @@ class FakeVcns(object): return {'policies': policies} def list_applications(self): - applications = [{'name': 'ICMP Echo', 'objectID': 'application-333'}, + applications = [{'name': 'ICMP Echo', 'objectId': 'application-333'}, {'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