From e9e8f5dccbc43ab3e07ec285a24489fdb9ac6c80 Mon Sep 17 00:00:00 2001 From: Jakub Libosvar Date: Tue, 13 Jun 2017 12:03:31 +0000 Subject: [PATCH] Introduce trusted ports to firewall driver API Currently trusted ports (DHCP & router ports) are considered trusted ports based on theirs owner. Trusted ports are not passed to the firewall driver and hence the driver doesn't have any way how to deal with such ports. This change introduces two new methods to firewall driver API: - process_trusted_ports - remove_trusted_ports These methods will give firewall driver a chance to process traffic coming from the trusted ports in case its needed. For specific case, see patch depending on this one. Change-Id: I0be64483515e45f98ffffce8346a6bff06bc0fd1 Related-bug: #1626010 --- neutron/agent/firewall.py | 7 +++ neutron/agent/securitygroups_rpc.py | 9 ++-- .../unit/agent/test_securitygroups_rpc.py | 53 ++++++++++++++++--- 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/neutron/agent/firewall.py b/neutron/agent/firewall.py index 1f3e18961eb..424ed64d923 100644 --- a/neutron/agent/firewall.py +++ b/neutron/agent/firewall.py @@ -162,6 +162,13 @@ class FirewallDriver(object): """ raise NotImplementedError() + def process_trusted_ports(self, port_ids): + """Process ports that are trusted and shouldn't be filtered.""" + pass + + def remove_trusted_ports(self, port_ids): + pass + class NoopFirewallDriver(FirewallDriver): """Noop Firewall Driver. diff --git a/neutron/agent/securitygroups_rpc.py b/neutron/agent/securitygroups_rpc.py index f0d4953d3d9..21df1ddea5b 100644 --- a/neutron/agent/securitygroups_rpc.py +++ b/neutron/agent/securitygroups_rpc.py @@ -128,6 +128,7 @@ class SecurityGroupAgentRpc(object): else: devices = self.plugin_rpc.security_group_rules_for_devices( self.context, list(device_ids)) + trusted_devices = list(set(device_ids) - set(devices.keys())) with self.firewall.defer_apply(): if self.use_enhanced_rpc: @@ -142,6 +143,7 @@ class SecurityGroupAgentRpc(object): else: LOG.debug("Prepare port filter for %s", device['device']) self.firewall.prepare_port_filter(device) + self.firewall.process_trusted_ports(trusted_devices) def _update_security_group_info(self, security_groups, security_group_member_ips): @@ -213,9 +215,10 @@ class SecurityGroupAgentRpc(object): with self.firewall.defer_apply(): for device_id in device_ids: device = self.firewall.ports.get(device_id) - if not device: - continue - self.firewall.remove_port_filter(device) + if device: + self.firewall.remove_port_filter(device) + else: + self.firewall.remove_trusted_ports([device_id]) @skip_if_noopfirewall_or_firewall_disabled def refresh_firewall(self, device_ids=None): diff --git a/neutron/tests/unit/agent/test_securitygroups_rpc.py b/neutron/tests/unit/agent/test_securitygroups_rpc.py index 1c42999c62d..b234757311d 100644 --- a/neutron/tests/unit/agent/test_securitygroups_rpc.py +++ b/neutron/tests/unit/agent/test_securitygroups_rpc.py @@ -871,6 +871,7 @@ class SecurityGroupAgentRpcTestCase(BaseSecurityGroupAgentRpcTestCase): self.firewall.assert_has_calls([mock.call.defer_apply(), mock.call.prepare_port_filter( self.fake_device), + mock.call.process_trusted_ports([]), mock.call.defer_apply(), mock.call.remove_port_filter( self.fake_device), @@ -896,6 +897,35 @@ class SecurityGroupAgentRpcTestCase(BaseSecurityGroupAgentRpcTestCase): self.assertFalse(self.agent.plugin_rpc. security_group_rules_for_devices.called) + def test_prepare_devices_filter_with_trusted_ports(self): + devices_to_filter = {k: {'device': k} for k in range(4, 8)} + all_devices = range(10) + expected_devices = [0, 1, 2, 3, 8, 9] + self.agent._use_enhanced_rpc = True + with mock.patch.object( + self.agent.plugin_rpc, + 'security_group_info_for_devices', + return_value={ + 'devices': devices_to_filter, + 'security_groups': {}, + 'sg_member_ips': {}}): + with mock.patch.object( + self.agent.firewall, 'process_trusted_ports') as m_process: + self.agent.prepare_devices_filter(all_devices) + m_process.assert_called_once_with(expected_devices) + + def test_remove_devices_filter_with_trusted_ports(self): + all_devices = range(10) + firewall_managed_ports = {k: k for k in range(4, 8)} + trusted_port_ids = [0, 1, 2, 3, 8, 9] + with mock.patch.object(self.agent, 'firewall') as mock_firewall: + mock_firewall.ports = firewall_managed_ports + self.agent.remove_devices_filter(all_devices) + mock_firewall.remove_port_filter.assert_has_calls( + [mock.call(i) for i in firewall_managed_ports.keys()]) + mock_firewall.remove_trusted_ports( + [mock.call([i]) for i in trusted_port_ids]) + def test_security_groups_rule_updated(self): self.agent.refresh_firewall = mock.Mock() self.agent.prepare_devices_filter(['fake_port_id']) @@ -937,17 +967,21 @@ class SecurityGroupAgentRpcTestCase(BaseSecurityGroupAgentRpcTestCase): self.agent.refresh_firewall() calls = [mock.call.defer_apply(), mock.call.prepare_port_filter(self.fake_device), + mock.call.process_trusted_ports(['fake_port_id']), mock.call.defer_apply(), - mock.call.update_port_filter(self.fake_device)] + mock.call.update_port_filter(self.fake_device), + mock.call.process_trusted_ports([])] self.firewall.assert_has_calls(calls) def test_refresh_firewall_devices(self): self.agent.prepare_devices_filter(['fake_port_id']) - self.agent.refresh_firewall([self.fake_device]) + self.agent.refresh_firewall([self.fake_device['device']]) calls = [mock.call.defer_apply(), mock.call.prepare_port_filter(self.fake_device), + mock.call.process_trusted_ports(['fake_port_id']), mock.call.defer_apply(), - mock.call.update_port_filter(self.fake_device)] + mock.call.update_port_filter(self.fake_device), + mock.call.process_trusted_ports([])] self.firewall.assert_has_calls(calls) def test_refresh_firewall_none(self): @@ -959,7 +993,7 @@ class SecurityGroupAgentRpcTestCase(BaseSecurityGroupAgentRpcTestCase): self.agent.plugin_rpc.security_group_info_for_devices = mock.Mock() self.agent.plugin_rpc.security_group_rules_for_devices = mock.Mock() self.agent.firewall.defer_apply = mock.Mock() - self.agent.refresh_firewall([self.fake_device]) + self.agent.refresh_firewall([self.fake_device['device']]) self.assertFalse(self.agent.plugin_rpc. security_group_info_for_devices.called) self.assertFalse(self.agent.plugin_rpc. @@ -1010,6 +1044,7 @@ class SecurityGroupAgentEnhancedRpcTestCase( tmp_mock2, mock.call.prepare_port_filter( self.fake_device), + mock.call.process_trusted_ports([]), mock.call.defer_apply(), mock.call.remove_port_filter( self.fake_device), @@ -1066,19 +1101,21 @@ class SecurityGroupAgentEnhancedRpcTestCase( mock.call.update_security_group_members( 'fake_sgid2', {'IPv4': [], 'IPv6': []}), mock.call.prepare_port_filter(self.fake_device), + mock.call.process_trusted_ports(['fake_port_id']), mock.call.defer_apply(), mock.call.update_security_group_rules('fake_sgid2', []), mock.call.update_security_group_rules( 'fake_sgid1', [{'remote_group_id': 'fake_sgid2'}]), mock.call.update_security_group_members( 'fake_sgid2', {'IPv4': [], 'IPv6': []}), - mock.call.update_port_filter(self.fake_device)] + mock.call.update_port_filter(self.fake_device), + mock.call.process_trusted_ports([])] self.firewall.assert_has_calls(calls) def test_refresh_firewall_devices_enhanced_rpc(self): self.agent.prepare_devices_filter(['fake_device']) - self.agent.refresh_firewall([self.fake_device]) + self.agent.refresh_firewall([self.fake_device['device']]) calls = [mock.call.defer_apply(), mock.call.update_security_group_rules('fake_sgid2', []), mock.call.update_security_group_rules('fake_sgid1', [ @@ -1087,13 +1124,15 @@ class SecurityGroupAgentEnhancedRpcTestCase( 'IPv4': [], 'IPv6': [] }), mock.call.prepare_port_filter(self.fake_device), + mock.call.process_trusted_ports([]), mock.call.defer_apply(), mock.call.update_security_group_rules('fake_sgid2', []), mock.call.update_security_group_rules('fake_sgid1', [ {'remote_group_id': 'fake_sgid2'}]), mock.call.update_security_group_members('fake_sgid2', { 'IPv4': [], 'IPv6': []}), - mock.call.update_port_filter(self.fake_device) + mock.call.update_port_filter(self.fake_device), + mock.call.process_trusted_ports([]), ] self.firewall.assert_has_calls(calls)