Add support for VXLAN to the Open vSwitch plugin.

This commit adds support for utilizing the VXLAN tunneling protocol in versions
of Open vSwitch >= 1.10. This is configurable and will default to GRE if not
configured. As part of this commit, it is possible to configure the UDP port
VXLAN will utilize as well. VXLAN and GRE cannot be configured at the same
time with this patch. 2 new configuration file options are added to the AGENT
section of the config to support this: 'tunnel_type' and 'vxlan_udp_port'.
In addition, the agent no longer makes use of enable_tunneling, as this can
be determined if tunnel_type is set.

Note: The VXLAN functionality utilized here is what is implemented in Open
vSwitch itself, and is different than the VXLAN functionality in the
upstream Linux kernel. The code validates both the userspace and kernel
pieces of OVS to verify if VXLAN functionality can be supported on the
running system

Implements blueprint ovs-vxlan-lisp-tunnel

Change-Id: I45d49d5d6463e574922c7f50d6499c6bdb6c862c
This commit is contained in:
Kyle Mestery 2013-05-17 15:04:19 -05:00
parent 1bfd162fc2
commit a98884efd9
8 changed files with 239 additions and 60 deletions

View File

@ -32,12 +32,13 @@ reconnect_interval = 2
# default value 'local' is useful only for single-box testing and
# provides no connectivity between hosts. You MUST either change this
# to 'vlan' and configure network_vlan_ranges below or change this to
# 'gre' and configure tunnel_id_ranges below in order for tenant
# networks to provide connectivity between hosts. Set to 'none' to
# disable creation of tenant networks.
# 'gre' or 'vxlan' and configure tunnel_id_ranges below in order for
# tenant networks to provide connectivity between hosts. Set to 'none'
# to disable creation of tenant networks.
#
# tenant_network_type = local
# Example: tenant_network_type = gre
# Example: tenant_network_type = vxlan
# (ListOpt) Comma-separated list of
# <physical_network>[:<vlan_min>:<vlan_max>] tuples enumerating ranges
@ -45,20 +46,20 @@ reconnect_interval = 2
# allocation. All physical networks listed are available for flat and
# VLAN provider network creation. Specified ranges of VLAN IDs are
# available for tenant network allocation if tenant_network_type is
# 'vlan'. If empty, only gre and local networks may be created.
# 'vlan'. If empty, only gre, vxlan and local networks may be created.
#
# network_vlan_ranges =
# Example: network_vlan_ranges = physnet1:1000:2999
# (BoolOpt) Set to True in the server and the agents to enable support
# for GRE networks. Requires kernel support for OVS patch ports and
# GRE tunneling.
# for GRE or VXLAN networks. Requires kernel support for OVS patch ports and
# GRE or VXLAN tunneling.
#
# enable_tunneling = False
# (ListOpt) Comma-separated list of <tun_min>:<tun_max> tuples
# enumerating ranges of GRE tunnel IDs that are available for tenant
# network allocation if tenant_network_type is 'gre'.
# enumerating ranges of GRE or VXLAN tunnel IDs that are available for
# tenant network allocation if tenant_network_type is 'gre' or 'vxlan'.
#
# tunnel_id_ranges =
# Example: tunnel_id_ranges = 1:1000
@ -103,6 +104,21 @@ reconnect_interval = 2
# Agent's polling interval in seconds
# polling_interval = 2
# (StrOpt) The type of tenant network tunnels to utilize when tunneling
# is enabled. This can be set to either 'gre' or 'vxlan' currently. If
# this is unset, it will default to 'None'.
#
# tunnel_type =
# Example: tunnel_type = gre
# Example: tunnel_type = vxlan
# (IntOpt) The port number to utilize if tunnel_type is 'vxlan'. By default,
# this will make use of the Open vSwitch default value of '4789' if not
# specified.
#
# vxlan_udp_port =
# Example: vxlan_udp_port = 8472
[SECURITYGROUP]
# Firewall driver for realizing quantum security group function.
# firewall_driver = quantum.agent.firewall.NoopFirewallDriver

View File

