summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Gandelman <adam.gandelman@canonical.com>2012-12-18 09:50:46 -0800
committerAdam Gandelman <adam.gandelman@canonical.com>2012-12-18 17:20:24 -0800
commit901a3dacb6f2d36cbe8d23707dba75452e91df33 (patch)
tree9f61348e6642d5ea4ecf0e7290b46aedbf414b8d
parent30ddc85a1046d8792cb9c2f82033124aebe50d0f (diff)
downloadnova-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.py28
-rw-r--r--nova/tests/network/test_linux_net.py4
-rw-r--r--nova/tests/test_libvirt.py16
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: