From a85c5ed3fb1d0cf9af14b976a233c682ffa89c6b Mon Sep 17 00:00:00 2001 From: Lajos Katona Date: Fri, 28 Sep 2018 09:32:37 +0200 Subject: [PATCH] supported_vnic_type configurable for ovs Now supported_vnic_types is hardcoded to the mechanism drivers, but that can depend on several factors, like type of the NIC, admin decision, etc. With this patch we put the right to decide which vnic types are supported for ovs agent into the hands of the admin, by allowing blacklisting items from the mechanism driver specific list. Background: http://eavesdrop.openstack.org/meetings/neutron_qos/2018/ neutron_qos.2018-07-31-15.00.log.html#l-58 Change-Id: I63e562e2eccc5b02c1c767d6a2c28cb803131e99 Partial-Bug: #1578989 See-Also: https://review.openstack.org/502306 (nova spec) See-Also: https://review.openstack.org/508149 (neutron spec) --- doc/source/admin/config-ml2.rst | 25 ++++++++ .../ml2/drivers/openvswitch/__init__.py | 0 .../ml2/drivers/openvswitch/mech_ovs_conf.py | 40 +++++++++++++ neutron/opts.py | 6 +- neutron/plugins/ml2/drivers/mech_agent.py | 29 +++++++++ .../mech_driver/mech_openvswitch.py | 17 +++++- .../unit/plugins/ml2/_test_mech_agent.py | 28 +++++++++ .../mech_driver/test_mech_openvswitch.py | 59 +++++++++++++++++++ ...configurable-for-ovs-fc73422daffd42b0.yaml | 9 +++ 9 files changed, 210 insertions(+), 3 deletions(-) create mode 100644 neutron/conf/plugins/ml2/drivers/openvswitch/__init__.py create mode 100644 neutron/conf/plugins/ml2/drivers/openvswitch/mech_ovs_conf.py create mode 100644 releasenotes/notes/make-supported-vnic-types-configurable-for-ovs-fc73422daffd42b0.yaml diff --git a/doc/source/admin/config-ml2.rst b/doc/source/admin/config-ml2.rst index 44e00647a47..b9ed28ba9a3 100644 --- a/doc/source/admin/config-ml2.rst +++ b/doc/source/admin/config-ml2.rst @@ -260,6 +260,31 @@ For more details, see the Configuration of those drivers is not part of this document. +Supported VNIC types +^^^^^^^^^^^^^^^^^^^^ + +The ``vnic_type_blacklist`` option is used to remove values from the mechanism driver's +``supported_vnic_types`` list. + +.. list-table:: Mechanism drivers and supported VNIC types + :header-rows: 1 + + * - mech driver / supported_vnic_types + - supported VNIC types + - blacklisting available + * - Linux bridge + - normal + - no + * - MacVTap + - macvtap + - no + * - Open vSwitch + - normal, direct + - yes (ovs_driver vnic_type_blacklist, see: `Configuration Reference <../configuration/ml2-conf.html#ovs_driver>`__) + * - SRIOV + - direct, macvtap, direct_physical + - no + Extension Drivers ----------------- diff --git a/neutron/conf/plugins/ml2/drivers/openvswitch/__init__.py b/neutron/conf/plugins/ml2/drivers/openvswitch/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/neutron/conf/plugins/ml2/drivers/openvswitch/mech_ovs_conf.py b/neutron/conf/plugins/ml2/drivers/openvswitch/mech_ovs_conf.py new file mode 100644 index 00000000000..5e34ff2c47a --- /dev/null +++ b/neutron/conf/plugins/ml2/drivers/openvswitch/mech_ovs_conf.py @@ -0,0 +1,40 @@ +# Copyright (c) 2018 Ericsson +# +# 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._i18n import _ + + +ovs_driver_opts = [ + cfg.ListOpt('vnic_type_blacklist', + default=[], + help=_("Comma-separated list of VNIC types for which support " + "is administratively prohibited by the mechanism " + "driver. Please note that the supported vnic_types " + "depend on your network interface card, on the kernel " + "version of your operating system, and on other " + "factors, like OVS version. In case of ovs mechanism " + "driver the valid vnic types are normal and direct. " + "Note that direct is supported only from kernel 4.8, " + "and from ovs 2.8.0. Bind DIRECT (SR-IOV) port allows " + "to offload the OVS flows using tc to the SR-IOV NIC. " + "This allows to support hardware offload via tc and " + "that allows us to manage the VF by OpenFlow control " + "plane using representor net-device.")), +] + + +def register_ovs_mech_driver_opts(cfg=cfg.CONF): + cfg.register_opts(ovs_driver_opts, "OVS_DRIVER") diff --git a/neutron/opts.py b/neutron/opts.py index 0d1a1d93bc9..f968902a47a 100644 --- a/neutron/opts.py +++ b/neutron/opts.py @@ -47,6 +47,7 @@ import neutron.conf.plugins.ml2.drivers.l2pop import neutron.conf.plugins.ml2.drivers.linuxbridge import neutron.conf.plugins.ml2.drivers.macvtap import neutron.conf.plugins.ml2.drivers.mech_sriov.agent_common +import neutron.conf.plugins.ml2.drivers.openvswitch.mech_ovs_conf import neutron.conf.plugins.ml2.drivers.ovs_conf import neutron.conf.quota import neutron.conf.service @@ -255,7 +256,10 @@ def list_ml2_conf_opts(): ('securitygroup', neutron.conf.agent.securitygroups_rpc.security_group_opts), ('l2pop', - neutron.conf.plugins.ml2.drivers.l2pop.l2_population_options) + neutron.conf.plugins.ml2.drivers.l2pop.l2_population_options), + ('ovs_driver', + neutron.conf.plugins.ml2.drivers.openvswitch.mech_ovs_conf. + ovs_driver_opts) ] diff --git a/neutron/plugins/ml2/drivers/mech_agent.py b/neutron/plugins/ml2/drivers/mech_agent.py index 56e7907df04..ee1fa12e8e3 100644 --- a/neutron/plugins/ml2/drivers/mech_agent.py +++ b/neutron/plugins/ml2/drivers/mech_agent.py @@ -22,6 +22,7 @@ from neutron_lib.plugins.ml2 import api from oslo_log import log import six +from neutron._i18n import _ from neutron.db import provisioning_blocks LOG = log.getLogger(__name__) @@ -132,6 +133,34 @@ class AgentMechanismDriverBase(api.MechanismDriver): return True. Otherwise, it must return False. """ + def blacklist_supported_vnic_types(self, vnic_types, blacklist): + """Validate the blacklist and blacklist the supported_vnic_types + + :param vnic_types: The supported_vnic_types list + :param blacklist: The blacklist as in vnic_type_blacklist + :return The blacklisted vnic_types + """ + if not blacklist: + return vnic_types + + # Not valid values in the blacklist: + if not all(bl in vnic_types for bl in blacklist): + raise ValueError(_("Not all of the items from vnic_type_blacklist " + "are valid vnic_types for %(agent)s mechanism " + "driver. The valid values are: " + "%(valid_vnics)s.") % + {'agent': self.agent_type, + 'valid_vnics': vnic_types}) + + supported_vnic_types = [vnic_t for vnic_t in vnic_types if + vnic_t not in blacklist] + + # Nothing left in the supported vnict types list: + if len(supported_vnic_types) < 1: + raise ValueError(_("All possible vnic_types were blacklisted for " + "%s mechanism driver!") % self.agent_type) + return supported_vnic_types + @six.add_metaclass(abc.ABCMeta) class SimpleAgentMechanismDriverBase(AgentMechanismDriverBase): diff --git a/neutron/plugins/ml2/drivers/openvswitch/mech_driver/mech_openvswitch.py b/neutron/plugins/ml2/drivers/openvswitch/mech_driver/mech_openvswitch.py index a2ba6ee943b..8d67ca2ffd6 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/mech_driver/mech_openvswitch.py +++ b/neutron/plugins/ml2/drivers/openvswitch/mech_driver/mech_openvswitch.py @@ -23,6 +23,7 @@ from oslo_config import cfg from oslo_log import log from neutron.agent import securitygroups_rpc +from neutron.conf.plugins.ml2.drivers.openvswitch import mech_ovs_conf from neutron.plugins.ml2.drivers import mech_agent from neutron.plugins.ml2.drivers.openvswitch.agent.common \ import constants as a_const @@ -34,6 +35,8 @@ LOG = log.getLogger(__name__) IPTABLES_FW_DRIVER_FULL = ("neutron.agent.linux.iptables_firewall." "OVSHybridIptablesFirewallDriver") +mech_ovs_conf.register_ovs_mech_driver_opts() + class OpenvswitchMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase): """Attach to networks using openvswitch L2 agent. @@ -60,8 +63,18 @@ class OpenvswitchMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase): super(OpenvswitchMechanismDriver, self).__init__( constants.AGENT_TYPE_OVS, portbindings.VIF_TYPE_OVS, - vif_details, supported_vnic_types=[portbindings.VNIC_NORMAL, - portbindings.VNIC_DIRECT]) + vif_details) + + # TODO(lajoskatona): move this blacklisting to + # SimpleAgentMechanismDriverBase. By that e blacklisting and validation + # of the vnic_types would be available for all mechanism drivers. + self.supported_vnic_types = self.blacklist_supported_vnic_types( + vnic_types=[portbindings.VNIC_NORMAL, portbindings.VNIC_DIRECT], + blacklist=cfg.CONF.OVS_DRIVER.vnic_type_blacklist + ) + LOG.info("%s's supported_vnic_types: %s", + self.agent_type, self.supported_vnic_types) + ovs_qos_driver.register() log_driver.register() diff --git a/neutron/tests/unit/plugins/ml2/_test_mech_agent.py b/neutron/tests/unit/plugins/ml2/_test_mech_agent.py index 3562dddf0bf..89398c29171 100644 --- a/neutron/tests/unit/plugins/ml2/_test_mech_agent.py +++ b/neutron/tests/unit/plugins/ml2/_test_mech_agent.py @@ -13,6 +13,9 @@ # License for the specific language governing permissions and limitations # under the License. +from oslo_config import cfg +from oslo_config import fixture as config_fixture + from neutron_lib.api.definitions import portbindings from neutron_lib.plugins.ml2 import api @@ -171,6 +174,31 @@ class FakePortContext(api.PortContext): pass +class MechDriverConfFixture(config_fixture.Config): + + def __init__(self, conf=cfg.CONF, blacklist_cfg=None, + registration_func=None): + """ConfigFixture for vnic_type_blacklist + + :param conf: The driver configuration object + :param blacklist_cfg: A dictionary in the form + {'group': {'opt': 'value'}}, i.e.: + {'OVS_DRIVER': {'vnic_type_blacklist': + ['foo']}} + :param registration_func: The method which do the config group's + registration. + """ + super(MechDriverConfFixture, self).__init__(conf) + self.blacklist_cfg = blacklist_cfg + self.registration_func = registration_func + + def setUp(self): + super(MechDriverConfFixture, self).setUp() + self.registration_func(self.conf) + for group, option in self.blacklist_cfg.items(): + self.config(group=group, **option) + + class AgentMechanismBaseTestCase(base.BaseTestCase): # The following must be overridden for the specific mechanism # driver being tested: diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/mech_driver/test_mech_openvswitch.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/mech_driver/test_mech_openvswitch.py index 7a4e4e76ab2..7405e85597a 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/mech_driver/test_mech_openvswitch.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/mech_driver/test_mech_openvswitch.py @@ -21,6 +21,7 @@ from neutron_lib import constants from neutron_lib.plugins.ml2 import api from oslo_config import cfg +from neutron.conf.plugins.ml2.drivers.openvswitch import mech_ovs_conf from neutron.plugins.ml2.drivers.openvswitch.agent.common import ( constants as a_const) from neutron.plugins.ml2.drivers.openvswitch.mech_driver import ( @@ -296,3 +297,61 @@ class OpenvswitchMechanismSRIOVTestCase(OpenvswitchMechanismBaseTestCase): context = self._make_port_ctx(self.AGENTS, profile=profile) self.driver.bind_port(context) mocked_bind_port.assert_called() + + +class OpenvswitchMechVnicTypesTestCase(OpenvswitchMechanismBaseTestCase): + def setUp(self): + self.blacklist_cfg = { + 'OVS_DRIVER': { + 'vnic_type_blacklist': [] + } + } + self.default_supported_vnics = [portbindings.VNIC_NORMAL, + portbindings.VNIC_DIRECT] + super(OpenvswitchMechVnicTypesTestCase, self).setUp() + + def test_default_vnic_types(self): + self.assertEqual([portbindings.VNIC_NORMAL, + portbindings.VNIC_DIRECT], + self.driver.supported_vnic_types) + + def test_vnic_type_blacklist_valid_item(self): + self.blacklist_cfg['OVS_DRIVER']['vnic_type_blacklist'] = \ + [portbindings.VNIC_DIRECT] + + fake_conf = cfg.CONF + fake_conf_fixture = base.MechDriverConfFixture( + fake_conf, self.blacklist_cfg, + mech_ovs_conf.register_ovs_mech_driver_opts) + self.useFixture(fake_conf_fixture) + + test_driver = mech_openvswitch.OpenvswitchMechanismDriver() + + supported_vnic_types = test_driver.supported_vnic_types + self.assertNotIn(portbindings.VNIC_DIRECT, supported_vnic_types) + self.assertEqual(len(self.default_supported_vnics) - 1, + len(supported_vnic_types)) + + def test_vnic_type_blacklist_not_valid_item(self): + self.blacklist_cfg['OVS_DRIVER']['vnic_type_blacklist'] = ['foo'] + + fake_conf = cfg.CONF + fake_conf_fixture = base.MechDriverConfFixture( + fake_conf, self.blacklist_cfg, + mech_ovs_conf.register_ovs_mech_driver_opts) + self.useFixture(fake_conf_fixture) + + self.assertRaises(ValueError, + mech_openvswitch.OpenvswitchMechanismDriver) + + def test_vnic_type_blacklist_all_items(self): + self.blacklist_cfg['OVS_DRIVER']['vnic_type_blacklist'] = \ + [portbindings.VNIC_NORMAL, portbindings.VNIC_DIRECT] + fake_conf = cfg.CONF + fake_conf_fixture = base.MechDriverConfFixture( + fake_conf, self.blacklist_cfg, + mech_ovs_conf.register_ovs_mech_driver_opts) + self.useFixture(fake_conf_fixture) + + self.assertRaises(ValueError, + mech_openvswitch.OpenvswitchMechanismDriver) diff --git a/releasenotes/notes/make-supported-vnic-types-configurable-for-ovs-fc73422daffd42b0.yaml b/releasenotes/notes/make-supported-vnic-types-configurable-for-ovs-fc73422daffd42b0.yaml new file mode 100644 index 00000000000..f612fdd2da3 --- /dev/null +++ b/releasenotes/notes/make-supported-vnic-types-configurable-for-ovs-fc73422daffd42b0.yaml @@ -0,0 +1,9 @@ +--- +other: + - | + Add new configuration group ``ovs_driver`` and new configuration option + under it ``vnic_type_blacklist``, to make the previously hardcoded + ``supported_vnic_types`` parameter of the OpenvswitchMechanismDriver + configurable. + The ``vnic_types`` listed in the blacklist will be removed from the + supported_vnic_types list.