Change tenant network type usage for IB Fabric

This patch changes tenant network type usage for InfiniBand Fabric
to vlan type. Add the indication of Fabric Type (Ethernet/InfiniBand)
to the provider_network via the plugin configuration file.
If physical network type is not specified for some provider network
listed in the network_vlan_ranges, use default physical network type.

Co-authored-by: Roey Chen <roeyc@mellanox.com>
Change-Id: Id45acfb8234359a43303c2eee2205a44998c039a
Closes-Bug: 1263638
This commit is contained in:
Irena Berezovsky 2014-01-16 14:28:01 +02:00
parent 4f6c33439b
commit 989246779d
7 changed files with 165 additions and 27 deletions

View File

@ -18,6 +18,21 @@
# network_vlan_ranges = # network_vlan_ranges =
# Example: network_vlan_ranges = default:1:100 # Example: network_vlan_ranges = default:1:100
# (ListOpt) Comma-separated list of
# <physical_network>:<physical_network_type> tuples mapping physical
# network names to physical network types. All physical
# networks listed in network_vlan_ranges should have
# mappings to appropriate physical network type.
# Type of the physical network can be either eth (Ethernet) or
# ib (InfiniBand). If empty, physical network eth type is assumed.
#
# physical_network_type_mappings =
# Example: physical_network_type_mappings = default:eth
# (StrOpt) Type of the physical network, can be either 'eth' or 'ib'
# The default value is 'eth'
# physical_network_type = eth
[eswitch] [eswitch]
# (ListOpt) Comma-separated list of # (ListOpt) Comma-separated list of
# <physical_network>:<physical_interface> tuples mapping physical # <physical_network>:<physical_interface> tuples mapping physical

View File

