From: Irena Berezovsky Date: Thu, 16 Jan 2014 12:28:01 +0000 (+0200) Subject: Change tenant network type usage for IB Fabric X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=989246779d991b0ff910eac71538b8b7731c5246;p=openstack-build%2Fneutron-build.git 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 Change-Id: Id45acfb8234359a43303c2eee2205a44998c039a Closes-Bug: 1263638 --- diff --git a/etc/neutron/plugins/mlnx/mlnx_conf.ini b/etc/neutron/plugins/mlnx/mlnx_conf.ini index 841947904..275b727c1 100644 --- a/etc/neutron/plugins/mlnx/mlnx_conf.ini +++ b/etc/neutron/plugins/mlnx/mlnx_conf.ini @@ -18,6 +18,21 @@ # network_vlan_ranges = # Example: network_vlan_ranges = default:1:100 +# (ListOpt) Comma-separated list of +# : 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] # (ListOpt) Comma-separated list of # : tuples mapping physical diff --git a/neutron/plugins/mlnx/agent/eswitch_neutron_agent.py b/neutron/plugins/mlnx/agent/eswitch_neutron_agent.py index 74ac21a10..d546dd5d5 100644 --- a/neutron/plugins/mlnx/agent/eswitch_neutron_agent.py +++ b/neutron/plugins/mlnx/agent/eswitch_neutron_agent.py @@ -37,7 +37,6 @@ from neutron.openstack.common.rpc import dispatcher from neutron.plugins.common import constants as p_const from neutron.plugins.mlnx.agent import utils from neutron.plugins.mlnx.common import config # noqa -from neutron.plugins.mlnx.common import constants from neutron.plugins.mlnx.common import exceptions LOG = logging.getLogger(__name__) @@ -103,8 +102,7 @@ class EswitchManager(object): net_map = self.network_map[network_id] net_map['ports'].append({'port_id': port_id, 'port_mac': port_mac}) - if network_type in (p_const.TYPE_VLAN, - constants.TYPE_IB): + if network_type == p_const.TYPE_VLAN: LOG.info(_('Binding Segmentation ID %(seg_id)s' 'to eSwitch for vNIC mac_address %(mac)s'), {'seg_id': seg_id, @@ -132,8 +130,6 @@ class EswitchManager(object): LOG.info(_("Provisioning network %s"), network_id) if network_type == p_const.TYPE_VLAN: LOG.debug(_("Creating VLAN Network")) - elif network_type == constants.TYPE_IB: - LOG.debug(_("Creating IB Network")) else: LOG.error(_("Unknown network type %(network_type)s " "for network %(network_id)s"), diff --git a/neutron/plugins/mlnx/common/config.py b/neutron/plugins/mlnx/common/config.py index 2f0376d25..b75e87be3 100644 --- a/neutron/plugins/mlnx/common/config.py +++ b/neutron/plugins/mlnx/common/config.py @@ -26,11 +26,18 @@ DEFAULT_INTERFACE_MAPPINGS = [] vlan_opts = [ cfg.StrOpt('tenant_network_type', default='vlan', help=_("Network type for tenant networks " - "(local, ib, vlan, or none)")), + "(local, vlan, or none)")), cfg.ListOpt('network_vlan_ranges', default=DEFAULT_VLAN_RANGES, help=_("List of :: " "or ")), + cfg.ListOpt('physical_network_type_mappings', + default=[], + help=_("List of : " + " 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)")) ] diff --git a/neutron/plugins/mlnx/common/constants.py b/neutron/plugins/mlnx/common/constants.py index 48274efbc..2277cb7bb 100644 --- a/neutron/plugins/mlnx/common/constants.py +++ b/neutron/plugins/mlnx/common/constants.py @@ -18,8 +18,9 @@ LOCAL_VLAN_ID = -2 FLAT_VLAN_ID = -1 -# Values for network_type +# Values for physical network_type TYPE_IB = 'ib' +TYPE_ETH = 'eth' VIF_TYPE_DIRECT = 'mlnx_direct' VIF_TYPE_HOSTDEV = 'hostdev' diff --git a/neutron/plugins/mlnx/mlnx_plugin.py b/neutron/plugins/mlnx/mlnx_plugin.py index cee2e4b3d..1b100fcd5 100644 --- a/neutron/plugins/mlnx/mlnx_plugin.py +++ b/neutron/plugins/mlnx/mlnx_plugin.py @@ -96,7 +96,7 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2, def __init__(self): """Start Mellanox Neutron Plugin.""" super(MellanoxEswitchPlugin, self).__init__() - self._parse_network_vlan_ranges() + self._parse_network_config() db.sync_network_states(self.network_vlan_ranges) self._set_tenant_network_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 ) + 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): try: self.network_vlan_ranges = plugin_utils.parse_network_vlan_ranges( @@ -142,14 +177,6 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2, sys.exit(1) 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): binding = db.get_network_binding(context.session, network['id']) network[provider.NETWORK_TYPE] = binding.network_type @@ -166,7 +193,6 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2, def _set_tenant_network_type(self): self.tenant_network_type = cfg.CONF.MLNX.tenant_network_type if self.tenant_network_type not in [svc_constants.TYPE_VLAN, - constants.TYPE_IB, svc_constants.TYPE_LOCAL, svc_constants.TYPE_NONE]: 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) 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) elif network_type == svc_constants.TYPE_LOCAL: @@ -241,7 +267,6 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2, physical_network, physical_network_set): if network_type in [svc_constants.TYPE_VLAN, - constants.TYPE_IB, svc_constants.TYPE_FLAT]: if physical_network_set: if physical_network not in self.network_vlan_ranges: @@ -256,7 +281,10 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2, return physical_network 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, constants.VIF_TYPE_HOSTDEV) 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, attrs.get('network_id')) - net_type = net_binding.network_type + phy_net = net_binding.physical_network if not binding_profile_set: return self.vnic_type if constants.VNIC_TYPE in binding_profile: 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, constants.VIF_TYPE_HOSTDEV): if self._check_port_binding_for_net_type(vnic_type, - net_type): + phy_net_type): self.base_binding_dict[portbindings.VIF_TYPE] = vnic_type return vnic_type else: msg = (_("Unsupported vnic type %(vnic_type)s " - "for network type %(net_type)s") % - {'vnic_type': vnic_type, 'net_type': net_type}) + "for physical network type %(net_type)s") % + {'vnic_type': vnic_type, 'net_type': phy_net_type}) else: msg = _("Invalid vnic_type on port_create") else: @@ -307,15 +336,13 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2, network_type = self.tenant_network_type if network_type == svc_constants.TYPE_NONE: raise q_exc.TenantNetworksDisabled() - elif network_type in [svc_constants.TYPE_VLAN, - constants.TYPE_IB]: + elif network_type == svc_constants.TYPE_VLAN: physical_network, vlan_id = db.reserve_network(session) else: # TYPE_LOCAL vlan_id = constants.LOCAL_VLAN_ID else: # provider network if network_type in [svc_constants.TYPE_VLAN, - constants.TYPE_IB, svc_constants.TYPE_FLAT]: db.reserve_specific_network(session, physical_network, diff --git a/neutron/tests/unit/mlnx/test_defaults.py b/neutron/tests/unit/mlnx/test_defaults.py index a53f6e3f4..8d9cc8c4e 100644 --- a/neutron/tests/unit/mlnx/test_defaults.py +++ b/neutron/tests/unit/mlnx/test_defaults.py @@ -29,6 +29,9 @@ class ConfigurationTest(base.BaseTestCase): cfg.CONF.MLNX.tenant_network_type) self.assertEqual(1, 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, len(cfg.CONF.ESWITCH. physical_interface_mappings)) diff --git a/neutron/tests/unit/mlnx/test_mlnx_plugin_config.py b/neutron/tests/unit/mlnx/test_mlnx_plugin_config.py new file mode 100644 index 000000000..52e5e99f3 --- /dev/null +++ b/neutron/tests/unit/mlnx/test_mlnx_plugin_config.py @@ -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)