Merge "Check vxlan enablement via modinfo"
This commit is contained in:
commit
cc48a40da6
@ -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")
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user