Check vxlan enablement via modinfo

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
This commit is contained in:
JUN JIE NAN 2014-01-10 15:01:13 +08:00 committed by Gerrit Code Review
parent f18558f72c
commit d583d55c6a
4 changed files with 170 additions and 76 deletions

View 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")

View File

@ -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 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_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'))
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:
self.vxlan_mode = lconst.VXLAN_NONE
LOG.warning(_('Unable to use VXLAN, it requires at least 3.8 '
'linux kernel and iproute2 3.8'))
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):
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 self.vxlan_mcast_supported():
self.vxlan_mode = lconst.VXLAN_MCAST
else:
raise exceptions.VxlanNetworkUnsupported()
LOG.debug(_('Using %s VXLAN mode'), self.vxlan_mode)
def fdb_ip_entry_exists(self, mac, ip, interface):

View 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

View 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("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)
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_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_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)
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)
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 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)
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.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):