Set ip_nonlocal_bind in namespace if it exists

Somewhere in the 3.19 kernel timeframe ip_nonlocal_bind was
changed to be a per-namespace attribute. To be backwards
compatible we need to try that first, then fall-back to
setting the one in the root namespace if it fails.

Closes-Bug: #1507078
Change-Id: I018e800bc8d4e85d067aaae865c9b04bf030c980
(cherry picked from commit 24acc41b93)
This commit is contained in:
Brian Haley 2015-10-16 18:02:16 -04:00
parent c4dd0570e4
commit 4428b291f3
5 changed files with 71 additions and 13 deletions

View File

@ -130,13 +130,27 @@ class FipNamespace(namespaces.Namespace):
def create(self):
# TODO(Carl) Get this functionality from mlavelle's namespace baseclass
LOG.debug("add fip-namespace(%s)", self.name)
LOG.debug("DVR: add fip namespace: %s", self.name)
ip_wrapper_root = ip_lib.IPWrapper()
ip_wrapper_root.netns.execute(['sysctl',
'-w',
'net.ipv4.ip_nonlocal_bind=1'],
run_as_root=True)
ip_wrapper = ip_wrapper_root.ensure_namespace(self.get_name())
# Somewhere in the 3.19 kernel timeframe ip_nonlocal_bind was
# changed to be a per-namespace attribute. To be backwards
# compatible we need to try both if at first we fail.
try:
ip_wrapper.netns.execute(['sysctl',
'-w',
'net.ipv4.ip_nonlocal_bind=1'],
log_fail_as_error=False,
run_as_root=True)
except RuntimeError:
LOG.debug('DVR: fip namespace (%s) does not support setting '
'net.ipv4.ip_nonlocal_bind, trying in root namespace',
self.name)
ip_wrapper_root.netns.execute(['sysctl',
'-w',
'net.ipv4.ip_nonlocal_bind=1'],
run_as_root=True)
ip_wrapper.netns.execute(['sysctl', '-w', 'net.ipv4.ip_forward=1'])
if self.use_ipv6:
ip_wrapper.netns.execute(['sysctl', '-w',
@ -166,7 +180,7 @@ class FipNamespace(namespaces.Namespace):
self.agent_gateway_port = None
# TODO(mrsmith): add LOG warn if fip count != 0
LOG.debug('DVR: destroy fip ns: %s', self.name)
LOG.debug('DVR: destroy fip namespace: %s', self.name)
super(FipNamespace, self).delete()
def create_gateway_port(self, agent_gateway_port):

View File

@ -800,7 +800,8 @@ class IpNetnsCommand(IpCommandBase):
self._as_root([], ('delete', name), use_root_namespace=True)
def execute(self, cmds, addl_env=None, check_exit_code=True,
extra_ok_codes=None, run_as_root=False):
log_fail_as_error=True, extra_ok_codes=None,
run_as_root=False):
ns_params = []
kwargs = {'run_as_root': run_as_root}
if self._parent.namespace:
@ -813,7 +814,8 @@ class IpNetnsCommand(IpCommandBase):
['%s=%s' % pair for pair in addl_env.items()])
cmd = ns_params + env_params + list(cmds)
return utils.execute(cmd, check_exit_code=check_exit_code,
extra_ok_codes=extra_ok_codes, **kwargs)
extra_ok_codes=extra_ok_codes,
log_fail_as_error=log_fail_as_error, **kwargs)
def exists(self, name):
output = self._parent._execute(

View File

@ -15,9 +15,11 @@
import mock
from oslo_utils import uuidutils
from neutron.agent.common import utils
from neutron.agent.l3 import dvr_fip_ns
from neutron.agent.l3 import link_local_allocator as lla
from neutron.agent.linux import ip_lib
from neutron.agent.linux import iptables_manager
from neutron.tests import base
_uuid = uuidutils.generate_uuid
@ -94,6 +96,41 @@ class TestDvrFipNs(base.BaseTestCase):
'20.0.0.30',
mock.ANY)
@mock.patch.object(iptables_manager, 'IptablesManager')
@mock.patch.object(utils, 'execute')
@mock.patch.object(ip_lib.IpNetnsCommand, 'exists')
def _test_create(self, old_kernel, exists, execute, IPTables):
exists.return_value = True
# There are up to four sysctl calls - two for ip_nonlocal_bind,
# and two to enable forwarding
execute.side_effect = [RuntimeError if old_kernel else None,
None, None, None]
self.fip_ns._iptables_manager = IPTables()
self.fip_ns.create()
ns_name = self.fip_ns.get_name()
netns_cmd = ['ip', 'netns', 'exec', ns_name]
bind_cmd = ['sysctl', '-w', 'net.ipv4.ip_nonlocal_bind=1']
expected = [mock.call(netns_cmd + bind_cmd, check_exit_code=True,
extra_ok_codes=None, log_fail_as_error=False,
run_as_root=True)]
if old_kernel:
expected.append(mock.call(bind_cmd, check_exit_code=True,
extra_ok_codes=None,
log_fail_as_error=True,
run_as_root=True))
execute.assert_has_calls(expected)
def test_create_old_kernel(self):
self._test_create(True)
def test_create_new_kernel(self):
self._test_create(False)
@mock.patch.object(ip_lib, 'IPWrapper')
def test_destroy(self, IPWrapper):
ip_wrapper = IPWrapper()

View File

@ -130,7 +130,8 @@ class TestProcessManager(base.BaseTestCase):
self.execute.assert_called_once_with(['the', 'cmd'],
check_exit_code=True,
extra_ok_codes=None,
run_as_root=False)
run_as_root=False,
log_fail_as_error=True)
def test_enable_with_namespace(self):
callback = mock.Mock()

View File

@ -1139,7 +1139,8 @@ class TestIpNetnsCommand(TestIPCmdBase):
execute.assert_called_once_with(
['ip', 'netns', 'exec', 'ns',
'sysctl', '-w', 'net.ipv4.conf.all.promote_secondaries=1'],
run_as_root=True, check_exit_code=True, extra_ok_codes=None)
run_as_root=True, check_exit_code=True, extra_ok_codes=None,
log_fail_as_error=True)
def test_delete_namespace(self):
with mock.patch('neutron.agent.common.utils.execute'):
@ -1180,7 +1181,8 @@ class TestIpNetnsCommand(TestIPCmdBase):
'link', 'list'],
run_as_root=True,
check_exit_code=True,
extra_ok_codes=None)
extra_ok_codes=None,
log_fail_as_error=True)
def test_execute_env_var_prepend(self):
self.parent.namespace = 'ns'
@ -1191,7 +1193,8 @@ class TestIpNetnsCommand(TestIPCmdBase):
['ip', 'netns', 'exec', 'ns', 'env'] +
['%s=%s' % (k, v) for k, v in env.items()] +
['ip', 'link', 'list'],
run_as_root=True, check_exit_code=True, extra_ok_codes=None)
run_as_root=True, check_exit_code=True, extra_ok_codes=None,
log_fail_as_error=True)
def test_execute_nosudo_with_no_namespace(self):
with mock.patch('neutron.agent.common.utils.execute') as execute:
@ -1200,7 +1203,8 @@ class TestIpNetnsCommand(TestIPCmdBase):
execute.assert_called_once_with(['test'],
check_exit_code=True,
extra_ok_codes=None,
run_as_root=False)
run_as_root=False,
log_fail_as_error=True)
class TestDeviceExists(base.BaseTestCase):