]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
ML2 mechanism driver for SR-IOV capable NIC based switching, Part 1
authorIrena Berezovsky <irenab@mellanox.com>
Tue, 18 Feb 2014 13:13:58 +0000 (15:13 +0200)
committerIrena Berezovsky <irenab@mellanox.com>
Tue, 22 Jul 2014 15:42:39 +0000 (18:42 +0300)
This set of changes introduces the ML2 mechanism driver for SR-IOV capable NIC based switching.
Please see the blueprint for more information.
The review is submitted in two parts:
- Part 1 (this part)
    The Mechanism Driver to support port binding for SR-IOV virtual functions of
    SRIOV capable switching NICs, such as Mellanox ConnectX Family.

    Use configurable list of supported NIC vendor and product PCI ids to filter
    devices to bind the SR-IOV port.
    Use configurable agent_required option to require SRIOV L2 Agent
    for bort binding.

- Part2
    The SRIOV NIC Based L2 Agent.

Partially implements: blueprint ml2-sriov-nic-switch

Change-Id: If3d28df2a8ffe72ae512ddae076f42fca936cff7

etc/neutron/plugins/ml2/ml2_conf_sriov.ini [new file with mode: 0644]
neutron/common/constants.py
neutron/extensions/portbindings.py
neutron/plugins/ml2/drivers/mech_sriov/__init__.py [new file with mode: 0644]
neutron/plugins/ml2/drivers/mech_sriov/mech_driver.py [new file with mode: 0644]
neutron/plugins/ml2/rpc.py
neutron/tests/unit/ml2/drivers/mech_sriov/__init__.py [new file with mode: 0644]
neutron/tests/unit/ml2/drivers/mech_sriov/test_mech_sriov_nic_switch.py [new file with mode: 0644]
setup.cfg

diff --git a/etc/neutron/plugins/ml2/ml2_conf_sriov.ini b/etc/neutron/plugins/ml2/ml2_conf_sriov.ini
new file mode 100644 (file)
index 0000000..09504af
--- /dev/null
@@ -0,0 +1,12 @@
+# Defines configuration options for SRIOV NIC Switch MechanismDriver
+
+[ml2_sriov]
+# (ListOpt) Comma-separated list of
+# supported Vendor PCI Devices, in format vendor_id:product_id
+#
+# supported_vendor_pci_devs = 15b3:1004
+# Example: supported_vendor_pci_devs = 15b3:1004, 8086:10c9
+#
+# (BoolOpt) Requires SRIOV neutron agent for port binding
+# agent_required = True
+
index 6c321139e3ee8dccd30f4455ee01da3cde452574..e1c61a8bc7d4bda7b4e213139fa34b39527598d9 100644 (file)
@@ -87,6 +87,7 @@ AGENT_TYPE_MLNX = 'Mellanox plugin agent'
 AGENT_TYPE_METERING = 'Metering agent'
 AGENT_TYPE_METADATA = 'Metadata agent'
 AGENT_TYPE_SDNVE = 'IBM SDN-VE agent'
+AGENT_TYPE_NIC_SWITCH = 'NIC Switch agent'
 L2_AGENT_TOPIC = 'N/A'
 
 PAGINATION_INFINITE = 'infinite'
index 7e5c76dd3f25e6167650b2bdb5cd669b818e7059..97574a1bff3955b9aec84fa482ebeb10b20738fa 100644 (file)
@@ -45,6 +45,7 @@ PROFILE = 'binding:profile'
 #                     strategy for OVS should be used
 CAP_PORT_FILTER = 'port_filter'
 OVS_HYBRID_PLUG = 'ovs_hybrid_plug'
+VIF_DETAILS_VLAN = 'vlan'
 
 VIF_TYPE_UNBOUND = 'unbound'
 VIF_TYPE_BINDING_FAILED = 'binding_failed'
@@ -58,11 +59,13 @@ VIF_TYPE_HYPERV = 'hyperv'
 VIF_TYPE_MIDONET = 'midonet'
 VIF_TYPE_MLNX_DIRECT = 'mlnx_direct'
 VIF_TYPE_MLNX_HOSTDEV = 'hostdev'
