Skip to content

Commit

Permalink
Add an iptables mangle rule per-bridge for DHCP.
Browse files Browse the repository at this point in the history
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.

(Backported from commit 901a3da)

Change-Id: I1a51c1d808fa47a77e713dbfe384ffad183d6031
  • Loading branch information
Adam Gandelman committed Dec 20, 2012
1 parent 451003e commit 4bfc8f1
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
29 changes: 27 additions & 2 deletions nova/network/linux_net.py
Expand Up @@ -277,7 +277,8 @@ def __init__(self, execute=None):
self.execute = execute

self.ipv4 = {'filter': IptablesTable(),
'nat': IptablesTable()}
'nat': IptablesTable(),
'mangle': IptablesTable()}
self.ipv6 = {'filter': IptablesTable()}

self.iptables_apply_deferred = False
Expand All @@ -298,7 +299,8 @@ def __init__(self, execute=None):

# 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:
Expand Down Expand Up @@ -732,6 +734,24 @@ def _add_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 = []
Expand Down Expand Up @@ -788,6 +808,8 @@ def kill_dhcp(dev):
else:
LOG.debug(_('Pid %d is stale, skip killing dnsmasq'), pid)

_remove_dhcp_mangle_rule(dev)


# NOTE(ja): Sending a HUP only reloads the hostfile, so any
# configuration options (like dchp-range, vlan, ...)
Expand All @@ -809,6 +831,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)

Expand Down
16 changes: 16 additions & 0 deletions nova/tests/test_libvirt.py
Expand Up @@ -3099,6 +3099,20 @@ def nwfilterDefineXML(*args, **kwargs):
':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',
Expand Down Expand Up @@ -3200,6 +3214,8 @@ def fake_iptables_execute(*cmd, **kwargs):
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:
Expand Down

0 comments on commit 4bfc8f1

Please sign in to comment.