@ -23,6 +23,7 @@ import re
from quantum.agent.linux import ip_lib
from quantum.agent.linux import utils
from quantum.openstack.common import log as logging
from quantum.plugins.openvswitch.common import constants
LOG = logging.getLogger(__name__)
@ -163,9 +164,17 @@ class OVSBridge:
flow_str = ",".join(flow_expr_arr)
self.run_ofctl("del-flows", [flow_str])
def add_tunnel_port(self, port_name, remote_ip):
def add_tunnel_port(self, port_name, remote_ip,
tunnel_type=constants.TYPE_GRE,
vxlan_udp_port=constants.VXLAN_UDP_PORT):
self.run_vsctl(["add-port", self.br_name, port_name])
self.set_db_attribute("Interface", port_name, "type", "gre")
self.set_db_attribute("Interface", port_name, "type", tunnel_type)
if tunnel_type == constants.TYPE_VXLAN:
# Only set the VXLAN UDP port if it's not the default
if vxlan_udp_port != constants.VXLAN_UDP_PORT:
self.set_db_attribute("Interface", port_name,
"options:dst_port",
vxlan_udp_port)
self.set_db_attribute("Interface", port_name, "options:remote_ip",
remote_ip)
self.set_db_attribute("Interface", port_name, "options:in_key", "flow")
@ -310,3 +319,25 @@ def get_bridges(root_helper):
except Exception as e:
LOG.exception(_("Unable to retrieve bridges. Exception: %s"), e)
return []
def get_installed_ovs_usr_version(root_helper):
args = ["ovs-vsctl", "--version"]
try:
cmd = utils.execute(args, root_helper=root_helper)
ver = re.findall("\d+\.\d+", cmd)[0]
return ver
except Exception:
LOG.exception(_("Unable to retrieve OVS userspace version."))
def get_installed_ovs_klm_version():
args = ["modinfo", "openvswitch"]
try:
cmd = utils.execute(args)
for line in cmd.split('\n'):
if 'version: ' in line and not 'srcversion' in line:
ver = re.findall("\d+\.\d+", line)
return ver[0]
except Exception:
LOG.exception(_("Unable to retrieve OVS kernel module version."))

View File

