diff --git a/neutron/cmd/sanity/checks.py b/neutron/cmd/sanity/checks.py index 5cfd039b45d..4fd1bec0344 100644 --- a/neutron/cmd/sanity/checks.py +++ b/neutron/cmd/sanity/checks.py @@ -21,6 +21,7 @@ import tempfile import netaddr from neutron_lib import constants as n_consts from neutron_lib import exceptions +from neutron_lib.utils import helpers from oslo_config import cfg from oslo_log import log as logging from oslo_utils import uuidutils @@ -515,3 +516,36 @@ def gre_conntrack_supported(): return agent_utils.execute(cmd, log_fail_as_error=False) except exceptions.ProcessExecutionError: return False + + +def min_tx_rate_support(): + device_mappings = helpers.parse_mappings( + cfg.CONF.SRIOV_NIC.physical_device_mappings, unique_keys=False) + devices_to_test = set() + for devices_in_physnet in device_mappings.values(): + for device in devices_in_physnet: + devices_to_test.add(device) + + # NOTE(ralonsoh): the VF used by default is 0. Each SR-IOV configured + # NIC should have configured at least 1 VF. + VF_NUM = 0 + devices_without_support = set() + for device in devices_to_test: + try: + ip_link = ip_lib.IpLinkCommand(device) + # NOTE(ralonsoh): to set min_tx_rate, first is needed to set + # max_tx_rate and max_tx_rate >= min_tx_rate. + vf_config = {'vf': VF_NUM, 'rate': {'min_tx_rate': int(400), + 'max_tx_rate': int(500)}} + ip_link.set_vf_feature(vf_config) + vf_config = {'vf': VF_NUM, 'rate': {'min_tx_rate': 0, + 'max_tx_rate': 0}} + ip_link.set_vf_feature(vf_config) + except ip_lib.InvalidArgument: + devices_without_support.add(device) + + if devices_without_support: + LOG.debug('The following NICs do not support "min_tx_rate": %s', + devices_without_support) + return False + return True diff --git a/neutron/cmd/sanity_check.py b/neutron/cmd/sanity_check.py index 86888a17187..5d26af2d19c 100644 --- a/neutron/cmd/sanity_check.py +++ b/neutron/cmd/sanity_check.py @@ -288,6 +288,15 @@ def check_ip_nonlocal_bind(): return result +def check_min_tx_rate_support(): + result = checks.min_tx_rate_support() + if not result: + LOG.warning('There are SR-IOV network interfaces that do not support ' + 'setting the minimum TX rate (dataplane enforced minimum ' + 'guaranteed bandwidth) "ip-link vf min_tx_rate".') + return result + + # Define CLI opts to test specific features, with a callback for the test OPTS = [ BoolOptCallback('ovs_vxlan', check_ovs_vxlan, default=False, @@ -348,6 +357,10 @@ OPTS = [ help=_('Check ip_nonlocal_bind kernel option works with ' 'network namespaces.'), default=False), + BoolOptCallback('check_min_tx_rate_support', check_min_tx_rate_support, + help=_('Check if the configured SR-IOV NICs support ' + 'the "ip-link vf min_tx_rate" parameter.'), + default=False), ] @@ -396,6 +409,8 @@ def enable_tests_from_config(): 'OVSHybridIptablesFirewallDriver'), ): cfg.CONF.set_default('bridge_firewalling', True) + if cfg.CONF.SRIOV_NIC.physical_device_mappings: + cfg.CONF.set_default('check_min_tx_rate_support', True) def all_tests_passed(): diff --git a/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py b/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py index ebc1c51ecb0..4c288745233 100644 --- a/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py +++ b/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py @@ -100,4 +100,11 @@ class PciDeviceIPWrapper(ip_lib.IPWrapper): """ ip = self.device(self.dev_name) vf_config = {'vf': vf_index, 'rate': {rate_type: int(rate_value)}} - ip.link.set_vf_feature(vf_config) + try: + ip.link.set_vf_feature(vf_config) + except ip_lib.InvalidArgument: + # NOTE(ralonsoh): some NICs do not support "min_tx_rate" parameter. + # https://bugs.launchpad.net/neutron/+bug/1918464 + LOG.error('Device %(device)s does not support ip-link vf ' + '"%(rate_type)s" parameter.', + {'device': self.dev_name, 'rate_type': rate_type}) diff --git a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_pci_lib.py b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_pci_lib.py index 94497e4ad5b..6bbd6ab78b7 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_pci_lib.py +++ b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_pci_lib.py @@ -101,3 +101,13 @@ class TestPciLib(base.BaseTestCase): self.pci_wrapper.set_vf_rate(self.VF_INDEX, 'min_tx_rate', 10) vf = {'vf': self.VF_INDEX, 'rate': {'min_tx_rate': 10}} self.mock_ip_device.link.set_vf_feature.assert_called_once_with(vf) + + @mock.patch.object(pci_lib, 'LOG') + def test_set_vf_rate_exception(self, mock_log): + self.mock_ip_device.link.set_vf_feature.side_effect = ( + ip_lib.InvalidArgument) + self.pci_wrapper.set_vf_rate(self.VF_INDEX, 'min_tx_rate', 10) + mock_log.error.assert_called_once_with( + 'Device %(device)s does not support ip-link vf "%(rate_type)s" ' + 'parameter.', {'device': self.DEV_NAME, 'rate_type': 'min_tx_rate'} + )