]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Check vxlan enablement via modinfo
authorJUN JIE NAN <nanjj@cn.ibm.com>
Fri, 10 Jan 2014 07:01:13 +0000 (15:01 +0800)
committerGerrit Code Review <review@openstack.org>
Wed, 5 Mar 2014 07:21:59 +0000 (07:21 +0000)
On some linux distribution, for RHEL 6.5 as an example, vxlan is
enabled but the kernel version is still 2.6. And some linux kernel
version is higher than 3.8 or even 3.11, its vxlan mod may be
disabled. Under both situation, vxlan enablement checking via linux
kernel version may not be correct.

In this patch, we check vxlan enablement via modinfo: if vxlan module
exists and functional test pass, vxlan is enabled.

Closes-Bug: #1267682

Change-Id: Id52c04b4739d2d11fe52d4b1631cb4f39e6b577f

neutron/common/exceptions.py
neutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py
neutron/plugins/linuxbridge/common/constants.py
neutron/tests/unit/linuxbridge/test_lb_neutron_agent.py

index c7c57642d1fcbbe5ce013b3cd370207899d4436e..0a8922107086a936662c630e9ab8dda08903cb7e 100644 (file)
@@ -308,5 +308,9 @@ class NetworkVxlanPortRangeError(NeutronException):
     message = _("Invalid network VXLAN port range: '%(vxlan_range)s'")
 
 
+class VxlanNetworkUnsupported(NeutronException):
+    message = _("VXLAN Network unsupported.")
+
+
 class DuplicatedExtension(NeutronException):
     message = _("Found duplicate extension: %(alias)s")
index 22e8c5d5f644ea94ac09f0097f4e361d949e7025..66b4427420d707efb7922b3d84d718f1b1358306 100755 (executable)
@@ -22,9 +22,7 @@
 # Neutron OpenVSwitch Plugin.
 # @author: Sumit Naiksatam, Cisco Systems, Inc.
 
-import distutils.version as dist_version
 import os
-import platform
 import sys
 import time
 
@@ -38,6 +36,7 @@ from neutron.agent import rpc as agent_rpc
 from neutron.agent import securitygroups_rpc as sg_rpc
 from neutron.common import config as logging_config
 from neutron.common import constants
+from neutron.common import exceptions
 from neutron.common import topics
 from neutron.common import utils as q_utils
 from neutron import context
@@ -514,29 +513,74 @@ class LinuxBridgeManager:
                 devices.add(device)
         return devices
 
+    def vxlan_ucast_supported(self):
+        if not cfg.CONF.VXLAN.l2_population:
+            return False
+        if not ip_lib.iproute_arg_supported(
+                ['bridge', 'fdb'], 'append', self.root_helper):
+            LOG.warning(_('Option "%(option)s" must be supported by command '
+                          '"%(command)s" to enable %(mode)s mode') %
+                        {'option': 'append',
+                         'command': 'bridge fdb',
+                         'mode': 'VXLAN UCAST'})
+            return False
+        for segmentation_id in range(1, constants.MAX_VXLAN_VNI + 1):
+            if not self.device_exists(
+                    self.get_vxlan_device_name(segmentation_id)):
+                break
+        else:
+            LOG.error(_('No valid Segmentation ID to perform UCAST test.'))
+            return False
+
+        test_iface = self.ensure_vxlan(segmentation_id)
+        try:
+            utils.execute(
+                cmd=['bridge', 'fdb', 'append', constants.FLOODING_ENTRY[0],
+                     'dev', test_iface, 'dst', '1.1.1.1'],
+                root_helper=self.root_helper)
+            return True
+        except RuntimeError:
+            return False
+        finally:
+            self.delete_vxlan(test_iface)
+
+    def vxlan_mcast_supported(self):
+        if not cfg.CONF.VXLAN.vxlan_group:
+            LOG.warning(_('VXLAN muticast group must be provided in '
+                          'vxlan_group option to enable VXLAN MCAST mode'))
+            return False
+        if not ip_lib.iproute_arg_supported(
+                ['ip', 'link', 'add', 'type', 'vxlan'],
+                'proxy', self.root_helper):
+            LOG.warning(_('Option "%(option)s" must be supported by command '
+                          '"%(command)s" to enable %(mode)s mode') %
+                        {'option': 'proxy',
+                         'command': 'ip link add type vxlan',
+                         'mode': 'VXLAN MCAST'})
+
+            return False
+        return True
+
+    def vxlan_module_supported(self):
+        try:
+            utils.execute(cmd=['modinfo', 'vxlan'])
+            return True
+        except RuntimeError:
+            return False
+
     def check_vxlan_support(self):
-        kernel_version = dist_version.LooseVersion(platform.release())
-        if cfg.CONF.VXLAN.l2_population and (
-                kernel_version > dist_version.LooseVersion(
-                lconst.MIN_VXLAN_KVER[lconst.VXLAN_UCAST])) and (
-                ip_lib.iproute_arg_supported(['bridge', 'fdb'],
-                                             'append', self.root_helper)):
+        self.vxlan_mode = lconst.VXLAN_NONE
+        if not self.vxlan_module_supported():
+            LOG.error(_('Linux kernel vxlan module and iproute2 3.8 or above '
+                        'are required to enable VXLAN.'))
+            raise exceptions.VxlanNetworkUnsupported()
+
+        if self.vxlan_ucast_supported():
             self.vxlan_mode = lconst.VXLAN_UCAST