+VIF_TYPE_HW_VEB = 'hw_veb'
 VIF_TYPE_OTHER = 'other'
 VIF_TYPES = [VIF_TYPE_UNBOUND, VIF_TYPE_BINDING_FAILED, VIF_TYPE_OVS,
              VIF_TYPE_IVS, VIF_TYPE_BRIDGE, VIF_TYPE_802_QBG,
              VIF_TYPE_802_QBH, VIF_TYPE_HYPERV, VIF_TYPE_MIDONET,
-             VIF_TYPE_MLNX_DIRECT, VIF_TYPE_MLNX_HOSTDEV, VIF_TYPE_OTHER]
+             VIF_TYPE_MLNX_DIRECT, VIF_TYPE_MLNX_HOSTDEV, VIF_TYPE_HW_VEB,
+             VIF_TYPE_OTHER]
 
 VNIC_NORMAL = 'normal'
 VNIC_DIRECT = 'direct'
diff --git a/neutron/plugins/ml2/drivers/mech_sriov/__init__.py b/neutron/plugins/ml2/drivers/mech_sriov/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/neutron/plugins/ml2/drivers/mech_sriov/mech_driver.py b/neutron/plugins/ml2/drivers/mech_sriov/mech_driver.py
new file mode 100644 (file)
index 0000000..3db3b89
--- /dev/null
@@ -0,0 +1,184 @@
+# Copyright 2014 Mellanox Technologies, Ltd
+#
+# 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.
+
+
+from oslo.config import cfg
+
+from neutron.common import constants
+from neutron.extensions import portbindings
+from neutron.openstack.common import log
+from neutron.plugins.common import constants as p_const
+from neutron.plugins.ml2 import driver_api as api
+
+
+LOG = log.getLogger(__name__)
+
+sriov_opts = [
+    cfg.ListOpt('supported_pci_vendor_devs',
+               default=['15b3:1004', '8086:10c9'],
+               help=_("Supported PCI vendor devices, defined by "
+                      "vendor_id:product_id according to the PCI ID "
+                      "Repository. Default enables support for Intel "
+                      "and Mellanox SR-IOV capable NICs")),
+    cfg.BoolOpt('agent_required',
+                default=False,
+                help=_("SRIOV neutron agent is required for port binding")),
+
+]
+
+cfg.CONF.register_opts(sriov_opts, "ml2_sriov")
+
+
+class SriovNicSwitchMechanismDriver(api.MechanismDriver):
+    """Mechanism Driver for SR-IOV capable NIC based switching.
+
+    The SriovNicSwitchMechanismDriver integrates the ml2 plugin with the
+    sriovNicSwitch L2 agent depending on configuration option.
+    Port binding with this driver may require the sriovNicSwitch agent
+    to be running on the port's host, and that agent to have connectivity
+    to at least one segment of the port's network.
+    L2 agent is not essential for port binding; port binding is handled by
+    VIF Driver via libvirt domain XML.
+    L2 Agent presents in  order to manage port update events.
+    If vendor NIC does not support updates, setting agent_required = False
+    will allow to use Mechanism Driver without L2 agent.
+
+    """
+
+    def __init__(self,
+                 agent_type=constants.AGENT_TYPE_NIC_SWITCH,
+                 vif_type=portbindings.VIF_TYPE_HW_VEB,
+                 vif_details={portbindings.CAP_PORT_FILTER: False},
+                 supported_vnic_types=[portbindings.VNIC_DIRECT,
+                                       portbindings.VNIC_MACVTAP],
+                 supported_pci_vendor_info=None):
+        """Initialize base class for SriovNicSwitch L2 agent type.
+
+        :param agent_type: Constant identifying agent type in agents_db
+        :param vif_type: Value for binding:vif_type when bound
+        :param vif_details: Dictionary with details for VIF driver when bound
+        :param supported_vnic_types: The binding:vnic_type values we can bind
+        :param supported_pci_vendor_info: The pci_vendor_info values to bind
+        """
+        self.agent_type = agent_type
+        self.supported_vnic_types = supported_vnic_types
+        self.vif_type = vif_type
+        self.vif_details = vif_details
+
+    def initialize(self):
+        try:
+            self.pci_vendor_info = self._parse_pci_vendor_config(
+                        cfg.CONF.ml2_sriov.supported_pci_vendor_devs)
+            self.agent_required = cfg.CONF.ml2_sriov.agent_required
+        except ValueError:
+            LOG.exception(_("Failed to parse supported PCI vendor devices"))
+            raise cfg.Error(_("Parsing supported pci_vendor_devs failed"))
+
+    def bind_port(self, context):
+        LOG.debug("Attempting to bind port %(port)s on "
+                  "network %(network)s",
+                  {'port': context.current['id'],
+                   'network': context.network.current['id']})
+        vnic_type = context.current.get(portbindings.VNIC_TYPE,
+                                        portbindings.VNIC_NORMAL)
+        if vnic_type not in self.supported_vnic_types:
+            LOG.debug("Refusing to bind due to unsupported vnic_type: %s",
+                      vnic_type)
+            return
+
+        if not self._check_supported_pci_vendor_device(context):
+            LOG.debug("Refusing to bind due to unsupported pci_vendor device")
+            return
+
+        if self.agent_required:
+            for agent in context.host_agents(self.agent_type):
+                LOG.debug("Checking agent: %s", agent)
+                if agent['alive']:
+                    if self.try_to_bind(context, agent):
+                        return
+                else:
+                    LOG.warning(_("Attempting to bind with dead agent: %s"),
+                                agent)
+        else:
+            self.try_to_bind(context)
+
+    def try_to_bind(self, context, agent=None):
+        for segment in context.network.network_segments:
+            if self.check_segment(segment, agent):
+                context.set_binding(segment[api.ID],
+                                    self.vif_type,
+                                    self.get_vif_details(context, segment),
+                                    constants.PORT_STATUS_ACTIVE)
+                LOG.debug("Bound using segment: %s", segment)
+                return True
+        return False
+
+    def check_segment(self, segment, agent=None):
+        """Check if segment can be bound.
+
+        :param segment: segment dictionary describing segment to bind
+        :param agent: agents_db entry describing agent to bind or None
+        :returns: True if segment can be bound for agent
+        """
+        network_type = segment[api.NETWORK_TYPE]
+        if network_type == p_const.TYPE_VLAN:
+            if agent:
+                mappings = agent['configurations'].get('device_mappings', {})
+                LOG.debug("Checking segment: %(segment)s "
+                          "for mappings: %(mappings)s ",
+                          {'segment': segment, 'mappings': mappings})
+                return segment[api.PHYSICAL_NETWORK] in mappings
+            return True
+        return False
+
+    def _check_supported_pci_vendor_device(self, context):
+        if self.pci_vendor_info:
+            profile = context.current.get(portbindings.PROFILE, {})
+            if not profile:
+                LOG.debug("Missing profile in port binding")
+                return False
+            pci_vendor_info = profile.get('pci_vendor_info')
+            if not pci_vendor_info:
+                LOG.debug("Missing pci vendor info in profile")
+                return False
+            if pci_vendor_info not in self.pci_vendor_info:
+                LOG.debug("Unsupported pci_vendor %s", pci_vendor_info)
+                return False
+            return True
+        return False
+
+    def get_vif_details(self, context, segment):
+        if segment[api.NETWORK_TYPE] == p_const.TYPE_VLAN:
+            vlan_id = str(segment[api.SEGMENTATION_ID])
+            self.vif_details[portbindings.VIF_DETAILS_VLAN] = vlan_id
+        return self.vif_details
+
+    def _parse_pci_vendor_config(self, pci_vendor_list):
+        parsed_list = []
+        for elem in pci_vendor_list:
+            elem = elem.strip()
+            if not elem:
+                continue
+            split_result = elem.split(':')
+            if len(split_result) != 2:
+                raise ValueError(_("Invalid pci_vendor_info: '%s'") % elem)
+            vendor_id = split_result[0].strip()
+            if not vendor_id:
+                raise ValueError(_("Missing vendor_id in: '%s'") % elem)
+            product_id = split_result[1].strip()
+            if not product_id:
+                raise ValueError(_("Missing product_id in: '%s'") % elem)
+            parsed_list.append(elem)
+        return parsed_list
index 0ee8c009991bdc2d481fc538ac20fd53898e3e74..a67d0186b0d7266cd297fd36c9880144c4cb3d4c 100644 (file)
@@ -125,7 +125,8 @@ class RpcCallbacks(n_rpc.RpcCallback,
                  'segmentation_id': segment[api.SEGMENTATION_ID],
                  'physical_network': segment[api.PHYSICAL_NETWORK],
                  'fixed_ips': port['fixed_ips'],
-                 'device_owner': port['device_owner']}
+                 'device_owner': port['device_owner'],
+                 'profile': port[portbindings.PROFILE]}
         LOG.debug(_("Returning: %s"), entry)
         return entry
 
