From 0520483e2ceff6f667721b363b4ff5f2a44090cb 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 18e79e718c..c6f8ae30b4 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 aa3feb874b..473d2e5e03 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' @@ -234,7 +235,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 75bda89651..378a95f7a7 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 24ac1c4fbb..2389421094 100644 --- a/vmware_nsx/tests/unit/nsx_v/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v/test_plugin.py @@ -2506,6 +2506,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