-        elif (kernel_version > dist_version.LooseVersion(
-                lconst.MIN_VXLAN_KVER[lconst.VXLAN_MCAST])) and (
-                ip_lib.iproute_arg_supported(['ip', 'link', 'add',
-                                              'type', 'vxlan'], 'proxy',
-                                             self.root_helper)):
-            if cfg.CONF.VXLAN.vxlan_group:
-                self.vxlan_mode = lconst.VXLAN_MCAST
-            else:
-                self.vxlan_mode = lconst.VXLAN_NONE
-                LOG.warning(_('VXLAN muticast group must be provided in '
-                              'vxlan_group option to enable VXLAN'))
+        elif self.vxlan_mcast_supported():
+            self.vxlan_mode = lconst.VXLAN_MCAST
         else:
-            self.vxlan_mode = lconst.VXLAN_NONE
-            LOG.warning(_('Unable to use VXLAN, it requires at least 3.8 '
-                          'linux kernel and iproute2 3.8'))
+            raise exceptions.VxlanNetworkUnsupported()
         LOG.debug(_('Using %s VXLAN mode'), self.vxlan_mode)
 
     def fdb_ip_entry_exists(self, mac, ip, interface):
index 05180f592cc7399ffee68bc22160230e43e7b64f..6dee88f406ca231df5314d2f1f0164de04b7efdc 100644 (file)
@@ -28,9 +28,6 @@ VXLAN_NONE = 'not_supported'
 VXLAN_MCAST = 'multicast_flooding'
 VXLAN_UCAST = 'unicast_flooding'
 
-# Corresponding minimal kernel versions requirements
-MIN_VXLAN_KVER = {VXLAN_MCAST: '3.8', VXLAN_UCAST: '3.11'}
-
 
 # TODO(rkukura): Eventually remove this function, which provides
 # temporary backward compatibility with pre-Havana RPC and DB vlan_id
index 256707b5bb149a29a272e9497a3b7e60745f832f..a15a1ee685fd332cdc519618039988c0a1b419fe 100644 (file)
@@ -24,6 +24,7 @@ import testtools
 from neutron.agent.linux import ip_lib
 from neutron.agent.linux import utils
 from neutron.common import constants
+from neutron.common import exceptions
 from neutron.openstack.common.rpc import common as rpc_common
 from neutron.plugins.common import constants as p_const
 from neutron.plugins.linuxbridge.agent import linuxbridge_neutron_agent
@@ -646,59 +647,107 @@ class TestLinuxBridgeManager(base.BaseTestCase):
                               "removed": set(["dev3"])
                               })
 