diff --git a/neutron/tests/unit/ml2/drivers/mech_sriov/__init__.py b/neutron/tests/unit/ml2/drivers/mech_sriov/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/neutron/tests/unit/ml2/drivers/mech_sriov/test_mech_sriov_nic_switch.py b/neutron/tests/unit/ml2/drivers/mech_sriov/test_mech_sriov_nic_switch.py
new file mode 100644 (file)
index 0000000..e854f06
--- /dev/null
@@ -0,0 +1,236 @@
+# Copyright 2014 Mellanox Technologies, Ltd
+#
+# 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
+
+from neutron.common import constants
+from neutron.extensions import portbindings
+from neutron.plugins.common import constants as p_const
+from neutron.plugins.ml2 import config  # noqa
+from neutron.plugins.ml2 import driver_api as api
+from neutron.plugins.ml2.drivers.mech_sriov import mech_driver
+from neutron.tests.unit.ml2 import _test_mech_agent as base
+
+MELLANOX_CONNECTX3_PCI_INFO = '15b3:1004'
+DEFAULT_PCI_INFO = ['15b3:1004', '8086:10c9']
+
+
+class TestFakePortContext(base.FakePortContext):
+        def __init__(self, agent_type, agents, segments,
+                     vnic_type=portbindings.VNIC_NORMAL,
+                     profile={'pci_vendor_info':
+                              MELLANOX_CONNECTX3_PCI_INFO}):
+            super(TestFakePortContext, self).__init__(agent_type,
+                                                      agents,
+                                                      segments,
+                                                      vnic_type)
+            self._bound_profile = profile
+
+        @property
+        def current(self):
+            return {'id': base.PORT_ID,
+                    'binding:vnic_type': self._bound_vnic_type,
+                    'binding:profile': self._bound_profile}
+
+        def set_binding(self, segment_id, vif_type, vif_details, state):
+            self._bound_segment_id = segment_id
+            self._bound_vif_type = vif_type
+            self._bound_vif_details = vif_details
+            self._bound_state = state
+
+
+class SriovNicSwitchMechanismBaseTestCase(base.AgentMechanismBaseTestCase):
+    VIF_TYPE = portbindings.VIF_TYPE_HW_VEB
+    CAP_PORT_FILTER = False
+    AGENT_TYPE = constants.AGENT_TYPE_NIC_SWITCH
+    VLAN_SEGMENTS = base.AgentMechanismVlanTestCase.VLAN_SEGMENTS
+
+    GOOD_MAPPINGS = {'fake_physical_network': 'fake_device'}
+    GOOD_CONFIGS = {'device_mappings': GOOD_MAPPINGS}
+
+    BAD_MAPPINGS = {'wrong_physical_network': 'wrong_device'}
+    BAD_CONFIGS = {'device_mappings': BAD_MAPPINGS}
+
+    AGENTS = [{'alive': True,
+               'configurations': GOOD_CONFIGS}]
+    AGENTS_DEAD = [{'alive': False,
+                    'configurations': GOOD_CONFIGS}]
+    AGENTS_BAD = [{'alive': False,
+                   'configurations': GOOD_CONFIGS},
+                  {'alive': True,
+                   'configurations': BAD_CONFIGS}]
+
+    def setUp(self):
+        cfg.CONF.set_override('supported_pci_vendor_devs',
+                              DEFAULT_PCI_INFO,
+                              'ml2_sriov')
+        cfg.CONF.set_override('agent_required', True, 'ml2_sriov')
+        super(SriovNicSwitchMechanismBaseTestCase, self).setUp()
+        self.driver = mech_driver.SriovNicSwitchMechanismDriver()
+        self.driver.initialize()
+
+    def test_check_segment(self):
+        """Validate the check_segment call."""
+        segment = {'api.NETWORK_TYPE': ""}
+        segment[api.NETWORK_TYPE] = p_const.TYPE_VLAN
+        self.assertTrue(self.driver.check_segment(segment))
+        # Validate a network type not currently supported
+        segment[api.NETWORK_TYPE] = p_const.TYPE_GRE
+        self.assertFalse(self.driver.check_segment(segment))
+
+
+class SriovSwitchMechGenericTestCase(SriovNicSwitchMechanismBaseTestCase,
+                                     base.AgentMechanismGenericTestCase):
+    pass
+
+
+class SriovMechVlanTestCase(SriovNicSwitchMechanismBaseTestCase,
+                            base.AgentMechanismBaseTestCase):
+    VLAN_SEGMENTS = [{api.ID: 'unknown_segment_id',
+                      api.NETWORK_TYPE: 'no_such_type'},
+                     {api.ID: 'vlan_segment_id',
+                      api.NETWORK_TYPE: 'vlan',
+                      api.PHYSICAL_NETWORK: 'fake_physical_network',
+                      api.SEGMENTATION_ID: 1234}]
+
+    def test_type_vlan(self):
+        context = TestFakePortContext(self.AGENT_TYPE,
+                                  self.AGENTS,
+                                  self.VLAN_SEGMENTS,
+                                  portbindings.VNIC_DIRECT)
+        self.driver.bind_port(context)
+        self._check_bound(context, self.VLAN_SEGMENTS[1])
+
+    def test_type_vlan_bad(self):
+        context = TestFakePortContext(self.AGENT_TYPE,
+                                  self.AGENTS_BAD,
+                                  self.VLAN_SEGMENTS,
+                                  portbindings.VNIC_DIRECT)
+        self.driver.bind_port(context)
+        self._check_unbound(context)
+
+
+class SriovSwitchMechVnicTypeTestCase(SriovNicSwitchMechanismBaseTestCase):
+    def _check_vif_type_for_vnic_type(self, vnic_type,
+                                      expected_vif_type):
+        context = TestFakePortContext(self.AGENT_TYPE,
+                                      self.AGENTS,
+                                      self.VLAN_SEGMENTS,
+                                      vnic_type)
+        self.driver.bind_port(context)
+        self.assertEqual(expected_vif_type, context._bound_vif_type)
+        vlan = int(context._bound_vif_details[portbindings.VIF_DETAILS_VLAN])
+        self.assertEqual(1234, vlan)
+
+    def test_vnic_type_direct(self):
+        self._check_vif_type_for_vnic_type(portbindings.VNIC_DIRECT,
+                                           portbindings.VIF_TYPE_HW_VEB)
+
+    def test_vnic_type_macvtap(self):
+        self._check_vif_type_for_vnic_type(portbindings.VNIC_MACVTAP,
+                                           portbindings.VIF_TYPE_HW_VEB)
+
+
+class SriovSwitchMechProfileTestCase(SriovNicSwitchMechanismBaseTestCase):
+    def _check_vif_for_pci_info(self, pci_vendor_info, expected_vif_type):
+        context = TestFakePortContext(self.AGENT_TYPE,
+                                      self.AGENTS,
+                                      self.VLAN_SEGMENTS,
+                                      portbindings.VNIC_DIRECT,
+                                      {'pci_vendor_info': pci_vendor_info})
+        self.driver.bind_port(context)
+        self.assertEqual(expected_vif_type, context._bound_vif_type)
+
+    def test_profile_supported_pci_info(self):
+        self._check_vif_for_pci_info(MELLANOX_CONNECTX3_PCI_INFO,
+                                     portbindings.VIF_TYPE_HW_VEB)
+
+    def test_profile_unsupported_pci_info(self):
+        with mock.patch('neutron.plugins.ml2.drivers.mech_sriov.'
+                        'mech_driver.LOG') as log_mock:
+            self._check_vif_for_pci_info('xxxx:yyyy', None)
+            log_mock.debug.assert_called_with('Refusing to bind due to '
+                                              'unsupported pci_vendor device')
+
+
+class SriovSwitchMechProfileFailTestCase(SriovNicSwitchMechanismBaseTestCase):
+    def _check_for_pci_vendor_info(self, pci_vendor_info):
+        context = TestFakePortContext(self.AGENT_TYPE,
+                                      self.AGENTS,
+                                      self.VLAN_SEGMENTS,
+                                      portbindings.VNIC_DIRECT,
+                                      pci_vendor_info)
+        self.driver._check_supported_pci_vendor_device(context)
+
+    def test_profile_missing_profile(self):
+        with mock.patch('neutron.plugins.ml2.drivers.mech_sriov.'
+                        'mech_driver.LOG') as log_mock:
+            self._check_for_pci_vendor_info({})
+            log_mock.debug.assert_called_with("Missing profile in port"
+                                              " binding")
+
+    def test_profile_missing_pci_vendor_info(self):
+        with mock.patch('neutron.plugins.ml2.drivers.mech_sriov.'
+                        'mech_driver.LOG') as log_mock:
+            self._check_for_pci_vendor_info({'aa': 'bb'})
+            log_mock.debug.assert_called_with("Missing pci vendor"
+                                              " info in profile")
+
+
+class SriovSwitchMechVifDetailsTestCase(SriovNicSwitchMechanismBaseTestCase):
+    def test_vif_details_contains_vlan_id(self):
+        VLAN_SEGMENTS = [{api.ID: 'vlan_segment_id',
+                          api.NETWORK_TYPE: 'vlan',
+                          api.PHYSICAL_NETWORK: 'fake_physical_network',
+                          api.SEGMENTATION_ID: 1234}]
+
+        context = TestFakePortContext(self.AGENT_TYPE,
+                                      self.AGENTS,
+                                      VLAN_SEGMENTS,
+                                      portbindings.VNIC_DIRECT)
+
+        self.driver.bind_port(context)
+        vif_details = context._bound_vif_details
+        self.assertIsNotNone(vif_details)
+        vlan_id = int(vif_details.get(portbindings.VIF_DETAILS_VLAN))
+        self.assertEqual(1234, vlan_id)
+
+
+class SriovSwitchMechConfigTestCase(SriovNicSwitchMechanismBaseTestCase):
+    def _set_config(self, pci_devs=['aa:bb']):
+        cfg.CONF.set_override('mechanism_drivers',
+                              ['logger', 'sriovnicswitch'], 'ml2')
+        cfg.CONF.set_override('supported_pci_vendor_devs', pci_devs,
+                              'ml2_sriov')
+
+    def test_pci_vendor_config_single_entry(self):
+        self._set_config()
+        self.driver.initialize()
+        self.assertEqual(['aa:bb'], self.driver.pci_vendor_info)
+
+    def test_pci_vendor_config_multiple_entry(self):
+        self._set_config(['x:y', 'a:b'])
+        self.driver.initialize()
+        self.assertEqual(['x:y', 'a:b'], self.driver.pci_vendor_info)
+
+    def test_pci_vendor_config_default_entry(self):
+        self.driver.initialize()
+        self.assertEqual(DEFAULT_PCI_INFO,
+                         self.driver.pci_vendor_info)
+
+    def test_pci_vendor_config_wrong_entry(self):
+        self._set_config('wrong_entry')
+        self.assertRaises(cfg.Error, self.driver.initialize)
index 94f7d9cd7bed1dee165c560acdb7e2ddd6785c3f..df4d6cfb4d4c1882df98dc3dc70461662336da01 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -71,6 +71,7 @@ data_files =
         etc/neutron/plugins/ml2/ml2_conf_odl.ini
         etc/neutron/plugins/ml2/ml2_conf_ofa.ini
         etc/neutron/plugins/ml2/ml2_conf_fslsdn.ini
+        etc/neutron/plugins/ml2/ml2_conf_sriov.ini
     etc/neutron/plugins/mlnx = etc/neutron/plugins/mlnx/mlnx_conf.ini
     etc/neutron/plugins/nec = etc/neutron/plugins/nec/nec.ini
     etc/neutron/plugins/nuage = etc/neutron/plugins/nuage/nuage_plugin.ini
@@ -167,6 +168,7 @@ neutron.ml2.mechanism_drivers =
     mlnx = neutron.plugins.ml2.drivers.mlnx.mech_mlnx:MlnxMechanismDriver
     brocade = neutron.plugins.ml2.drivers.brocade.mechanism_brocade:BrocadeMechanism
     fslsdn = neutron.plugins.ml2.drivers.mechanism_fslsdn:FslsdnMechanismDriver
+    sriovnicswitch = neutron.plugins.ml2.drivers.mech_sriov.mech_driver:SriovNicSwitchMechanismDriver
 neutron.openstack.common.cache.backends =
     memory = neutron.openstack.common.cache._backends.memory:MemoryBackend
 # These are for backwards compat with Icehouse notification_driver configuration values