From 4f0caa0ece73bfa060e10f482a39f436a65a55fc Mon Sep 17 00:00:00 2001 From: Dustin Lundquist Date: Fri, 19 Aug 2016 18:44:49 +0100 Subject: [PATCH] Rename ipv6_utils.is_enabled() IPv6 utils is_enabled() doesn't actually determine if IPv6 is enabled on the host. It checks if /proc/sys/net/ipv6/conf/default/disable_ipv6 is present and is set to 0. This kernel configuration option controls if the kernel will automatically assign IPv6 link-local addresses to newly created network interfaces when their link state changes to up. The existence of this /proc files does indicate that the Linux kernel has the ipv6 module loaded or ipv6 was compiled in. Having this /proc file set to zero does not indicate IPv6 is not available on the system, just that newly created interfaces will inherit this configuration and will not have IPv6 addresses bound to them unless the administrator changes the interfaces specific /proc/sys/net/ipv6/conf/$IFACE/disable_ipv6 configuration. This check was added to Neutron so it could operate with distributions which didn't load the ipv6 kernel module, preventing errors when attempting to make IPv6 specific configurations in the iptables firewall driver and the L3 agent. Removing it would break existing deployments. Renaming this function to provide clarity for complex conditions tested by this function. In fact it is a good security practice to set this default disable_ipv6 option to 1, and explicitly enable IPv6 by setting disable_ipv6=0 on individual interfaces which the administrator intends to bind IPv6 addresses on. This establishes parity with IPv4 behavior where interfaces are not active in an address family until the administrator explicitly configures them to be active in that address family. This practice does not currently work as expected with the Neutron, since setting /proc/sys/net/ipv6/conf/default/disable_ipv6 to 1 unexpectedly disables creating IPv6 security group rules leaving instances completely exposed via IPv6 regardless of security group rules. Change-Id: I844b992240a5db642766ec9c04e3b5fcab8e2e23 --- neutron/agent/l3/agent.py | 2 +- neutron/agent/linux/iptables_firewall.py | 2 +- neutron/common/ipv6_utils.py | 16 ++++++++++++++-- .../metering/drivers/iptables/iptables_driver.py | 2 +- .../tests/functional/agent/l3/test_ha_router.py | 3 ++- neutron/tests/unit/common/test_ipv6_utils.py | 14 +++++++------- 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/neutron/agent/l3/agent.py b/neutron/agent/l3/agent.py index 3d477da5aa0..a3614d14650 100644 --- a/neutron/agent/l3/agent.py +++ b/neutron/agent/l3/agent.py @@ -250,7 +250,7 @@ class L3NATAgent(ha.AgentMixin, super(L3NATAgent, self).__init__(host=self.conf.host) self.target_ex_net_id = None - self.use_ipv6 = ipv6_utils.is_enabled() + self.use_ipv6 = ipv6_utils.is_enabled_and_bind_by_default() self.pd = pd.PrefixDelegation(self.context, self.process_monitor, self.driver, diff --git a/neutron/agent/linux/iptables_firewall.py b/neutron/agent/linux/iptables_firewall.py index 8978de7c0dc..f9852faa9e5 100644 --- a/neutron/agent/linux/iptables_firewall.py +++ b/neutron/agent/linux/iptables_firewall.py @@ -66,7 +66,7 @@ class IptablesFirewallDriver(firewall.FirewallDriver): def __init__(self, namespace=None): self.iptables = iptables_manager.IptablesManager( - use_ipv6=ipv6_utils.is_enabled(), + use_ipv6=ipv6_utils.is_enabled_and_bind_by_default(), namespace=namespace) # TODO(majopela, shihanzhang): refactor out ipset to a separate # driver composed over this one diff --git a/neutron/common/ipv6_utils.py b/neutron/common/ipv6_utils.py index f54ef4c759b..670d00cd438 100644 --- a/neutron/common/ipv6_utils.py +++ b/neutron/common/ipv6_utils.py @@ -18,6 +18,7 @@ IPv6-related utilities and helper functions. """ import os +from debtcollector import moves from debtcollector import removals import netaddr from neutron_lib import constants as const @@ -53,7 +54,10 @@ def get_ipv6_addr_by_EUI64(prefix, mac): 'EUI-64: %s') % prefix) -def is_enabled(): +def is_enabled_and_bind_by_default(): + """Check if host has the IPv6 support and is configured to bind IPv6 + address to new interfaces by default. + """ global _IS_IPV6_ENABLED if _IS_IPV6_ENABLED is None: @@ -65,10 +69,18 @@ def is_enabled(): else: _IS_IPV6_ENABLED = False if not _IS_IPV6_ENABLED: - LOG.info(_LI("IPv6 is not enabled on this system.")) + LOG.info(_LI("IPv6 not present or configured not to bind to new " + "interfaces on this system. Please ensure IPv6 is " + "enabled and /proc/sys/net/ipv6/conf/default/" + "disable_ipv6 is set to 1 to enable IPv6.")) return _IS_IPV6_ENABLED +is_enabled = moves.moved_function(is_enabled_and_bind_by_default, + 'is_enabled', __name__, version='Ocata', + removal_version='Pike') + + def is_auto_address_subnet(subnet): """Check if subnet is an auto address subnet.""" modes = [const.IPV6_SLAAC, const.DHCPV6_STATELESS] diff --git a/neutron/services/metering/drivers/iptables/iptables_driver.py b/neutron/services/metering/drivers/iptables/iptables_driver.py index 40666461c15..003524c049f 100644 --- a/neutron/services/metering/drivers/iptables/iptables_driver.py +++ b/neutron/services/metering/drivers/iptables/iptables_driver.py @@ -74,7 +74,7 @@ class RouterWithMetering(object): namespace=self.ns_name, binary_name=WRAP_NAME, state_less=True, - use_ipv6=ipv6_utils.is_enabled()) + use_ipv6=ipv6_utils.is_enabled_and_bind_by_default()) self.metering_labels = {} diff --git a/neutron/tests/functional/agent/l3/test_ha_router.py b/neutron/tests/functional/agent/l3/test_ha_router.py index 4d4382da9f1..086e93f06a4 100644 --- a/neutron/tests/functional/agent/l3/test_ha_router.py +++ b/neutron/tests/functional/agent/l3/test_ha_router.py @@ -98,7 +98,8 @@ class L3HATestCase(framework.L3AgentTestFramework): self._router_lifecycle(enable_ha=True, dual_stack=True, v6_ext_gw_with_sub=False) - @testtools.skipUnless(ipv6_utils.is_enabled(), "IPv6 is not enabled") + @testtools.skipUnless(ipv6_utils.is_enabled_and_bind_by_default(), + "IPv6 is not enabled") def test_ipv6_router_advts_after_router_state_change(self): # Schedule router to l3 agent, and then add router gateway. Verify # that router gw interface is configured to receive Router Advts. diff --git a/neutron/tests/unit/common/test_ipv6_utils.py b/neutron/tests/unit/common/test_ipv6_utils.py index fad579b2a34..3251be406cb 100644 --- a/neutron/tests/unit/common/test_ipv6_utils.py +++ b/neutron/tests/unit/common/test_ipv6_utils.py @@ -55,10 +55,10 @@ class IPv6byEUI64TestCase(base.BaseTestCase): ipv6_utils.get_ipv6_addr_by_EUI64(prefix, mac)) -class TestIsEnabled(base.BaseTestCase): +class TestIsEnabledAndBindByDefault(base.BaseTestCase): def setUp(self): - super(TestIsEnabled, self).setUp() + super(TestIsEnabledAndBindByDefault, self).setUp() def reset_detection_flag(): ipv6_utils._IS_IPV6_ENABLED = None @@ -70,25 +70,25 @@ class TestIsEnabled(base.BaseTestCase): def test_enabled(self): self.useFixture(tools.OpenFixture(self.proc_path, '0')) - enabled = ipv6_utils.is_enabled() + enabled = ipv6_utils.is_enabled_and_bind_by_default() self.assertTrue(enabled) def test_disabled(self): self.useFixture(tools.OpenFixture(self.proc_path, '1')) - enabled = ipv6_utils.is_enabled() + enabled = ipv6_utils.is_enabled_and_bind_by_default() self.assertFalse(enabled) def test_disabled_non_exists(self): mo = self.useFixture(tools.OpenFixture(self.proc_path, '1')).mock_open self.mock_exists.return_value = False - enabled = ipv6_utils.is_enabled() + enabled = ipv6_utils.is_enabled_and_bind_by_default() self.assertFalse(enabled) self.assertFalse(mo.called) def test_memoize(self): mo = self.useFixture(tools.OpenFixture(self.proc_path, '0')).mock_open - ipv6_utils.is_enabled() - enabled = ipv6_utils.is_enabled() + ipv6_utils.is_enabled_and_bind_by_default() + enabled = ipv6_utils.is_enabled_and_bind_by_default() self.assertTrue(enabled) mo.assert_called_once_with(self.proc_path, 'r')