diff options
| author | Adam Gandelman <adam.gandelman@canonical.com> | 2012-12-18 09:50:46 -0800 |
|---|---|---|
| committer | Adam Gandelman <adam.gandelman@canonical.com> | 2012-12-18 17:20:24 -0800 |
| commit | 901a3dacb6f2d36cbe8d23707dba75452e91df33 (patch) | |
| tree | 9f61348e6642d5ea4ecf0e7290b46aedbf414b8d | |
| parent | 30ddc85a1046d8792cb9c2f82033124aebe50d0f (diff) | |
| download | nova-901a3dacb6f2d36cbe8d23707dba75452e91df33.tar.gz nova-901a3dacb6f2d36cbe8d23707dba75452e91df33.tar.xz nova-901a3dacb6f2d36cbe8d23707dba75452e91df33.zip | |
Add an iptables mangle rule per-bridge for DHCP.
When vhost-net is present on a host, and DHCP services are
run on the same system as guests (multi_host), an iptables
rule is needed to fill packet checksums. This adds a rule
per-bridge for multi_host networks when vhost-net is present,
similar to how newer versions of libvirt handle the issue for
bridges/networks that it manages.
Fixes LP: #1029430
EDIT: Updated tests and pep8.
Change-Id: I1a51c1d808fa47a77e713dbfe384ffad183d6031
| -rw-r--r-- | nova/network/linux_net.py | 28 | ||||
| -rw-r--r-- | nova/tests/network/test_linux_net.py | 4 | ||||
| -rw-r--r-- | nova/tests/test_libvirt.py | 16 |
3 files changed, 46 insertions, 2 deletions
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 8b0ae41c3..a1c03bc51 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -290,7 +290,8 @@ class IptablesManager(object): self.execute = execute self.ipv4 = {'filter': IptablesTable(), - 'nat': IptablesTable()} + 'nat': IptablesTable(), + 'mangle': IptablesTable()} self.ipv6 = {'filter': IptablesTable()} self.iptables_apply_deferred = False @@ -311,7 +312,8 @@ class IptablesManager(object): # Wrap the built-in chains builtin_chains = {4: {'filter': ['INPUT', 'OUTPUT', 'FORWARD'], - 'nat': ['PREROUTING', 'OUTPUT', 'POSTROUTING']}, + 'nat': ['PREROUTING', 'OUTPUT', 'POSTROUTING'], + 'mangle': ['POSTROUTING']}, 6: {'filter': ['INPUT', 'OUTPUT', 'FORWARD']}} for ip_version in builtin_chains: @@ -766,6 +768,24 @@ def _remove_dnsmasq_accept_rules(dev): iptables_manager.apply() +def _add_dhcp_mangle_rule(dev): + if not os.path.exists('/dev/vhost-net'): + return + table = iptables_manager.ipv4['mangle'] + table.add_rule('POSTROUTING', + '-o %s -p udp -m udp --dport 68 -j CHECKSUM ' + '--checksum-fill' % dev) + iptables_manager.apply() + + +def _remove_dhcp_mangle_rule(dev): + table = iptables_manager.ipv4['mangle'] + table.remove_rule('POSTROUTING', + '-o %s -p udp -m udp --dport 68 -j CHECKSUM ' + '--checksum-fill' % dev) + iptables_manager.apply() + + def get_dhcp_opts(context, network_ref): """Get network's hosts config in dhcp-opts format.""" hosts = [] @@ -828,6 +848,7 @@ def kill_dhcp(dev): else: LOG.debug(_('Pid %d is stale, skip killing dnsmasq'), pid) _remove_dnsmasq_accept_rules(dev) + _remove_dhcp_mangle_rule(dev) # NOTE(ja): Sending a HUP only reloads the hostfile, so any @@ -850,6 +871,9 @@ def restart_dhcp(context, dev, network_ref): write_to_file(optsfile, get_dhcp_opts(context, network_ref)) os.chmod(optsfile, 0644) + if network_ref['multi_host']: + _add_dhcp_mangle_rule(dev) + # Make sure dnsmasq can actually read it (it setuid()s to "nobody") os.chmod(conffile, 0644) diff --git a/nova/tests/network/test_linux_net.py b/nova/tests/network/test_linux_net.py index 243b0ee56..a94deb150 100644 --- a/nova/tests/network/test_linux_net.py +++ b/nova/tests/network/test_linux_net.py @@ -472,6 +472,8 @@ class LinuxNetworkTestCase(test.TestCase): '--arp-ip-src', dhcp, '-j', 'DROP'), ('iptables-save', '-c', '-t', 'filter'), ('iptables-restore', '-c'), + ('iptables-save', '-c', '-t', 'mangle'), + ('iptables-restore', '-c'), ('iptables-save', '-c', '-t', 'nat'), ('iptables-restore', '-c'), ('ip6tables-save', '-c', '-t', 'filter'), @@ -509,6 +511,8 @@ class LinuxNetworkTestCase(test.TestCase): '--arp-ip-src', dhcp, '-j', 'DROP'), ('iptables-save', '-c', '-t', 'filter'), ('iptables-restore', '-c'), + ('iptables-save', '-c', '-t', 'mangle'), + ('iptables-restore', '-c'), ('iptables-save', '-c', '-t', 'nat'), ('iptables-restore', '-c'), ('ip6tables-save', '-c', '-t', 'filter'), diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index fbafe27f3..a7df2c938 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -3218,6 +3218,20 @@ class IptablesFirewallTestCase(test.TestCase): ':POSTROUTING ACCEPT [5063:386098]', ] + in_mangle_rules = [ + '# Generated by iptables-save v1.4.12 on Tue Dec 18 15:50:25 201;', + '*mangle', + ':PREROUTING ACCEPT [241:39722]', + ':INPUT ACCEPT [230:39282]', + ':FORWARD ACCEPT [0:0]', + ':OUTPUT ACCEPT [266:26558]', + ':POSTROUTING ACCEPT [267:26590]', + '-A POSTROUTING -o virbr0 -p udp -m udp --dport 68 -j CHECKSUM ' + '--checksum-fill', + 'COMMIT', + '# Completed on Tue Dec 18 15:50:25 2012', + ] + in_filter_rules = [ '# Generated by iptables-save v1.4.4 on Mon Dec 6 11:54:13 2010', '*filter', @@ -3319,6 +3333,8 @@ class IptablesFirewallTestCase(test.TestCase): return '\n'.join(self.in_filter_rules), None if cmd == ('iptables-save', '-c', '-t', 'nat'): return '\n'.join(self.in_nat_rules), None + if cmd == ('iptables-save', '-c', '-t', 'mangle'): + return '\n'.join(self.in_mangle_rules), None if cmd == ('iptables-restore', '-c',): lines = process_input.split('\n') if '*filter' in lines: |