@ -37,7 +37,6 @@ from neutron.openstack.common.rpc import dispatcher
from neutron.plugins.common import constants as p_const from neutron.plugins.common import constants as p_const
from neutron.plugins.mlnx.agent import utils from neutron.plugins.mlnx.agent import utils
from neutron.plugins.mlnx.common import config # noqa from neutron.plugins.mlnx.common import config # noqa
from neutron.plugins.mlnx.common import constants
from neutron.plugins.mlnx.common import exceptions from neutron.plugins.mlnx.common import exceptions
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -103,8 +102,7 @@ class EswitchManager(object):
net_map = self.network_map[network_id] net_map = self.network_map[network_id]
net_map['ports'].append({'port_id': port_id, 'port_mac': port_mac}) net_map['ports'].append({'port_id': port_id, 'port_mac': port_mac})
if network_type in (p_const.TYPE_VLAN, if network_type == p_const.TYPE_VLAN:
constants.TYPE_IB):
LOG.info(_('Binding Segmentation ID %(seg_id)s' LOG.info(_('Binding Segmentation ID %(seg_id)s'
'to eSwitch for vNIC mac_address %(mac)s'), 'to eSwitch for vNIC mac_address %(mac)s'),
{'seg_id': seg_id, {'seg_id': seg_id,
@ -132,8 +130,6 @@ class EswitchManager(object):
LOG.info(_("Provisioning network %s"), network_id) LOG.info(_("Provisioning network %s"), network_id)
if network_type == p_const.TYPE_VLAN: if network_type == p_const.TYPE_VLAN:
LOG.debug(_("Creating VLAN Network")) LOG.debug(_("Creating VLAN Network"))
elif network_type == constants.TYPE_IB:
LOG.debug(_("Creating IB Network"))
else: else:
LOG.error(_("Unknown network type %(network_type)s " LOG.error(_("Unknown network type %(network_type)s "
"for network %(network_id)s"), "for network %(network_id)s"),

View File

@ -26,11 +26,18 @@ DEFAULT_INTERFACE_MAPPINGS = []
vlan_opts = [ vlan_opts = [
cfg.StrOpt('tenant_network_type', default='vlan', cfg.StrOpt('tenant_network_type', default='vlan',
help=_("Network type for tenant networks " help=_("Network type for tenant networks "
"(local, ib, vlan, or none)")), "(local, vlan, or none)")),
cfg.ListOpt('network_vlan_ranges', cfg.ListOpt('network_vlan_ranges',
default=DEFAULT_VLAN_RANGES, default=DEFAULT_VLAN_RANGES,
help=_("List of <physical_network>:<vlan_min>:<vlan_max> " help=_("List of <physical_network>:<vlan_min>:<vlan_max> "
"or <physical_network>")), "or <physical_network>")),
cfg.ListOpt('physical_network_type_mappings',
default=[],
help=_("List of <physical_network>:<physical_network_type> "
" with physical_network_type is either eth or ib")),
cfg.StrOpt('physical_network_type', default='eth',
help=_("Physical network type for provider network "
"(eth or ib)"))
] ]

View File

@ -18,8 +18,9 @@
LOCAL_VLAN_ID = -2 LOCAL_VLAN_ID = -2
FLAT_VLAN_ID = -1 FLAT_VLAN_ID = -1
# Values for network_type # Values for physical network_type
TYPE_IB = 'ib' TYPE_IB = 'ib'
TYPE_ETH = 'eth'
VIF_TYPE_DIRECT = 'mlnx_direct' VIF_TYPE_DIRECT = 'mlnx_direct'
VIF_TYPE_HOSTDEV = 'hostdev' VIF_TYPE_HOSTDEV = 'hostdev'

View File

@ -96,7 +96,7 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
def __init__(self): def __init__(self):
"""Start Mellanox Neutron Plugin.""" """Start Mellanox Neutron Plugin."""
super(MellanoxEswitchPlugin, self).__init__() super(MellanoxEswitchPlugin, self).__init__()
self._parse_network_vlan_ranges() self._parse_network_config()
db.sync_network_states(self.network_vlan_ranges) db.sync_network_states(self.network_vlan_ranges)
self._set_tenant_network_type() self._set_tenant_network_type()
self.vnic_type = cfg.CONF.ESWITCH.vnic_type self.vnic_type = cfg.CONF.ESWITCH.vnic_type
@ -133,6 +133,41 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
l3_rpc_agent_api.L3AgentNotify l3_rpc_agent_api.L3AgentNotify
) )
def _parse_network_config(self):
self._parse_physical_network_types()
self._parse_network_vlan_ranges()
for network in self.network_vlan_ranges.keys():
if not self.phys_network_type_maps.get(network):
self.phys_network_type_maps[network] = self.physical_net_type
def _parse_physical_network_types(self):
"""Parse physical network types configuration.
Verify default physical network type is valid.
Parse physical network mappings.
"""
self.physical_net_type = cfg.CONF.MLNX.physical_network_type
if self.physical_net_type not in (constants.TYPE_ETH,
constants.TYPE_IB):
LOG.error(_("Invalid physical network type %(type)s."
"Server terminated!"), {'type': self.physical_net_type})
raise SystemExit(1)
try:
self.phys_network_type_maps = utils.parse_mappings(
cfg.CONF.MLNX.physical_network_type_mappings)
except ValueError as e:
LOG.error(_("Parsing physical_network_type failed: %s."
" Server terminated!"), e)
raise SystemExit(1)
for network, type in self.phys_network_type_maps.iteritems():
if type not in (constants.TYPE_ETH, constants.TYPE_IB):
LOG.error(_("Invalid physical network type %(type)s "
" for network %(net)s. Server terminated!"),
{'net': network, 'type': type})
raise SystemExit(1)
LOG.info(_("Physical Network type mappings: %s"),
self.phys_network_type_maps)
def _parse_network_vlan_ranges(self): def _parse_network_vlan_ranges(self):
try: try:
self.network_vlan_ranges = plugin_utils.parse_network_vlan_ranges( self.network_vlan_ranges = plugin_utils.parse_network_vlan_ranges(
@ -142,14 +177,6 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
sys.exit(1) sys.exit(1)
LOG.info(_("Network VLAN ranges: %s"), self.network_vlan_ranges) LOG.info(_("Network VLAN ranges: %s"), self.network_vlan_ranges)
def _add_network_vlan_range(self, physical_network, vlan_min, vlan_max):
self._add_network(physical_network)
self.network_vlan_ranges[physical_network].append((vlan_min, vlan_max))
def _add_network(self, physical_network):
if physical_network not in self.network_vlan_ranges:
self.network_vlan_ranges[physical_network] = []
def _extend_network_dict_provider(self, context, network): def _extend_network_dict_provider(self, context, network):
binding = db.get_network_binding(context.session, network['id']) binding = db.get_network_binding(context.session, network['id'])
network[provider.NETWORK_TYPE] = binding.network_type network[provider.NETWORK_TYPE] = binding.network_type
@ -166,7 +193,6 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
def _set_tenant_network_type(self): def _set_tenant_network_type(self):
self.tenant_network_type = cfg.CONF.MLNX.tenant_network_type self.tenant_network_type = cfg.CONF.MLNX.tenant_network_type
if self.tenant_network_type not in [svc_constants.TYPE_VLAN, if self.tenant_network_type not in [svc_constants.TYPE_VLAN,
constants.TYPE_IB,
svc_constants.TYPE_LOCAL, svc_constants.TYPE_LOCAL,
svc_constants.TYPE_NONE]: svc_constants.TYPE_NONE]:
LOG.error(_("Invalid tenant_network_type: %s. " LOG.error(_("Invalid tenant_network_type: %s. "
@ -194,7 +220,7 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
self._process_flat_net(segmentation_id_set) self._process_flat_net(segmentation_id_set)
segmentation_id = constants.FLAT_VLAN_ID segmentation_id = constants.FLAT_VLAN_ID
elif network_type in [svc_constants.TYPE_VLAN, constants.TYPE_IB]: elif network_type == svc_constants.TYPE_VLAN:
self._process_vlan_net(segmentation_id, segmentation_id_set) self._process_vlan_net(segmentation_id, segmentation_id_set)
elif network_type == svc_constants.TYPE_LOCAL: elif network_type == svc_constants.TYPE_LOCAL:
@ -241,7 +267,6 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
physical_network, physical_network,
physical_network_set): physical_network_set):
if network_type in [svc_constants.TYPE_VLAN, if network_type in [svc_constants.TYPE_VLAN,
constants.TYPE_IB,
svc_constants.TYPE_FLAT]: svc_constants.TYPE_FLAT]:
if physical_network_set: if physical_network_set:
if physical_network not in self.network_vlan_ranges: if physical_network not in self.network_vlan_ranges:
@ -256,7 +281,10 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
return physical_network return physical_network
def _check_port_binding_for_net_type(self, vnic_type, net_type): def _check_port_binding_for_net_type(self, vnic_type, net_type):
if net_type == svc_constants.TYPE_VLAN: """
VIF_TYPE_DIRECT is valid only for Ethernet fabric
"""
if net_type == constants.TYPE_ETH:
return vnic_type in (constants.VIF_TYPE_DIRECT, return vnic_type in (constants.VIF_TYPE_DIRECT,
constants.VIF_TYPE_HOSTDEV) constants.VIF_TYPE_HOSTDEV)
elif net_type == constants.TYPE_IB: elif net_type == constants.TYPE_IB:
@ -269,22 +297,23 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
net_binding = db.get_network_binding(context.session, net_binding = db.get_network_binding(context.session,
attrs.get('network_id')) attrs.get('network_id'))
net_type = net_binding.network_type phy_net = net_binding.physical_network
if not binding_profile_set: if not binding_profile_set:
return self.vnic_type return self.vnic_type
if constants.VNIC_TYPE in binding_profile: if constants.VNIC_TYPE in binding_profile:
vnic_type = binding_profile[constants.VNIC_TYPE] vnic_type = binding_profile[constants.VNIC_TYPE]
phy_net_type = self.phys_network_type_maps[phy_net]
if vnic_type in (constants.VIF_TYPE_DIRECT, if vnic_type in (constants.VIF_TYPE_DIRECT,
constants.VIF_TYPE_HOSTDEV): constants.VIF_TYPE_HOSTDEV):
if self._check_port_binding_for_net_type(vnic_type, if self._check_port_binding_for_net_type(vnic_type,
net_type): phy_net_type):
self.base_binding_dict[portbindings.VIF_TYPE] = vnic_type self.base_binding_dict[portbindings.VIF_TYPE] = vnic_type
return vnic_type return vnic_type
else: else:
msg = (_("Unsupported vnic type %(vnic_type)s " msg = (_("Unsupported vnic type %(vnic_type)s "
"for network type %(net_type)s") % "for physical network type %(net_type)s") %
{'vnic_type': vnic_type, 'net_type': net_type}) {'vnic_type': vnic_type, 'net_type': phy_net_type})
else: else:
msg = _("Invalid vnic_type on port_create") msg = _("Invalid vnic_type on port_create")
else: else:
@ -307,15 +336,13 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
network_type = self.tenant_network_type network_type = self.tenant_network_type
if network_type == svc_constants.TYPE_NONE: if network_type == svc_constants.TYPE_NONE:
raise q_exc.TenantNetworksDisabled() raise q_exc.TenantNetworksDisabled()
elif network_type in [svc_constants.TYPE_VLAN, elif network_type == svc_constants.TYPE_VLAN:
constants.TYPE_IB]:
physical_network, vlan_id = db.reserve_network(session) physical_network, vlan_id = db.reserve_network(session)
else: # TYPE_LOCAL else: # TYPE_LOCAL
vlan_id = constants.LOCAL_VLAN_ID vlan_id = constants.LOCAL_VLAN_ID
else: else:
# provider network # provider network
if network_type in [svc_constants.TYPE_VLAN, if network_type in [svc_constants.TYPE_VLAN,
constants.TYPE_IB,
svc_constants.TYPE_FLAT]: svc_constants.TYPE_FLAT]:
db.reserve_specific_network(session, db.reserve_specific_network(session,
physical_network, physical_network,

View File

@ -29,6 +29,9 @@ class ConfigurationTest(base.BaseTestCase):
cfg.CONF.MLNX.tenant_network_type) cfg.CONF.MLNX.tenant_network_type)
self.assertEqual(1, self.assertEqual(1,
len(cfg.CONF.MLNX.network_vlan_ranges)) len(cfg.CONF.MLNX.network_vlan_ranges))
self.assertEqual('eth',
cfg.CONF.MLNX.physical_network_type)
self.assertFalse(cfg.CONF.MLNX.physical_network_type_mappings)
self.assertEqual(0, self.assertEqual(0,
len(cfg.CONF.ESWITCH. len(cfg.CONF.ESWITCH.
physical_interface_mappings)) physical_interface_mappings))

View File

@ -0,0 +1,89 @@
# Copyright (c) 2014 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import mock
from oslo.config import cfg
#NOTE this import loads tests required options
from neutron.plugins.mlnx.common import config # noqa
from neutron.plugins.mlnx.common import constants
from neutron.plugins.mlnx.mlnx_plugin import MellanoxEswitchPlugin
from neutron.tests import base
class TestMlnxPluginConfig(base.BaseTestCase):
expected_vlan_mappings = {'physnet1': [(1, 1000)],
'physnet2': [(1, 1000)]}
expected_network_types = {'physnet1': constants.TYPE_ETH,
'physnet2': constants.TYPE_IB}
config_vlan_ranges = ['physnet1:1:1000', 'physnet2:1:1000']
config_network_types = ['physnet1:eth', 'physnet2:ib']
def setUp(self):
super(TestMlnxPluginConfig, self).setUp()
cfg.CONF.set_override('rpc_backend',
'neutron.openstack.common.rpc.impl_fake')
cfg.CONF.set_override(group='MLNX',
name='network_vlan_ranges',
override=self.config_vlan_ranges)
def _create_mlnx_plugin(self):
with mock.patch('neutron.plugins.mlnx.db.mlnx_db_v2'):
return MellanoxEswitchPlugin()
def _assert_expected_config(self):
plugin = self._create_mlnx_plugin()
self.assertEqual(plugin.network_vlan_ranges,
self.expected_vlan_mappings)
self.assertEqual(plugin.phys_network_type_maps,
self.expected_network_types)
def test_vlan_ranges_with_network_type(self):
cfg.CONF.set_override(group='MLNX',
name='physical_network_type_mappings',
override=self.config_network_types)
self._assert_expected_config()
def test_vlan_ranges_partial_network_type(self):
cfg.CONF.set_override(group='MLNX',
name='physical_network_type_mappings',
override=self.config_network_types[:1])
cfg.CONF.set_override(group='MLNX',
name='physical_network_type',
override=constants.TYPE_IB)
self._assert_expected_config()
def test_vlan_ranges_no_network_type(self):
cfg.CONF.set_override(group='MLNX',
name='physical_network_type',
override=constants.TYPE_IB)
cfg.CONF.set_override(group='MLNX',
name='physical_network_type_mappings',
override=[])
self.expected_network_types.update({'physnet1': constants.TYPE_IB})
self._assert_expected_config()
self.expected_network_types.update({'physnet1': constants.TYPE_ETH})
def test_parse_physical_network_mappings_invalid_type(self):
cfg.CONF.set_override(group='MLNX',
name='physical_network_type_mappings',
override=['physnet:invalid-type'])
self.assertRaises(SystemExit, self._create_mlnx_plugin)
def test_invalid_network_type(self):
cfg.CONF.set_override(group='MLNX',
name='physical_network_type',
override='invalid-type')
self.assertRaises(SystemExit, self._create_mlnx_plugin)