From 769782be844e4c74fdc0aad0ff704b06c874c3ad Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 20 May 2013 09:39:59 -0700 Subject: Don't snat all traffic when force_snat_range set When using /proc/sys/net/bridge/bridge-nf-call-iptables=1, bridged traffic gets snatted even though it is being bridged out to an external gateway. This can lead to asymmetric routes where traffic goes out the fixed network and comes back on the float network and can lead to packets being blocked by firewalls. Work around this problem by only fallback snatting when the traffic is going to one of the force_snat_ranges. If force_snat_range is not set it defaults to the existing behavior of snatting all traffic that doesn't hit an earlier rule. Fixes bug 1182143 Change-Id: If496dad2308a68a6a4a9fd43d695943bc5034ac4 --- nova/network/linux_net.py | 11 ++++++----- nova/tests/network/test_linux_net.py | 22 ++++++++++++++++++++++ nova/tests/network/test_manager.py | 18 +++++++++++------- 3 files changed, 39 insertions(+), 12 deletions(-) (limited to 'nova') diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index c47b50060..9156c3306 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -628,11 +628,12 @@ def metadata_accept(): def add_snat_rule(ip_range): if CONF.routing_source_ip: - rule = '-s %s -j SNAT --to-source %s' % (ip_range, - CONF.routing_source_ip) - if CONF.public_interface: - rule += ' -o %s' % CONF.public_interface - iptables_manager.ipv4['nat'].add_rule('snat', rule) + for dest_range in CONF.force_snat_range or ['0.0.0.0/0']: + rule = ('-s %s -d %s -j SNAT --to-source %s' + % (ip_range, dest_range, CONF.routing_source_ip)) + if CONF.public_interface: + rule += ' -o %s' % CONF.public_interface + iptables_manager.ipv4['nat'].add_rule('snat', rule) iptables_manager.apply() diff --git a/nova/tests/network/test_linux_net.py b/nova/tests/network/test_linux_net.py index 4829f2d93..e9542a648 100644 --- a/nova/tests/network/test_linux_net.py +++ b/nova/tests/network/test_linux_net.py @@ -242,6 +242,28 @@ class LinuxNetworkTestCase(test.TestCase): self.stubs.Set(db, 'instance_get', get_instance) self.stubs.Set(db, 'network_get_associated_fixed_ips', get_associated) + def _test_add_snat_rule(self, expected): + def verify_add_rule(chain, rule): + self.assertEqual(chain, 'snat') + self.assertEqual(rule, expected) + + self.stubs.Set(linux_net.iptables_manager.ipv4['nat'], + 'add_rule', verify_add_rule) + linux_net.add_snat_rule('10.0.0.0/24') + + def test_add_snat_rule(self): + self.flags(routing_source_ip='10.10.10.1') + expected = ('-s 10.0.0.0/24 -d 0.0.0.0/0 ' + '-j SNAT --to-source 10.10.10.1 -o eth0') + self._test_add_snat_rule(expected) + + def test_add_snat_rule_snat_range(self): + self.flags(routing_source_ip='10.10.10.1', + force_snat_range=['10.10.10.0/24']) + expected = ('-s 10.0.0.0/24 -d 10.10.10.0/24 ' + '-j SNAT --to-source 10.10.10.1 -o eth0') + self._test_add_snat_rule(expected) + def test_update_dhcp_for_nw00(self): self.flags(use_single_default_gateway=True) diff --git a/nova/tests/network/test_manager.py b/nova/tests/network/test_manager.py index b8f75233a..1fa578aaf 100644 --- a/nova/tests/network/test_manager.py +++ b/nova/tests/network/test_manager.py @@ -1710,7 +1710,8 @@ class CommonNetworkTestCase(test.TestCase): table_name='nat') # The expected rules that should be configured based on the fixed_range - expected_lines = ['[0:0] -A %s-snat -s %s -j SNAT --to-source %s -o %s' + expected_lines = ['[0:0] -A %s-snat -s %s -d 0.0.0.0/0 ' + '-j SNAT --to-source %s -o %s' % (binary_name, CONF.fixed_range, CONF.routing_source_ip, CONF.public_interface), @@ -1758,7 +1759,8 @@ class CommonNetworkTestCase(test.TestCase): table_name='nat') # The expected rules that should be configured based on the fixed_range - expected_lines = ['[0:0] -A %s-snat -s %s -j SNAT --to-source %s -o %s' + expected_lines = ['[0:0] -A %s-snat -s %s -d 0.0.0.0/0 ' + '-j SNAT --to-source %s -o %s' % (binary_name, networks[0]['cidr'], CONF.routing_source_ip, CONF.public_interface), @@ -1772,7 +1774,8 @@ class CommonNetworkTestCase(test.TestCase): '--ctstate DNAT -j ACCEPT' % (binary_name, networks[0]['cidr'], networks[0]['cidr']), - '[0:0] -A %s-snat -s %s -j SNAT --to-source %s -o %s' + '[0:0] -A %s-snat -s %s -d 0.0.0.0/0 ' + '-j SNAT --to-source %s -o %s' % (binary_name, networks[1]['cidr'], CONF.routing_source_ip, CONF.public_interface), @@ -1826,10 +1829,11 @@ class CommonNetworkTestCase(test.TestCase): table_name='nat') # Add the new expected rules to the old ones - expected_lines += ['[0:0] -A %s-snat -s %s -j SNAT --to-source %s -o ' - '%s' % (binary_name, new_network['cidr'], - CONF.routing_source_ip, - CONF.public_interface), + expected_lines += ['[0:0] -A %s-snat -s %s -d 0.0.0.0/0 ' + '-j SNAT --to-source %s -o %s' + % (binary_name, new_network['cidr'], + CONF.routing_source_ip, + CONF.public_interface), '[0:0] -A %s-POSTROUTING -s %s -d %s/32 -j ACCEPT' % (binary_name, new_network['cidr'], CONF.metadata_host), -- cgit