From becfd6ebe603d5bac0148afb1e0892eaa3e325e5 Mon Sep 17 00:00:00 2001 From: Moshe Levi Date: Tue, 11 Aug 2015 07:08:11 +0300 Subject: [PATCH] SR-IOV: Convert max rate from kbps to Mbps ip link tool configures max rate in Mbps and it the QoS model max rate is defined in kbps. This patch convert the max rate from kbps to Mbps. Also because zero disables the rate limit the min value is 1Mbps and not 1kbps. DocImpact Partially-Implements: blueprint ml2-sriov-qos-with-bwlimiting Change-Id: I91b08c5d8ccaa2867b6eafd0c86872f401dd04c8 --- neutron/common/utils.py | 8 +++++ .../mech_sriov/agent/eswitch_manager.py | 26 +++++++++++++- .../ml2/drivers/mech_sriov/agent/pci_lib.py | 2 +- neutron/tests/unit/common/test_utils.py | 10 ++++++ .../mech_sriov/agent/test_eswitch_manager.py | 35 +++++++++++++++++-- 5 files changed, 77 insertions(+), 4 deletions(-) diff --git a/neutron/common/utils.py b/neutron/common/utils.py index 579766fb4..6c9d9b17b 100644 --- a/neutron/common/utils.py +++ b/neutron/common/utils.py @@ -19,6 +19,7 @@ """Utilities and helper functions.""" import datetime +import decimal import errno import functools import hashlib @@ -442,3 +443,10 @@ class DelayedStringRenderer(object): def camelize(s): return ''.join(s.replace('_', ' ').title().split()) + + +def round_val(val): + # we rely on decimal module since it behaves consistently across Python + # versions (2.x vs. 3.x) + return int(decimal.Decimal(val).quantize(decimal.Decimal('1'), + rounding=decimal.ROUND_HALF_UP)) diff --git a/neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py b/neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py index 0bfb0e0f8..938db4590 100644 --- a/neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py +++ b/neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py @@ -20,6 +20,7 @@ import re from oslo_log import log as logging import six +from neutron.common import utils from neutron.i18n import _LE, _LW from neutron.plugins.ml2.drivers.mech_sriov.agent.common \ import exceptions as exc @@ -163,7 +164,30 @@ class EmbSwitch(object): @param max_kbps: device max rate in kbps """ vf_index = self._get_vf_index(pci_slot) - return self.pci_dev_wrapper.set_vf_max_rate(vf_index, max_kbps) + #(Note): ip link set max rate in Mbps therefore + #we need to convert the max_kbps to Mbps. + #Zero means to disable the rate so the lowest rate + #available is 1Mbps. Floating numbers are not allowed + if max_kbps > 0 and max_kbps < 1000: + max_mbps = 1 + else: + max_mbps = utils.round_val(max_kbps / 1000.0) + + log_dict = { + 'max_rate': max_mbps, + 'max_kbps': max_kbps, + 'vf_index': vf_index + } + if max_kbps % 1000 != 0: + LOG.debug("Maximum rate for SR-IOV ports is counted in Mbps; " + "setting %(max_rate)s Mbps limit for port %(vf_index)s " + "instead of %(max_kbps)s kbps", + log_dict) + else: + LOG.debug("Setting %(max_rate)s Mbps limit for port %(vf_index)s", + log_dict) + + return self.pci_dev_wrapper.set_vf_max_rate(vf_index, max_mbps) def _get_vf_index(self, pci_slot): vf_index = self.pci_slot_map.get(pci_slot) 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 a1e31cd66..8f984e0aa 100644 --- a/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py +++ b/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py @@ -126,7 +126,7 @@ class PciDeviceIPWrapper(ip_lib.IPWrapper): """sets vf max rate. @param vf_index: vf index - @param max_tx_rate: vf max tx rate + @param max_tx_rate: vf max tx rate in Mbps """ try: self._as_root([], "link", ("set", self.dev_name, "vf", diff --git a/neutron/tests/unit/common/test_utils.py b/neutron/tests/unit/common/test_utils.py index 20e764bfa..b604bbb27 100644 --- a/neutron/tests/unit/common/test_utils.py +++ b/neutron/tests/unit/common/test_utils.py @@ -690,3 +690,13 @@ class TestCamelize(base.BaseTestCase): for s, expected in data.items(): self.assertEqual(expected, utils.camelize(s)) + + +class TestRoundVal(base.BaseTestCase): + def test_round_val_ok(self): + for expected, value in ((0, 0), + (0, 0.1), + (1, 0.5), + (1, 1.49), + (2, 1.5)): + self.assertEqual(expected, utils.round_val(value)) diff --git a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py index e131dc1eb..2d30a0507 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py +++ b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py @@ -277,8 +277,39 @@ class TestEmbSwitch(base.BaseTestCase): def test_set_device_max_rate_ok(self): with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib." - "PciDeviceIPWrapper.set_vf_max_rate"): - self.emb_switch.set_device_max_rate(self.PCI_SLOT, 1000) + "PciDeviceIPWrapper.set_vf_max_rate") as pci_lib_mock: + self.emb_switch.set_device_max_rate(self.PCI_SLOT, 2000) + pci_lib_mock.assert_called_with(0, 2) + + def test_set_device_max_rate_ok2(self): + with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib." + "PciDeviceIPWrapper.set_vf_max_rate") as pci_lib_mock: + self.emb_switch.set_device_max_rate(self.PCI_SLOT, 99) + pci_lib_mock.assert_called_with(0, 1) + + def test_set_device_max_rate_rounded_ok(self): + with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib." + "PciDeviceIPWrapper.set_vf_max_rate") as pci_lib_mock: + self.emb_switch.set_device_max_rate(self.PCI_SLOT, 2001) + pci_lib_mock.assert_called_with(0, 2) + + def test_set_device_max_rate_rounded_ok2(self): + with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib." + "PciDeviceIPWrapper.set_vf_max_rate") as pci_lib_mock: + self.emb_switch.set_device_max_rate(self.PCI_SLOT, 2499) + pci_lib_mock.assert_called_with(0, 2) + + def test_set_device_max_rate_rounded_ok3(self): + with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib." + "PciDeviceIPWrapper.set_vf_max_rate") as pci_lib_mock: + self.emb_switch.set_device_max_rate(self.PCI_SLOT, 2500) + pci_lib_mock.assert_called_with(0, 3) + + def test_set_device_max_rate_disable(self): + with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib." + "PciDeviceIPWrapper.set_vf_max_rate") as pci_lib_mock: + self.emb_switch.set_device_max_rate(self.PCI_SLOT, 0) + pci_lib_mock.assert_called_with(0, 0) def test_set_device_max_rate_fail(self): with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib." -- 2.45.2