From 331ba4509f9bbe4033bb0d84e9163d1c95ce3955 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 ec7350f276..3a3d0ea5ef 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 7ed642df1a..6fda8a9f7e 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' @@ -230,7 +231,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 2c555e5aeb..bcae68b321 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