-    def _check_vxlan_support(self, kernel_version, vxlan_proxy_supported,
-                             fdb_append_supported, l2_population,
-                             expected_mode):
-        def iproute_supported_side_effect(*args):
-            if args[1] == 'proxy':
-                return vxlan_proxy_supported
-            elif args[1] == 'append':
-                return fdb_append_supported
-
+    def _check_vxlan_support(self, expected, vxlan_module_supported,
+                             vxlan_ucast_supported, vxlan_mcast_supported):
+        with contextlib.nested(
+            mock.patch.object(self.lbm, 'vxlan_module_supported',
+                              return_value=vxlan_module_supported),
+            mock.patch.object(self.lbm, 'vxlan_ucast_supported',
+                              return_value=vxlan_ucast_supported),
+            mock.patch.object(self.lbm, 'vxlan_mcast_supported',
+                              return_value=vxlan_mcast_supported)):
+            if expected == lconst.VXLAN_NONE:
+                self.assertRaises(exceptions.VxlanNetworkUnsupported,
+                                  self.lbm.check_vxlan_support)
+                self.assertEqual(expected, self.lbm.vxlan_mode)
+            else:
+                self.lbm.check_vxlan_support()
+                self.assertEqual(expected, self.lbm.vxlan_mode)
+
+    def test_check_vxlan_support(self):
+        self._check_vxlan_support(expected=lconst.VXLAN_UCAST,
+                                  vxlan_module_supported=True,
+                                  vxlan_ucast_supported=True,
+                                  vxlan_mcast_supported=True)
+        self._check_vxlan_support(expected=lconst.VXLAN_MCAST,
+                                  vxlan_module_supported=True,
+                                  vxlan_ucast_supported=False,
+                                  vxlan_mcast_supported=True)
+
+        self._check_vxlan_support(expected=lconst.VXLAN_NONE,
+                                  vxlan_module_supported=False,
+                                  vxlan_ucast_supported=False,
+                                  vxlan_mcast_supported=False)
+        self._check_vxlan_support(expected=lconst.VXLAN_NONE,
+                                  vxlan_module_supported=True,
+                                  vxlan_ucast_supported=False,
+                                  vxlan_mcast_supported=False)
+
+    def _check_vxlan_module_supported(self, expected, execute_side_effect):
+        with mock.patch.object(
+                utils, 'execute',
+                side_effect=execute_side_effect):
+            self.assertEqual(expected, self.lbm.vxlan_module_supported())
+
+    def test_vxlan_module_supported(self):
+        self._check_vxlan_module_supported(
+            expected=True,
+            execute_side_effect=None)
+        self._check_vxlan_module_supported(
+            expected=False,
+            execute_side_effect=RuntimeError())
+
+    def _check_vxlan_ucast_supported(
+            self, expected, l2_population, iproute_arg_supported, fdb_append):
+        cfg.CONF.set_override('l2_population', l2_population, 'VXLAN')
         with contextlib.nested(
-            mock.patch("platform.release", return_value=kernel_version),
-            mock.patch.object(ip_lib, 'iproute_arg_supported',
-                              side_effect=iproute_supported_side_effect),
-        ) as (kver_fn, ip_arg_fn):
-            self.lbm.check_vxlan_support()
-            self.assertEqual(self.lbm.vxlan_mode, expected_mode)
-
-    def test_vxlan_mode_ucast(self):
-        self._check_vxlan_support(kernel_version='3.12',
-                                  vxlan_proxy_supported=True,
-                                  fdb_append_supported=True,
-                                  l2_population=True,
-                                  expected_mode=lconst.VXLAN_MCAST)
-
-    def test_vxlan_mode_mcast(self):
-        self._check_vxlan_support(kernel_version='3.12',
-                                  vxlan_proxy_supported=True,
-                                  fdb_append_supported=False,
-                                  l2_population=True,
-                                  expected_mode=lconst.VXLAN_MCAST)
-        self._check_vxlan_support(kernel_version='3.10',
-                                  vxlan_proxy_supported=True,
-                                  fdb_append_supported=True,
-                                  l2_population=True,
-                                  expected_mode=lconst.VXLAN_MCAST)
-
-    def test_vxlan_mode_unsupported(self):
-        self._check_vxlan_support(kernel_version='3.7',
-                                  vxlan_proxy_supported=True,
-                                  fdb_append_supported=True,
-                                  l2_population=False,
-                                  expected_mode=lconst.VXLAN_NONE)
-        self._check_vxlan_support(kernel_version='3.10',
-                                  vxlan_proxy_supported=False,
-                                  fdb_append_supported=False,
-                                  l2_population=False,
-                                  expected_mode=lconst.VXLAN_NONE)
-        cfg.CONF.set_override('vxlan_group', '', 'VXLAN')
-        self._check_vxlan_support(kernel_version='3.12',
-                                  vxlan_proxy_supported=True,
-                                  fdb_append_supported=True,
-                                  l2_population=True,
-                                  expected_mode=lconst.VXLAN_NONE)
+                mock.patch.object(
+                    self.lbm, 'device_exists', return_value=False),
+                mock.patch.object(self.lbm, 'delete_vxlan', return_value=None),
+                mock.patch.object(self.lbm, 'ensure_vxlan', return_value=None),
+                mock.patch.object(
+                    utils, 'execute',
+                    side_effect=None if fdb_append else RuntimeError()),
+                mock.patch.object(
+                    ip_lib, 'iproute_arg_supported',
+                    return_value=iproute_arg_supported)):
+                self.assertEqual(expected, self.lbm.vxlan_ucast_supported())
+
+    def test_vxlan_ucast_supported(self):
+        self._check_vxlan_ucast_supported(
+            expected=False,
+            l2_population=False, iproute_arg_supported=True, fdb_append=True)
+        self._check_vxlan_ucast_supported(
+            expected=False,
+            l2_population=True, iproute_arg_supported=False, fdb_append=True)
+        self._check_vxlan_ucast_supported(
+            expected=False,
+            l2_population=True, iproute_arg_supported=True, fdb_append=False)
+        self._check_vxlan_ucast_supported(
+            expected=True,
+            l2_population=True, iproute_arg_supported=True, fdb_append=True)
+
+    def _check_vxlan_mcast_supported(
+            self, expected, vxlan_group, iproute_arg_supported):
+        cfg.CONF.set_override('vxlan_group', vxlan_group, 'VXLAN')
+        with mock.patch.object(
+                ip_lib, 'iproute_arg_supported',
+                return_value=iproute_arg_supported):
+            self.assertEqual(expected, self.lbm.vxlan_mcast_supported())
+
+    def test_vxlan_mcast_supported(self):
+        self._check_vxlan_mcast_supported(
+            expected=False,
+            vxlan_group='',
+            iproute_arg_supported=True)
+        self._check_vxlan_mcast_supported(
+            expected=False,
+            vxlan_group='224.0.0.1',
+            iproute_arg_supported=False)
+        self._check_vxlan_mcast_supported(
+            expected=True,
+            vxlan_group='224.0.0.1',
+            iproute_arg_supported=True)
 
 
 class TestLinuxBridgeRpcCallbacks(base.BaseTestCase):