Ensure netfilter is enabled for bridges

Since security-groups use iptables rules on Linux bridges, we need to
ensure that netfilter is enabled for bridges.  Unfortunately, there
seems to be a long history of distributions having differing defaults
for this, best described in [1].

It seems at the moment everyone has to discover this for themselves;
packstack found it in Ia8c86dcb31810a8d6b133a161388604fde9bead4, then
fuel found the same thing in I8582c24706c3a7253e00569eef275f116d765bca
and then finally someone else hit it and put it into documentation
with I4ed3cec03a1b3a7d56dfe18394154ec1b2db6791.  I just spent a long
time figuring it out too when deploying with devstack.

Rather than having yet another fix in devstack, I don't see why
neutron shouldn't be ensuring the setting is correct when it starts up
-- without these settings enabled, security-groups are silently
broken.  This does that, and modifies test-cases to check we make the
calls.

[1] http://wiki.libvirt.org/page/Net.bridge-nf-call_and_sysctl.conf

Change-Id: If2d316eb8c422dc1e4f34b17a50b93dd72993a99
This commit is contained in:
Ian Wienand 2015-05-07 14:59:38 +10:00
parent 4e34dded69
commit 359b7c971a
2 changed files with 38 additions and 1 deletions

View File

@ -22,6 +22,7 @@ from neutron.agent import firewall
from neutron.agent.linux import ipset_manager
from neutron.agent.linux import iptables_comments as ic
from neutron.agent.linux import iptables_manager
from neutron.agent.linux import utils
from neutron.common import constants
from neutron.common import ipv6_utils
from neutron.extensions import portsecurity as psec
@ -71,6 +72,32 @@ class IptablesFirewallDriver(firewall.FirewallDriver):
lambda: collections.defaultdict(list))
self.pre_sg_members = None
self.enable_ipset = cfg.CONF.SECURITYGROUP.enable_ipset
self._enabled_netfilter_for_bridges = False
def _enable_netfilter_for_bridges(self):
# we only need to set these values once, but it has to be when
# we create a bridge; before that the bridge module might not
# be loaded and the proc values aren't there.
if self._enabled_netfilter_for_bridges:
return
else:
self._enabled_netfilter_for_bridges = True
# These proc values ensure that netfilter is enabled on
# bridges; essential for enforcing security groups rules with
# OVS Hybrid. Distributions can differ on whether this is
# enabled by default or not (Ubuntu - yes, Redhat - no, for
# example).
LOG.debug("Enabling netfilter for bridges")
utils.execute(['sysctl', '-w',
'net.bridge.bridge-nf-call-arptables=1'],
run_as_root=True)
utils.execute(['sysctl', '-w',
'net.bridge.bridge-nf-call-ip6tables=1'],
run_as_root=True)
utils.execute(['sysctl', '-w',
'net.bridge.bridge-nf-call-iptables=1'],
run_as_root=True)
@property
def ports(self):
@ -103,7 +130,7 @@ class IptablesFirewallDriver(firewall.FirewallDriver):
LOG.debug("Preparing device (%s) filter", port['device'])
self._remove_chains()
self._set_ports(port)
self._enable_netfilter_for_bridges()
# each security group has it own chains
self._setup_chains()
self.iptables.apply()

View File

@ -2483,6 +2483,9 @@ class TestSecurityGroupAgentWithIptables(base.BaseTestCase):
cfg.CONF.set_override('enable_ipset', False, group='SECURITYGROUP')
cfg.CONF.set_override('comment_iptables_rules', False, group='AGENT')
self.utils_exec = mock.patch(
'neutron.agent.linux.utils.execute').start()
self.rpc = mock.Mock()
self._init_agent(defer_refresh_firewall)
@ -2607,6 +2610,13 @@ class TestSecurityGroupAgentWithIptables(base.BaseTestCase):
self.assertThat(kwargs['process_input'],
matchers.MatchesRegex(expected_regex))
expected = ['net.bridge.bridge-nf-call-arptables=1',
'net.bridge.bridge-nf-call-ip6tables=1',
'net.bridge.bridge-nf-call-iptables=1']
for e in expected:
self.utils_exec.assert_any_call(['sysctl', '-w', e],
run_as_root=True)
def _replay_iptables(self, v4_filter, v6_filter, raw):
self._register_mock_call(
['iptables-save', '-c'],