]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Change tenant network type usage for IB Fabric
authorIrena Berezovsky <irenab@mellanox.com>
Thu, 16 Jan 2014 12:28:01 +0000 (14:28 +0200)
committerThomas Goirand <thomas@goirand.fr>
Thu, 13 Mar 2014 07:20:30 +0000 (15:20 +0800)
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

etc/neutron/plugins/mlnx/mlnx_conf.ini
neutron/plugins/mlnx/agent/eswitch_neutron_agent.py
neutron/plugins/mlnx/common/config.py
neutron/plugins/mlnx/common/constants.py
neutron/plugins/mlnx/mlnx_plugin.py
neutron/tests/unit/mlnx/test_defaults.py
neutron/tests/unit/mlnx/test_mlnx_plugin_config.py [new file with mode: 0644]

index 841947904316ca2e985506d99b9a6755495ebd2e..275b727c1309958fc18b7fa0d847d8b802328cec 100644 (file)
 # network_vlan_ranges =
 # 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]
 # (ListOpt) Comma-separated list of
 # <physical_network>:<physical_interface> tuples mapping physical
index 74ac21a105f33d1053b987d5efc18030f84eacfb..d546dd5d538dc867ee7d98b253d96dee43267673 100644 (file)
@@ -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"),
index 2f0376d257e7465318c297009f0bf1ceec1dd23d..b75e87be3f32026eb474211510905d35e2cd854c 100644 (file)
@@ -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 <physical_network>:<vlan_min>:<vlan_max> "
                        "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)"))
 ]
 
 
index 48274efbc395f1726c6ef681b12716e7ac13bc5a..2277cb7bb5065cd87ca575fbfb533d678eb311b8 100644 (file)
@@ -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'
index 28ceac7f284020602ad4bbb751ebba59bf54ff70..a2b347417998d8d59139a18abc18f7bb6911e997 100644 (file)
@@ -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
@@ -134,6 +134,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(
@@ -143,14 +178,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
@@ -167,7 +194,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. "
@@ -195,7 +221,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:
@@ -242,7 +268,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:
@@ -257,7 +282,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:
@@ -270,22 +298,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:
@@ -308,15 +337,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,
index a53f6e3f4635f8d40d0c3b2609c12ae46e283a71..8d9cc8c4e01f7cca85a3af307b1dd7b2eeebc334 100644 (file)
@@ -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 (file)
index 0000000..52e5e99
--- /dev/null
@@ -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)