diff --git a/neutron/agent/linux/ovs_lib.py b/neutron/agent/linux/ovs_lib.py index 5428404fe1..7cdb6f4dc7 100644 --- a/neutron/agent/linux/ovs_lib.py +++ b/neutron/agent/linux/ovs_lib.py @@ -479,6 +479,16 @@ def get_installed_ovs_klm_version(): LOG.exception(_("Unable to retrieve OVS kernel module version.")) +def get_installed_kernel_version(): + args = ["uname", "-r"] + try: + cmd = utils.execute(args) + for line in cmd.split('\n'): + return str(re.findall("\d+\.\d+\.\d+", line)) + except Exception: + LOG.exception(_("Unable to retrieve installed Linux kernel version.")) + + def get_bridge_external_bridge_id(root_helper, bridge): args = ["ovs-vsctl", "--timeout=2", "br-get-external-id", bridge, "bridge-id"] @@ -490,7 +500,13 @@ def get_bridge_external_bridge_id(root_helper, bridge): def _compare_installed_and_required_version( - installed_version, required_version, check_type, version_type): + installed_kernel_version, installed_version, required_version, + check_type, version_type): + if installed_kernel_version: + if dist_version.StrictVersion( + installed_kernel_version) >= dist_version.StrictVersion( + constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN): + return if installed_version: if dist_version.StrictVersion( installed_version) < dist_version.StrictVersion( @@ -515,17 +531,21 @@ def _compare_installed_and_required_version( def check_ovs_vxlan_version(root_helper): min_required_version = constants.MINIMUM_OVS_VXLAN_VERSION installed_klm_version = get_installed_ovs_klm_version() + installed_kernel_version = get_installed_kernel_version() installed_usr_version = get_installed_ovs_usr_version(root_helper) LOG.debug(_("Checking OVS version for VXLAN support " - "installed klm version is %s "), installed_klm_version) - LOG.debug(_("Checking OVS version for VXLAN support " - "installed usr version is %s"), installed_usr_version) + "installed klm version is %(klm)s, installed Linux version is " + "%(kernel)s, installed user version is %(usr)s ") % + {'klm': installed_klm_version, + 'kernel': installed_kernel_version, + 'usr': installed_usr_version}) # First check the userspace version - _compare_installed_and_required_version(installed_usr_version, + _compare_installed_and_required_version(None, installed_usr_version, min_required_version, 'userspace', 'VXLAN') # Now check the kernel version - _compare_installed_and_required_version(installed_klm_version, + _compare_installed_and_required_version(installed_kernel_version, + installed_klm_version, min_required_version, 'kernel', 'VXLAN') diff --git a/neutron/plugins/openvswitch/common/constants.py b/neutron/plugins/openvswitch/common/constants.py index 761f93add0..3a5b4aaae9 100644 --- a/neutron/plugins/openvswitch/common/constants.py +++ b/neutron/plugins/openvswitch/common/constants.py @@ -33,6 +33,9 @@ VETH_PHYSICAL_PREFIX = 'phy-' # The minimum version of OVS which supports VXLAN tunneling MINIMUM_OVS_VXLAN_VERSION = "1.10" +# The first version of the Linux kernel with converged VXLAN code for OVS +MINIMUM_LINUX_KERNEL_OVS_VXLAN = "3.13.0" + # The different types of tunnels TUNNEL_NETWORK_TYPES = [p_const.TYPE_GRE, p_const.TYPE_VXLAN] diff --git a/neutron/tests/unit/ofagent/test_ofa_neutron_agent.py b/neutron/tests/unit/ofagent/test_ofa_neutron_agent.py index ae685a5839..71afcd213d 100644 --- a/neutron/tests/unit/ofagent/test_ofa_neutron_agent.py +++ b/neutron/tests/unit/ofagent/test_ofa_neutron_agent.py @@ -33,6 +33,7 @@ from neutron.tests.unit.ofagent import fake_oflib NOTIFIER = ('neutron.plugins.ml2.rpc.AgentNotifierApi') +OVS_LINUX_KERN_VERS_WITHOUT_VXLAN = "3.12.0" class OFAAgentTestCase(base.BaseTestCase): @@ -510,6 +511,7 @@ class TestOFANeutronAgent(OFAAgentTestCase): def _check_ovs_vxlan_version(self, installed_usr_version, installed_klm_version, + installed_kernel_version, expecting_ok): with mock.patch( 'neutron.agent.linux.ovs_lib.get_installed_ovs_klm_version' @@ -517,41 +519,50 @@ class TestOFANeutronAgent(OFAAgentTestCase): with mock.patch( 'neutron.agent.linux.ovs_lib.get_installed_ovs_usr_version' ) as usr_cmd: - try: - klm_cmd.return_value = installed_klm_version - usr_cmd.return_value = installed_usr_version - self.agent.tunnel_types = 'vxlan' - self.agent._check_ovs_version() - version_ok = True - except SystemExit as e: - self.assertEqual(e.code, 1) - version_ok = False - self.assertEqual(version_ok, expecting_ok) + with mock.patch( + 'neutron.agent.linux.ovs_lib.get_installed_kernel_version' + ) as krn_cmd: + try: + klm_cmd.return_value = installed_klm_version + usr_cmd.return_value = installed_usr_version + krn_cmd.return_value = installed_kernel_version + self.agent.tunnel_types = 'vxlan' + self.agent._check_ovs_version() + version_ok = True + except SystemExit as e: + self.assertEqual(e.code, 1) + version_ok = False + self.assertEqual(version_ok, expecting_ok) def test_check_minimum_version(self): min_vxlan_ver = constants.MINIMUM_OVS_VXLAN_VERSION + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN self._check_ovs_vxlan_version(min_vxlan_ver, min_vxlan_ver, - expecting_ok=True) + min_kernel_ver, expecting_ok=True) def test_check_future_version(self): install_ver = str(float(constants.MINIMUM_OVS_VXLAN_VERSION) + 0.01) + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN self._check_ovs_vxlan_version(install_ver, install_ver, - expecting_ok=True) + min_kernel_ver, expecting_ok=True) def test_check_fail_version(self): install_ver = str(float(constants.MINIMUM_OVS_VXLAN_VERSION) - 0.01) + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN self._check_ovs_vxlan_version(install_ver, install_ver, - expecting_ok=False) + min_kernel_ver, expecting_ok=False) def test_check_fail_no_version(self): + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN self._check_ovs_vxlan_version(None, None, - expecting_ok=False) + min_kernel_ver, expecting_ok=False) def test_check_fail_klm_version(self): min_vxlan_ver = constants.MINIMUM_OVS_VXLAN_VERSION + min_kernel_ver = OVS_LINUX_KERN_VERS_WITHOUT_VXLAN install_ver = str(float(min_vxlan_ver) - 0.01) self._check_ovs_vxlan_version(min_vxlan_ver, install_ver, - expecting_ok=False) + min_kernel_ver, expecting_ok=False) def test_daemon_loop_uses_polling_manager(self): with mock.patch( diff --git a/neutron/tests/unit/openvswitch/test_ovs_lib.py b/neutron/tests/unit/openvswitch/test_ovs_lib.py index 56a085972b..a9c1b981ad 100644 --- a/neutron/tests/unit/openvswitch/test_ovs_lib.py +++ b/neutron/tests/unit/openvswitch/test_ovs_lib.py @@ -29,6 +29,8 @@ from neutron.plugins.openvswitch.common import constants from neutron.tests import base from neutron.tests import tools +OVS_LINUX_KERN_VERS_WITHOUT_VXLAN = "3.12.0" + class TestBaseOVS(base.BaseTestCase): @@ -804,6 +806,7 @@ class OVS_Lib_Test(base.BaseTestCase): def _check_ovs_vxlan_version(self, installed_usr_version, installed_klm_version, + installed_kernel_version, expecting_ok): with mock.patch( 'neutron.agent.linux.ovs_lib.get_installed_ovs_klm_version' @@ -811,37 +814,54 @@ class OVS_Lib_Test(base.BaseTestCase): with mock.patch( 'neutron.agent.linux.ovs_lib.get_installed_ovs_usr_version' ) as usr_cmd: - try: - klm_cmd.return_value = installed_klm_version - usr_cmd.return_value = installed_usr_version - ovs_lib.check_ovs_vxlan_version(root_helper='sudo') - version_ok = True - except SystemError: - version_ok = False - self.assertEqual(version_ok, expecting_ok) + with mock.patch( + 'neutron.agent.linux.ovs_lib.get_installed_kernel_version' + ) as kernel_cmd: + try: + klm_cmd.return_value = installed_klm_version + usr_cmd.return_value = installed_usr_version + kernel_cmd.return_value = installed_kernel_version + ovs_lib.check_ovs_vxlan_version(root_helper='sudo') + version_ok = True + except SystemError: + version_ok = False + self.assertEqual(version_ok, expecting_ok) def test_check_minimum_version(self): min_vxlan_ver = constants.MINIMUM_OVS_VXLAN_VERSION + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN self._check_ovs_vxlan_version(min_vxlan_ver, min_vxlan_ver, - expecting_ok=True) + min_kernel_ver, expecting_ok=True) def test_check_future_version(self): install_ver = str(float(constants.MINIMUM_OVS_VXLAN_VERSION) + 0.01) + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN self._check_ovs_vxlan_version(install_ver, install_ver, - expecting_ok=True) + min_kernel_ver, expecting_ok=True) def test_check_fail_version(self): install_ver = str(float(constants.MINIMUM_OVS_VXLAN_VERSION) - 0.01) + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN self._check_ovs_vxlan_version(install_ver, install_ver, - expecting_ok=False) + min_kernel_ver, expecting_ok=False) def test_check_fail_no_version(self): + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN self._check_ovs_vxlan_version(None, None, + min_kernel_ver, expecting_ok=False) def test_check_fail_klm_version(self): min_vxlan_ver = constants.MINIMUM_OVS_VXLAN_VERSION + min_kernel_ver = OVS_LINUX_KERN_VERS_WITHOUT_VXLAN install_ver = str(float(min_vxlan_ver) - 0.01) self._check_ovs_vxlan_version(min_vxlan_ver, install_ver, + min_kernel_ver, expecting_ok=False) + + def test_check_pass_kernel_version(self): + min_vxlan_ver = constants.MINIMUM_OVS_VXLAN_VERSION + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN + self._check_ovs_vxlan_version(min_vxlan_ver, min_vxlan_ver, + min_kernel_ver, expecting_ok=True) diff --git a/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py b/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py index f27f173ede..13464ca547 100644 --- a/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py +++ b/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py @@ -33,6 +33,7 @@ from neutron.tests import base NOTIFIER = ('neutron.plugins.openvswitch.' 'ovs_neutron_plugin.AgentNotifierApi') +OVS_LINUX_KERN_VERS_WITHOUT_VXLAN = "3.12.0" class CreateAgentConfigMap(base.BaseTestCase): @@ -490,6 +491,7 @@ class TestOvsNeutronAgent(base.BaseTestCase): def _check_ovs_vxlan_version(self, installed_usr_version, installed_klm_version, + installed_kernel_version, expecting_ok): with mock.patch( 'neutron.agent.linux.ovs_lib.get_installed_ovs_klm_version' @@ -497,41 +499,50 @@ class TestOvsNeutronAgent(base.BaseTestCase): with mock.patch( 'neutron.agent.linux.ovs_lib.get_installed_ovs_usr_version' ) as usr_cmd: - try: - klm_cmd.return_value = installed_klm_version - usr_cmd.return_value = installed_usr_version - self.agent.tunnel_types = 'vxlan' - self.agent._check_ovs_version() - version_ok = True - except SystemExit as e: - self.assertEqual(e.code, 1) - version_ok = False - self.assertEqual(version_ok, expecting_ok) + with mock.patch( + 'neutron.agent.linux.ovs_lib.get_installed_kernel_version' + ) as kernel_cmd: + try: + klm_cmd.return_value = installed_klm_version + usr_cmd.return_value = installed_usr_version + kernel_cmd.return_value = installed_kernel_version + self.agent.tunnel_types = 'vxlan' + self.agent._check_ovs_version() + version_ok = True + except SystemExit as e: + self.assertEqual(e.code, 1) + version_ok = False + self.assertEqual(version_ok, expecting_ok) def test_check_minimum_version(self): min_vxlan_ver = constants.MINIMUM_OVS_VXLAN_VERSION + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN self._check_ovs_vxlan_version(min_vxlan_ver, min_vxlan_ver, - expecting_ok=True) + min_kernel_ver, expecting_ok=True) def test_check_future_version(self): install_ver = str(float(constants.MINIMUM_OVS_VXLAN_VERSION) + 0.01) + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN self._check_ovs_vxlan_version(install_ver, install_ver, - expecting_ok=True) + min_kernel_ver, expecting_ok=True) def test_check_fail_version(self): install_ver = str(float(constants.MINIMUM_OVS_VXLAN_VERSION) - 0.01) + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN self._check_ovs_vxlan_version(install_ver, install_ver, - expecting_ok=False) + min_kernel_ver, expecting_ok=False) def test_check_fail_no_version(self): + min_kernel_ver = constants.MINIMUM_LINUX_KERNEL_OVS_VXLAN self._check_ovs_vxlan_version(None, None, - expecting_ok=False) + min_kernel_ver, expecting_ok=False) def test_check_fail_klm_version(self): min_vxlan_ver = constants.MINIMUM_OVS_VXLAN_VERSION + min_kernel_ver = OVS_LINUX_KERN_VERS_WITHOUT_VXLAN install_ver = str(float(min_vxlan_ver) - 0.01) self._check_ovs_vxlan_version(min_vxlan_ver, install_ver, - expecting_ok=False) + min_kernel_ver, expecting_ok=False) def _prepare_l2_pop_ofports(self): lvm1 = mock.Mock() diff --git a/neutron/tests/unit/openvswitch/test_ovs_tunnel.py b/neutron/tests/unit/openvswitch/test_ovs_tunnel.py index b1d98be94a..1940730fad 100644 --- a/neutron/tests/unit/openvswitch/test_ovs_tunnel.py +++ b/neutron/tests/unit/openvswitch/test_ovs_tunnel.py @@ -252,12 +252,19 @@ class TunnelTest(base.BaseTestCase): return_value="1.10") as klm_ver: with mock.patch.object(ovs_lib, 'get_installed_ovs_usr_version', return_value="1.10") as usr_ver: - ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE, - self.TUN_BRIDGE, - '10.0.0.1', self.NET_MAPPING, - 'sudo', 2, ['vxlan'], - self.VETH_MTU) + with mock.patch.object(ovs_lib, 'get_installed_kernel_version', + return_value=( + constants. + MINIMUM_LINUX_KERNEL_OVS_VXLAN + )) as kernel_ver: + ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE, + self.TUN_BRIDGE, + '10.0.0.1', + self.NET_MAPPING, + 'sudo', 2, ['vxlan'], + self.VETH_MTU) klm_ver.assert_called_once_with() + kernel_ver.assert_called_once_with() usr_ver.assert_called_once_with('sudo') self._verify_mock_calls()