@ -19,7 +19,10 @@
# @author: Dan Wendlandt, Nicira Networks, Inc.
# @author: Dave Lapsley, Nicira Networks, Inc.
# @author: Aaron Rosen, Nicira Networks, Inc.
# @author: Seetharama Ayyadevara, Freescale Semiconductor, Inc.
# @author: Kyle Mestery, Cisco Systems, Inc.
import distutils.version as dist_version
import sys
import time
@ -146,7 +149,7 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
def __init__(self, integ_br, tun_br, local_ip,
bridge_mappings, root_helper,
polling_interval, enable_tunneling):
polling_interval, tunnel_type=constants.TYPE_NONE):
'''Constructor.
:param integ_br: name of the integration bridge.
@ -155,7 +158,8 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
:param bridge_mappings: mappings from physical network name to bridge.
:param root_helper: utility to use when running shell cmds.
:param polling_interval: interval (secs) to poll DB.
:param enable_tunneling: if True enable GRE networks.
:param tunnel_type: Either gre or vxlan. If set, will automatically
set enable_tunneling to True.
'''
self.root_helper = root_helper
self.available_local_vlans = set(xrange(q_const.MIN_VLAN_TAG,
@ -166,9 +170,15 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
self.polling_interval = polling_interval
self.enable_tunneling = enable_tunneling
if tunnel_type in constants.TUNNEL_NETWORK_TYPES:
self.enable_tunneling = True
else:
self.enable_tunneling = False
self.local_ip = local_ip
self.tunnel_count = 0
self.tunnel_type = tunnel_type
self.vxlan_udp_port = cfg.CONF.AGENT.vxlan_udp_port
self._check_ovs_version()
if self.enable_tunneling:
self.setup_tunnel_br(tun_br)
self.agent_state = {
@ -177,6 +187,7 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
'topic': q_const.L2_AGENT_TOPIC,
'configurations': bridge_mappings,
'agent_type': q_const.AGENT_TYPE_OVS,
'tunnel_type': self.tunnel_type,
'start_flag': True}
self.setup_rpc()
@ -185,6 +196,11 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
self.plugin_rpc,
root_helper)
def _check_ovs_version(self):
if self.enable_tunneling and self.tunnel_type == constants.TYPE_VXLAN:
check_ovs_version(constants.MINIMUM_OVS_VXLAN_VERSION,
self.root_helper)
def _report_state(self):
try:
# How many devices are likely used by a VM
@ -274,8 +290,9 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
tunnel_id = kwargs.get('tunnel_id')
if tunnel_ip == self.local_ip:
return
tun_name = 'gre-%s' % tunnel_id
self.tun_br.add_tunnel_port(tun_name, tunnel_ip)
tun_name = '%s-%s' % (self.tunnel_type, tunnel_id)
self.tun_br.add_tunnel_port(tun_name, tunnel_ip, self.tunnel_type,
self.vxlan_udp_port)
def create_rpc_dispatcher(self):
'''Get the rpc dispatcher for this manager.
@ -290,7 +307,8 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
'''Provisions a local VLAN.
:param net_uuid: the uuid of the network associated with this vlan.
:param network_type: the network type ('gre', 'vlan', 'flat', 'local')
:param network_type: the network type ('gre', 'vxlan', 'vlan', 'flat',
'local')
:param physical_network: the physical network for 'vlan' or 'flat'
:param segmentation_id: the VID for 'vlan' or tunnel ID for 'tunnel'
'''
@ -306,7 +324,7 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
physical_network,
segmentation_id)
if network_type == constants.TYPE_GRE:
if network_type in constants.TUNNEL_NETWORK_TYPES:
if self.enable_tunneling:
# outbound
self.tun_br.add_flow(priority=4, in_port=self.patch_int_ofport,
@ -321,8 +339,10 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
actions="mod_vlan_vid:%s,output:%s" %
(lvid, self.patch_int_ofport))
else:
LOG.error(_("Cannot provision GRE network for net-id=%s "
"- tunneling disabled"), net_uuid)
LOG.error(_("Cannot provision %(network_type)s network for "
"net-id=%(net_uuid)s - tunneling disabled"),
{'network_type': network_type,
'net_uuid': net_uuid})
elif network_type == constants.TYPE_FLAT:
if physical_network in self.phys_brs:
# outbound
@ -383,7 +403,7 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
{'vlan_id': lvm.vlan,
'net_uuid': net_uuid})
if lvm.network_type == constants.TYPE_GRE:
if lvm.network_type in constants.TUNNEL_NETWORK_TYPES:
if self.enable_tunneling:
self.tun_br.delete_flows(tun_id=lvm.segmentation_id)
self.tun_br.delete_flows(dl_vlan=lvm.vlan)
@ -438,7 +458,7 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
lvm = self.local_vlan_map[net_uuid]
lvm.vif_ports[port.vif_id] = port
if network_type == constants.TYPE_GRE:
if network_type in constants.TUNNEL_NETWORK_TYPES:
if self.enable_tunneling:
# inbound unicast
self.tun_br.add_flow(priority=3, tun_id=segmentation_id,
@ -471,7 +491,8 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
vif_port = lvm.vif_ports.pop(vif_id, None)
if vif_port:
if self.enable_tunneling and lvm.network_type == 'gre':
if self.enable_tunneling and lvm.network_type in (
constants.TUNNEL_NETWORK_TYPES):
# remove inbound unicast flow
self.tun_br.delete_flows(tun_id=lvm.segmentation_id,
dl_dst=vif_port.vif_mac)
@ -674,8 +695,10 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
tunnels = details['tunnels']
for tunnel in tunnels:
if self.local_ip != tunnel['ip_address']:
tun_name = 'gre-%s' % tunnel['id']
self.tun_br.add_tunnel_port(tun_name, tunnel['ip_address'])
tun_name = '%s-%s' % (self.tunnel_type, tunnel['id'])
self.tun_br.add_tunnel_port(tun_name, tunnel['ip_address'],
self.tunnel_type,
self.vxlan_udp_port)
except Exception as e:
LOG.debug(_("Unable to sync tunnel IP %(local_ip)s: %(e)s"),
{'local_ip': self.local_ip, 'e': e})
@ -728,6 +751,44 @@ class OVSQuantumAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
self.rpc_loop()
def check_ovs_version(min_required_version, root_helper):
LOG.debug(_("Checking OVS version for VXLAN support"))
installed_klm_version = ovs_lib.get_installed_ovs_klm_version()
installed_usr_version = ovs_lib.get_installed_ovs_usr_version(root_helper)
# First check the userspace version
if installed_usr_version:
if dist_version.StrictVersion(
installed_usr_version) < dist_version.StrictVersion(
min_required_version):
LOG.error(_('Failed userspace version check for Open '
'vSwitch with VXLAN support. To use '
'VXLAN tunnels with OVS, please ensure '
'the OVS version is %s '
'or newer!'), min_required_version)
sys.exit(1)
# Now check the kernel version
if installed_klm_version:
if dist_version.StrictVersion(
installed_klm_version) < dist_version.StrictVersion(
min_required_version):
LOG.error(_('Failed kernel version check for Open '
'vSwitch with VXLAN support. To use '
'VXLAN tunnels with OVS, please ensure '
'the OVS version is %s or newer!'),
min_required_version)
sys.exti(1)
else:
LOG.warning(_('Cannot determine kernel Open vSwitch version, '
'please ensure your Open vSwitch kernel module '
'is at least version %s to support VXLAN '
'tunnels.'), min_required_version)
else:
LOG.warning(_('Unable to determine Open vSwitch version. Please '
'ensure that its version is %s or newer to use VXLAN '
'tunnels with OVS.'), min_required_version)
sys.exit(1)
def create_agent_config_map(config):
"""Create a map of agent config parameters.
@ -746,11 +807,12 @@ def create_agent_config_map(config):
bridge_mappings=bridge_mappings,
root_helper=config.AGENT.root_helper,
polling_interval=config.AGENT.polling_interval,
enable_tunneling=config.OVS.enable_tunneling,
tunnel_type=config.AGENT.tunnel_type,
)
if kwargs['enable_tunneling'] and not kwargs['local_ip']:
msg = _('Tunnelling cannot be enabled without a valid local_ip.')
if kwargs['tunnel_type'] in constants.TUNNEL_NETWORK_TYPES:
if not kwargs['local_ip']:
msg = _('Tunneling cannot be enabled without a valid local_ip.')
raise ValueError(msg)
return kwargs

View File

@ -17,6 +17,7 @@
from oslo.config import cfg
from quantum.agent.common import config
from quantum.plugins.openvswitch.common import constants
from quantum import scheduler
@ -44,7 +45,7 @@ ovs_opts = [
help=_("List of <physical_network>:<bridge>")),
cfg.StrOpt('tenant_network_type', default='local',
help=_("Network type for tenant networks "
"(local, vlan, gre, or none)")),
"(local, vlan, gre, vxlan, or none)")),
cfg.ListOpt('network_vlan_ranges',
default=DEFAULT_VLAN_RANGES,
help=_("List of <physical_network>:<vlan_min>:<vlan_max> "
@ -58,6 +59,11 @@ agent_opts = [
cfg.IntOpt('polling_interval', default=2,
help=_("The number of seconds the agent will wait between "
"polling for local device changes.")),
cfg.StrOpt('tunnel_type', default=None,
help=_("Network type for agent tunnel networks "
"(gre or vxlan)")),
cfg.IntOpt('vxlan_udp_port', default=constants.VXLAN_UDP_PORT,
help=_("The UDP port to use for VXLAN tunnels.")),
]

View File

@ -24,9 +24,17 @@ TYPE_FLAT = 'flat'
TYPE_VLAN = 'vlan'
TYPE_GRE = 'gre'
TYPE_LOCAL = 'local'
TYPE_VXLAN = 'vxlan'
TYPE_NONE = 'none'
VXLAN_UDP_PORT = 4789
# Name prefixes for veth device pair linking the integration bridge
# with the physical bridge for a physical network
VETH_INTEGRATION_PREFIX = 'int-'
VETH_PHYSICAL_PREFIX = 'phy-'
# The minimum version of OVS which supports VXLAN tunneling
MINIMUM_OVS_VXLAN_VERSION = "1.10"
# The different types of tunnels
TUNNEL_NETWORK_TYPES = [TYPE_GRE, TYPE_VXLAN]

View File

@ -19,6 +19,7 @@
# @author: Dave Lapsley, Nicira Networks, Inc.
# @author: Aaron Rosen, Nicira Networks, Inc.
# @author: Bob Kukura, Red Hat, Inc.
# @author: Seetharama Ayyadevara, Freescale Semiconductor, Inc.
import sys
@ -222,7 +223,7 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
"""Implement the Quantum abstractions using Open vSwitch.
Depending on whether tunneling is enabled, either a GRE tunnel or
Depending on whether tunneling is enabled, either a GRE, VXLAN tunnel or
a new VLAN is created for each network. An agent is relied upon to
perform the actual OVS configuration on each host.
@ -269,9 +270,10 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
if self.tenant_network_type not in [constants.TYPE_LOCAL,
constants.TYPE_VLAN,
constants.TYPE_GRE,
constants.TYPE_VXLAN,
constants.TYPE_NONE]:
LOG.error(_("Invalid tenant_network_type: %s. "
"Agent terminated!"),
"Server terminated!"),
self.tenant_network_type)
sys.exit(1)
self.enable_tunneling = cfg.CONF.OVS.enable_tunneling
@ -279,9 +281,9 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
if self.enable_tunneling:
self._parse_tunnel_id_ranges()
ovs_db_v2.sync_tunnel_allocations(self.tunnel_id_ranges)
elif self.tenant_network_type == constants.TYPE_GRE:
LOG.error(_("Tunneling disabled but tenant_network_type is 'gre'. "
"Agent terminated!"))
elif self.tenant_network_type in constants.TUNNEL_NETWORK_TYPES:
LOG.error(_("Tunneling disabled but tenant_network_type is '%s'. "
"Server terminated!"), self.tenant_network_type)
sys.exit(1)
self.setup_rpc()
self.network_scheduler = importutils.import_object(
@ -308,7 +310,7 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
self.network_vlan_ranges = plugin_utils.parse_network_vlan_ranges(
cfg.CONF.OVS.network_vlan_ranges)
except Exception as ex:
LOG.error(_("%s. Agent terminated!"), ex)
LOG.error(_("%s. Server terminated!"), ex)
sys.exit(1)
LOG.info(_("Network VLAN ranges: %s"), self.network_vlan_ranges)
@ -320,7 +322,7 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
self.tunnel_id_ranges.append((int(tun_min), int(tun_max)))
except ValueError as ex:
LOG.error(_("Invalid tunnel ID range: "
"'%(range)s' - %(e)s. Agent terminated!"),
"'%(range)s' - %(e)s. Server terminated!"),
{'range': entry, 'e': ex})
sys.exit(1)
LOG.info(_("Tunnel ID ranges: %s"), self.tunnel_id_ranges)
@ -329,7 +331,7 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
binding = ovs_db_v2.get_network_binding(context.session,
network['id'])
network[provider.NETWORK_TYPE] = binding.network_type
if binding.network_type == constants.TYPE_GRE:
if binding.network_type in constants.TUNNEL_NETWORK_TYPES:
network[provider.PHYSICAL_NETWORK] = None
network[provider.SEGMENTATION_ID] = binding.segmentation_id
elif binding.network_type == constants.TYPE_FLAT:
@ -374,13 +376,13 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
{'min_id': q_const.MIN_VLAN_TAG,
'max_id': q_const.MAX_VLAN_TAG})
raise q_exc.InvalidInput(error_message=msg)
elif network_type == constants.TYPE_GRE:
elif network_type in constants.TUNNEL_NETWORK_TYPES:
if not self.enable_tunneling:
msg = _("GRE networks are not enabled")
msg = _("%s networks are not enabled") % network_type
raise q_exc.InvalidInput(error_message=msg)
if physical_network_set:
msg = _("provider:physical_network specified for GRE "
"network")
msg = _("provider:physical_network specified for %s "
"network") % network_type
raise q_exc.InvalidInput(error_message=msg)
else:
physical_network = None
@ -454,7 +456,7 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
elif network_type == constants.TYPE_VLAN:
(physical_network,
segmentation_id) = ovs_db_v2.reserve_vlan(session)
elif network_type == constants.TYPE_GRE:
elif network_type in constants.TUNNEL_NETWORK_TYPES:
segmentation_id = ovs_db_v2.reserve_tunnel(session)
# no reservation needed for TYPE_LOCAL
else:
@ -462,7 +464,7 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
if network_type in [constants.TYPE_VLAN, constants.TYPE_FLAT]:
ovs_db_v2.reserve_specific_vlan(session, physical_network,
segmentation_id)
elif network_type == constants.TYPE_GRE:
elif network_type in constants.TUNNEL_NETWORK_TYPES:
ovs_db_v2.reserve_specific_tunnel(session, segmentation_id)
# no reservation needed for TYPE_LOCAL
net = super(OVSQuantumPluginV2, self).create_network(context,
@ -494,7 +496,7 @@ class OVSQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
with session.begin(subtransactions=True):
binding = ovs_db_v2.get_network_binding(session, id)
super(OVSQuantumPluginV2, self).delete_network(context, id)
if binding.network_type == constants.TYPE_GRE:
if binding.network_type in constants.TUNNEL_NETWORK_TYPES:
ovs_db_v2.release_tunnel(session, binding.segmentation_id,
self.tunnel_id_ranges)
elif binding.network_type in [constants.TYPE_VLAN,

View File

@ -25,6 +25,7 @@ from quantum.agent.linux import ip_lib
from quantum.agent.linux import ovs_lib
from quantum.openstack.common.rpc import common as rpc_common
from quantum.plugins.openvswitch.agent import ovs_quantum_agent
from quantum.plugins.openvswitch.common import constants
from quantum.tests import base
@ -41,6 +42,7 @@ class CreateAgentConfigMap(base.BaseTestCase):
self.addCleanup(cfg.CONF.reset)
# An ip address is required for tunneling but there is no default
cfg.CONF.set_override('enable_tunneling', True, group='OVS')
cfg.CONF.set_override('tunnel_type', 'gre', group='AGENT')
with testtools.ExpectedException(ValueError):
ovs_quantum_agent.create_agent_config_map(cfg.CONF)
@ -310,3 +312,43 @@ class TestOvsQuantumAgent(base.BaseTestCase):
lvm.vif_ports = {"vif1": mock.Mock()}
self.agent.port_unbound("vif3", "netuid12345")
self.assertEqual(reclvl_fn.call_count, 2)
def _check_ovs_vxlan_version(self, installed_version, min_vers,
expecting_ok):
with mock.patch(
'quantum.agent.linux.ovs_lib.get_installed_ovs_klm_version'
) as klm_cmd:
with mock.patch(
'quantum.agent.linux.ovs_lib.get_installed_ovs_usr_version'
) as usr_cmd:
try:
klm_cmd.return_value = installed_version
usr_cmd.return_value = installed_version
self.agent.tunnel_type = 'vxlan'
ovs_quantum_agent.check_ovs_version(min_vers,
root_helper='sudo')
version_ok = True
except SystemExit as e:
self.assertEquals(e.code, 1)
version_ok = False
self.assertEqual(version_ok, expecting_ok)
def test_check_minimum_version(self):
self._check_ovs_vxlan_version('1.10',
constants.MINIMUM_OVS_VXLAN_VERSION,
expecting_ok=True)
def test_check_future_version(self):
self._check_ovs_vxlan_version('1.11',
constants.MINIMUM_OVS_VXLAN_VERSION,
expecting_ok=True)
def test_check_fail_version(self):
self._check_ovs_vxlan_version('1.9',
constants.MINIMUM_OVS_VXLAN_VERSION,
expecting_ok=False)
def test_check_fail_no_version(self):
self._check_ovs_vxlan_version(None,
constants.MINIMUM_OVS_VXLAN_VERSION,
expecting_ok=False)

View File

@ -129,7 +129,19 @@ class TunnelTest(base.BaseTestCase):
ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
self.mox.VerifyAll()
def testConstructVXLAN(self):
self.mox.StubOutWithMock(ovs_lib, 'get_installed_ovs_klm_version')
ovs_lib.get_installed_ovs_klm_version().AndReturn("1.10")
self.mox.StubOutWithMock(ovs_lib, 'get_installed_ovs_usr_version')
ovs_lib.get_installed_ovs_usr_version('sudo').AndReturn("1.10")
self.mox.ReplayAll()
ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, 'vxlan')
self.mox.VerifyAll()
def testProvisionLocalVlan(self):
@ -146,7 +158,7 @@ class TunnelTest(base.BaseTestCase):
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.available_local_vlans = set([LV_ID])
a.provision_local_vlan(NET_UUID, constants.TYPE_GRE, None, LS_ID)
self.mox.VerifyAll()
@ -166,7 +178,7 @@ class TunnelTest(base.BaseTestCase):
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.available_local_vlans = set([LV_ID])
a.phys_brs['net1'] = self.mock_map_tun_bridge
a.phys_ofports['net1'] = self.MAP_TUN_OFPORT
@ -179,7 +191,7 @@ class TunnelTest(base.BaseTestCase):
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.provision_local_vlan(NET_UUID, constants.TYPE_FLAT, 'net2', LS_ID)
self.mox.VerifyAll()
@ -197,7 +209,7 @@ class TunnelTest(base.BaseTestCase):
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.available_local_vlans = set([LV_ID])
a.phys_brs['net1'] = self.mock_map_tun_bridge
a.phys_ofports['net1'] = self.MAP_TUN_OFPORT
@ -210,7 +222,7 @@ class TunnelTest(base.BaseTestCase):
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.provision_local_vlan(NET_UUID, constants.TYPE_VLAN, 'net2', LS_ID)
self.mox.VerifyAll()
@ -223,7 +235,7 @@ class TunnelTest(base.BaseTestCase):
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.available_local_vlans = set()
a.local_vlan_map[NET_UUID] = LVM
a.reclaim_local_vlan(NET_UUID, LVM)
@ -241,7 +253,7 @@ class TunnelTest(base.BaseTestCase):
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.phys_brs['net1'] = self.mock_map_tun_bridge
a.phys_ofports['net1'] = self.MAP_TUN_OFPORT
a.int_ofports['net1'] = self.INT_OFPORT
@ -263,7 +275,7 @@ class TunnelTest(base.BaseTestCase):
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.phys_brs['net1'] = self.mock_map_tun_bridge
a.phys_ofports['net1'] = self.MAP_TUN_OFPORT
a.int_ofports['net1'] = self.INT_OFPORT
@ -288,7 +300,7 @@ class TunnelTest(base.BaseTestCase):
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.local_vlan_map[NET_UUID] = LVM
a.port_bound(VIF_PORT, NET_UUID, 'gre', None, LS_ID)
self.mox.VerifyAll()
@ -308,7 +320,7 @@ class TunnelTest(base.BaseTestCase):
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.local_vlan_map[NET_UUID] = LVM
a.port_bound(VIF_PORT, NET_UUID, 'gre', None, LS_ID)
a.available_local_vlans = set([LV_ID])
@ -327,19 +339,19 @@ class TunnelTest(base.BaseTestCase):
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.available_local_vlans = set([LV_ID])
a.local_vlan_map[NET_UUID] = LVM
a.port_dead(VIF_PORT)
self.mox.VerifyAll()
def testTunnelUpdate(self):
self.mock_tun_bridge.add_tunnel_port('gre-1', '10.0.10.1')
self.mock_tun_bridge.add_tunnel_port('gre-1', '10.0.10.1', 'gre', 4789)
self.mox.ReplayAll()
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.tunnel_update(
mox.MockAnything, tunnel_id='1', tunnel_ip='10.0.10.1')
self.mox.VerifyAll()
@ -349,7 +361,7 @@ class TunnelTest(base.BaseTestCase):
a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
a.tunnel_update(
mox.MockAnything, tunnel_id='1', tunnel_ip='10.0.0.1')
self.mox.VerifyAll()
@ -389,7 +401,7 @@ class TunnelTest(base.BaseTestCase):
self.TUN_BRIDGE,
'10.0.0.1',
self.NET_MAPPING,
'sudo', 2, True)
'sudo', 2, 'gre')
# Hack to test loop
# We start method and expect it will raise after 2nd loop