# for GRE or VXLAN networks. Requires kernel support for OVS patch ports and
# GRE or VXLAN tunneling.
#
-# WARNING: This option will be deprecated in the Icehouse release, and will
-# be replaced by specifying one or more 'tunnel_types' in the
-# "agent" section of the configuration file below.
+# WARNING: This option will be deprecated in the Icehouse release, at which
+# point setting tunnel_type below will be required to enable
+# tunneling.
#
# enable_tunneling = False
+# (StrOpt) The type of tunnel network, if any, supported by the plugin. If
+# this is set, it will cause tunneling to be enabled. If this is not set and
+# the option enable_tunneling is set, this will default to 'gre'.
+#
+# tunnel_type =
+# Example: tunnel_type = gre
+# Example: tunnel_type = vxlan
+
# (ListOpt) Comma-separated list of <tun_min>:<tun_max> tuples
# enumerating ranges of GRE or VXLAN tunnel IDs that are available for
# tenant network allocation if tenant_network_type is 'gre' or 'vxlan'.
# 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'.
+# (ListOpt) The types of tenant network tunnels supported by the agent.
+# Setting this will enable tunneling support in the agent. This can be set to
+# either 'gre' or 'vxlan'. If this is unset, it will default to [] and
+# disable tunneling support in the agent. When running the agent with the OVS
+# plugin, this value must be the same as "tunnel_type" in the "[ovs]" section.
+# When running the agent with ML2, you can specify as many values here as
+# your compute hosts supports.
#
-# tunnel_type =
-# Example: tunnel_type = gre
-# Example: tunnel_type = vxlan
+# tunnel_types =
+# Example: tunnel_types = gre
+# Example: tunnel_types = vxlan
+# Example: tunnel_types = vxlan, gre
-# (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.
+# (IntOpt) The port number to utilize if tunnel_types includes '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
def __init__(self, integ_br, tun_br, local_ip,
bridge_mappings, root_helper,
- polling_interval, tunnel_type=constants.TYPE_NONE):
+ polling_interval, tunnel_types=None):
'''Constructor.
:param integ_br: name of the integration bridge.
: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 tunnel_type: Either gre or vxlan. If set, will automatically
- set enable_tunneling to True.
+ :param tunnel_types: A list of tunnel types to enable support for in
+ the agent. 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,
self.polling_interval = polling_interval
- if tunnel_type in constants.TUNNEL_NETWORK_TYPES:
+ if tunnel_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.tunnel_types = tunnel_types or []
self.vxlan_udp_port = cfg.CONF.AGENT.vxlan_udp_port
self._check_ovs_version()
if self.enable_tunneling:
'topic': q_const.L2_AGENT_TOPIC,
'configurations': bridge_mappings,
'agent_type': q_const.AGENT_TYPE_OVS,
- 'tunnel_type': self.tunnel_type,
+ 'tunnel_types': self.tunnel_types,
'start_flag': True}
self.setup_rpc()
root_helper)
def _check_ovs_version(self):
- if self.enable_tunneling and self.tunnel_type == constants.TYPE_VXLAN:
+ if constants.TYPE_VXLAN in self.tunnel_types:
check_ovs_version(constants.MINIMUM_OVS_VXLAN_VERSION,
self.root_helper)
return
tunnel_ip = kwargs.get('tunnel_ip')
tunnel_id = kwargs.get('tunnel_id')
+ tunnel_type = kwargs.get('tunnel_type')
+ if not tunnel_type:
+ LOG.error(_("No tunnel_type specified, cannot create tunnels"))
+ return
+ if tunnel_type not in self.tunnel_types:
+ LOG.error(_("tunnel_type %s not supported by agent"), tunnel_type)
+ return
if tunnel_ip == self.local_ip:
return
- tun_name = '%s-%s' % (self.tunnel_type, tunnel_id)
- self.tun_br.add_tunnel_port(tun_name, tunnel_ip, self.tunnel_type,
+ tun_name = '%s-%s' % (tunnel_type, tunnel_id)
+ self.tun_br.add_tunnel_port(tun_name, tunnel_ip, tunnel_type,
self.vxlan_udp_port)
def create_rpc_dispatcher(self):
tunnels = details['tunnels']
for tunnel in tunnels:
if self.local_ip != tunnel['ip_address']:
- tun_name = '%s-%s' % (self.tunnel_type, tunnel['id'])
+ tunnel_type = tunnel.get('tunnel_type')
+ if not tunnel_type:
+ LOG.error(_('No tunnel_type specified, cannot add '
+ 'tunnel port'))
+ return
+ tun_name = '%s-%s' % (tunnel_type, tunnel['id'])
self.tun_br.add_tunnel_port(tun_name, tunnel['ip_address'],
- self.tunnel_type,
+ tunnel_type,
self.vxlan_udp_port)
except Exception as e:
LOG.debug(_("Unable to sync tunnel IP %(local_ip)s: %(e)s"),
'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)
+ raise SystemExit(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)
+ raise SystemExit(1)
def create_agent_config_map(config):
bridge_mappings=bridge_mappings,
root_helper=config.AGENT.root_helper,
polling_interval=config.AGENT.polling_interval,
- tunnel_type=config.AGENT.tunnel_type,
+ tunnel_types=config.AGENT.tunnel_types,
)
# If enable_tunneling is TRUE, set tunnel_type to default to GRE
- if config.OVS.enable_tunneling and not kwargs['tunnel_type']:
- kwargs['tunnel_type'] = constants.TYPE_GRE
+ if config.OVS.enable_tunneling and not kwargs['tunnel_types']:
+ kwargs['tunnel_types'] = [constants.TYPE_GRE]
- if kwargs['tunnel_type'] in constants.TUNNEL_NETWORK_TYPES:
+ # Verify the tunnel_types specified are valid
+ for tun in kwargs['tunnel_types']:
+ if tun not in constants.TUNNEL_NETWORK_TYPES:
+ msg = _('Invalid tunnel type specificed: %s'), tun
+ raise ValueError(msg)
if not kwargs['local_ip']:
msg = _('Tunneling cannot be enabled without a valid local_ip.')
raise ValueError(msg)
DEFAULT_BRIDGE_MAPPINGS = []
DEFAULT_VLAN_RANGES = []
DEFAULT_TUNNEL_RANGES = []
+DEFAULT_TUNNEL_TYPES = []
ovs_opts = [
cfg.StrOpt('integration_bridge', default='br-int',
cfg.ListOpt('tunnel_id_ranges',
default=DEFAULT_TUNNEL_RANGES,
help=_("List of <tun_min>:<tun_max>")),
+ cfg.StrOpt('tunnel_type', default='',
+ help=_("The type of tunnels to use when utilizing tunnels, "
+ "either 'gre' or 'vxlan'")),
]
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.ListOpt('tunnel_types', default=DEFAULT_TUNNEL_TYPES,
+ help=_("Network types supported by the agent "
+ "(gre and/or vxlan)")),
cfg.IntOpt('vxlan_udp_port', default=constants.VXLAN_UDP_PORT,
help=_("The UDP port to use for VXLAN tunnels.")),
]
entry['tunnels'] = tunnels
# Notify all other listening agents
self.notifier.tunnel_update(rpc_context, tunnel.ip_address,
- tunnel.id)
+ tunnel.id, cfg.CONF.OVS.tunnel_type)
# Return the list of tunnels IP's to the agent
return entry
physical_network=physical_network),
topic=self.topic_port_update)
- def tunnel_update(self, context, tunnel_ip, tunnel_id):
+ def tunnel_update(self, context, tunnel_ip, tunnel_id, tunnel_type):
self.fanout_cast(context,
self.make_msg('tunnel_update',
tunnel_ip=tunnel_ip,
- tunnel_id=tunnel_id),
+ tunnel_id=tunnel_id,
+ tunnel_type=tunnel_type),
topic=self.topic_tunnel_update)
self.tenant_network_type)
sys.exit(1)
self.enable_tunneling = cfg.CONF.OVS.enable_tunneling
+ if self.enable_tunneling:
+ self.tunnel_type = cfg.CONF.OVS.tunnel_type or constants.TYPE_GRE
+ elif cfg.CONF.OVS.tunnel_type:
+ self.tunnel_type = cfg.CONF.OVS.tunnel_type
+ self.enable_tunneling = True
self.tunnel_id_ranges = []
if self.enable_tunneling:
self._parse_tunnel_id_ranges()
def test_create_agent_config_map_fails_for_invalid_tunnel_config(self):
self.addCleanup(cfg.CONF.reset)
- # An ip address is required for tunneling but there is no default
- cfg.CONF.set_override('tunnel_type', constants.TYPE_GRE,
+ # An ip address is required for tunneling but there is no default,
+ # verify this for both gre and vxlan tunnels.
+ cfg.CONF.set_override('tunnel_types', [constants.TYPE_GRE],
+ group='AGENT')
+ with testtools.ExpectedException(ValueError):
+ ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ cfg.CONF.set_override('tunnel_types', [constants.TYPE_VXLAN],
group='AGENT')
with testtools.ExpectedException(ValueError):
ovs_neutron_agent.create_agent_config_map(cfg.CONF)
def test_create_agent_config_map_enable_tunneling(self):
self.addCleanup(cfg.CONF.reset)
# Verify setting only enable_tunneling will default tunnel_type to GRE
- cfg.CONF.set_override('tunnel_type', None, group='AGENT')
+ cfg.CONF.set_override('tunnel_types', None, group='AGENT')
cfg.CONF.set_override('enable_tunneling', True, group='OVS')
cfg.CONF.set_override('local_ip', '10.10.10.10', group='OVS')
cfgmap = ovs_neutron_agent.create_agent_config_map(cfg.CONF)
- self.assertEqual(cfgmap['tunnel_type'], constants.TYPE_GRE)
+ self.assertEqual(cfgmap['tunnel_types'], [constants.TYPE_GRE])
def test_create_agent_config_map_fails_no_local_ip(self):
self.addCleanup(cfg.CONF.reset)
with testtools.ExpectedException(ValueError):
ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ def test_create_agent_config_map_fails_for_invalid_tunnel_type(self):
+ self.addCleanup(cfg.CONF.reset)
+ cfg.CONF.set_override('tunnel_types', ['foobar'], group='AGENT')
+ with testtools.ExpectedException(ValueError):
+ ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+
+ def test_create_agent_config_map_multiple_tunnel_types(self):
+ self.addCleanup(cfg.CONF.reset)
+ cfg.CONF.set_override('local_ip', '10.10.10.10', group='OVS')
+ cfg.CONF.set_override('tunnel_types', [constants.TYPE_GRE,
+ constants.TYPE_VXLAN], group='AGENT')
+ cfgmap = ovs_neutron_agent.create_agent_config_map(cfg.CONF)
+ self.assertEqual(cfgmap['tunnel_types'],
+ [constants.TYPE_GRE, constants.TYPE_VXLAN])
+
class TestOvsNeutronAgent(base.BaseTestCase):
self.agent.port_unbound("vif3", "netuid12345")
self.assertEqual(reclvl_fn.call_count, 2)
- def _check_ovs_vxlan_version(self, installed_version, min_vers,
+ def _check_ovs_vxlan_version(self, installed_usr_version,
+ installed_klm_version, min_vers,
expecting_ok):
with mock.patch(
'neutron.agent.linux.ovs_lib.get_installed_ovs_klm_version'
'neutron.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'
+ klm_cmd.return_value = installed_klm_version
+ usr_cmd.return_value = installed_usr_version
+ self.agent.tunnel_types = 'vxlan'
ovs_neutron_agent.check_ovs_version(min_vers,
root_helper='sudo')
version_ok = True
self.assertEqual(version_ok, expecting_ok)
def test_check_minimum_version(self):
- self._check_ovs_vxlan_version('1.10',
+ self._check_ovs_vxlan_version('1.10', '1.10',
constants.MINIMUM_OVS_VXLAN_VERSION,
expecting_ok=True)
def test_check_future_version(self):
- self._check_ovs_vxlan_version('1.11',
+ self._check_ovs_vxlan_version('1.11', '1.11',
constants.MINIMUM_OVS_VXLAN_VERSION,
expecting_ok=True)
def test_check_fail_version(self):
- self._check_ovs_vxlan_version('1.9',
+ self._check_ovs_vxlan_version('1.9', '1.9',
constants.MINIMUM_OVS_VXLAN_VERSION,
expecting_ok=False)
def test_check_fail_no_version(self):
- self._check_ovs_vxlan_version(None,
+ self._check_ovs_vxlan_version(None, None,
+ constants.MINIMUM_OVS_VXLAN_VERSION,
+ expecting_ok=False)
+
+ def test_check_fail_klm_version(self):
+ self._check_ovs_vxlan_version('1.10', '1.9',
constants.MINIMUM_OVS_VXLAN_VERSION,
expecting_ok=False)
constants.TUNNEL,
topics.UPDATE),
'tunnel_update', rpc_method='fanout_cast',
- tunnel_ip='fake_ip', tunnel_id='fake_id')
+ tunnel_ip='fake_ip', tunnel_id='fake_id',
+ tunnel_type=None)
def test_device_details(self):
rpcapi = agent_rpc.PluginApi(topics.PLUGIN)
ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ 'sudo', 2, ['gre'])
self.mox.VerifyAll()
def testConstructVXLAN(self):
ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'vxlan')
+ 'sudo', 2, ['vxlan'])
self.mox.VerifyAll()
def testProvisionLocalVlan(self):
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ '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()
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ '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
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ 'sudo', 2, ['gre'])
a.provision_local_vlan(NET_UUID, constants.TYPE_FLAT, 'net2', LS_ID)
self.mox.VerifyAll()
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ '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
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ 'sudo', 2, ['gre'])
a.provision_local_vlan(NET_UUID, constants.TYPE_VLAN, 'net2', LS_ID)
self.mox.VerifyAll()
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ 'sudo', 2, ['gre'])
a.available_local_vlans = set()
a.local_vlan_map[NET_UUID] = LVM
a.reclaim_local_vlan(NET_UUID, LVM)
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ '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
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ '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
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ 'sudo', 2, ['gre'])
a.local_vlan_map[NET_UUID] = LVM
a.port_bound(VIF_PORT, NET_UUID, 'gre', None, LS_ID)
self.mox.VerifyAll()
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ '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])
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ 'sudo', 2, ['gre'])
a.available_local_vlans = set([LV_ID])
a.local_vlan_map[NET_UUID] = LVM
a.port_dead(VIF_PORT)
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ 'sudo', 2, ['gre'])
a.tunnel_update(
- mox.MockAnything, tunnel_id='1', tunnel_ip='10.0.10.1')
+ mox.MockAnything, tunnel_id='1', tunnel_ip='10.0.10.1',
+ tunnel_type=constants.TYPE_GRE)
self.mox.VerifyAll()
def testTunnelUpdateSelf(self):
a = ovs_neutron_agent.OVSNeutronAgent(self.INT_BRIDGE,
self.TUN_BRIDGE,
'10.0.0.1', self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ 'sudo', 2, ['gre'])
a.tunnel_update(
mox.MockAnything, tunnel_id='1', tunnel_ip='10.0.0.1')
self.mox.VerifyAll()
self.TUN_BRIDGE,
'10.0.0.1',
self.NET_MAPPING,
- 'sudo', 2, 'gre')
+ 'sudo', 2, ['gre'])
# Hack to test loop
# We start method and expect it will raise after 2nd loop