Fix ingress bw limit for OVS DPDK ports
For OVS based DPDK ports ingress bandwidth limit is now implemented using egress-policer qos type. Additionally limit values are set in other_config of QoS because there is no queue used in this case. This patch moves also helper methods used to conversion between bytes and bits and between bits and kilobits to neutron.common.utils to be able to use it also in ovs_lib module. Change-Id: I94d1e8dfb82df5c602476db8aaa884ae91fecd7f Closes-Bug: #1724729
This commit is contained in:
parent
ea4c9fae71
commit
1be8574352
@ -31,6 +31,8 @@ from neutron._i18n import _
|
|||||||
from neutron.agent.common import ip_lib
|
from neutron.agent.common import ip_lib
|
||||||
from neutron.agent.common import utils
|
from neutron.agent.common import utils
|
||||||
from neutron.agent.ovsdb import api as ovsdb_api
|
from neutron.agent.ovsdb import api as ovsdb_api
|
||||||
|
from neutron.common import constants as common_constants
|
||||||
|
from neutron.common import utils as common_utils
|
||||||
from neutron.conf.agent import ovs_conf
|
from neutron.conf.agent import ovs_conf
|
||||||
from neutron.plugins.ml2.drivers.openvswitch.agent.common \
|
from neutron.plugins.ml2.drivers.openvswitch.agent.common \
|
||||||
import constants
|
import constants
|
||||||
@ -732,16 +734,27 @@ class OVSBridge(BaseOVS):
|
|||||||
other_config=qos_other_config))
|
other_config=qos_other_config))
|
||||||
return qos_uuid
|
return qos_uuid
|
||||||
|
|
||||||
def update_ingress_bw_limit_for_port(self, port_name, max_kbps,
|
def _update_bw_limit_profile_dpdk(self, txn, port_name, qos_uuid,
|
||||||
max_burst_kbps):
|
other_config):
|
||||||
max_bw_in_bits = str(max_kbps * 1000)
|
if qos_uuid:
|
||||||
max_burst_in_bits = str(max_burst_kbps * 1000)
|
txn.add(self.ovsdb.db_set(
|
||||||
|
'QoS', qos_uuid, ('other_config', other_config)))
|
||||||
|
else:
|
||||||
|
external_ids = {'id': port_name}
|
||||||
|
qos_uuid = txn.add(
|
||||||
|
self.ovsdb.db_create(
|
||||||
|
'QoS', external_ids=external_ids, type='egress-policer',
|
||||||
|
other_config=other_config))
|
||||||
|
return qos_uuid
|
||||||
|
|
||||||
|
def _update_ingress_bw_limit_for_port(
|
||||||
|
self, port_name, max_bw_in_bits, max_burst_in_bits):
|
||||||
qos_other_config = {
|
qos_other_config = {
|
||||||
'max-rate': max_bw_in_bits
|
'max-rate': str(max_bw_in_bits)
|
||||||
}
|
}
|
||||||
queue_other_config = {
|
queue_other_config = {
|
||||||
'max-rate': max_bw_in_bits,
|
'max-rate': str(max_bw_in_bits),
|
||||||
'burst': max_burst_in_bits,
|
'burst': str(max_burst_in_bits),
|
||||||
}
|
}
|
||||||
qos = self.find_qos(port_name)
|
qos = self.find_qos(port_name)
|
||||||
queue = self.find_queue(port_name, QOS_DEFAULT_QUEUE)
|
queue = self.find_queue(port_name, QOS_DEFAULT_QUEUE)
|
||||||
@ -761,6 +774,33 @@ class OVSBridge(BaseOVS):
|
|||||||
txn.add(self.ovsdb.db_set(
|
txn.add(self.ovsdb.db_set(
|
||||||
'Port', port_name, ('qos', qos_uuid)))
|
'Port', port_name, ('qos', qos_uuid)))
|
||||||
|
|
||||||
|
def _update_ingress_bw_limit_for_dpdk_port(
|
||||||
|
self, port_name, max_bw_in_bits, max_burst_in_bits):
|
||||||
|
# cir and cbs should be set in bytes instead of bits
|
||||||
|
qos_other_config = {
|
||||||
|
'cir': str(max_bw_in_bits / 8),
|
||||||
|
'cbs': str(max_burst_in_bits / 8)
|
||||||
|
}
|
||||||
|
qos = self.find_qos(port_name)
|
||||||
|
qos_uuid = qos['_uuid'] if qos else None
|
||||||
|
with self.ovsdb.transaction(check_error=True) as txn:
|
||||||
|
qos_uuid = self._update_bw_limit_profile_dpdk(
|
||||||
|
txn, port_name, qos_uuid, qos_other_config)
|
||||||
|
txn.add(self.ovsdb.db_set(
|
||||||
|
'Port', port_name, ('qos', qos_uuid)))
|
||||||
|
|
||||||
|
def update_ingress_bw_limit_for_port(self, port_name, max_kbps,
|
||||||
|
max_burst_kbps):
|
||||||
|
max_bw_in_bits = max_kbps * common_constants.SI_BASE
|
||||||
|
max_burst_in_bits = max_burst_kbps * common_constants.SI_BASE
|
||||||
|
port_type = self._get_port_val(port_name, "type")
|
||||||
|
if port_type in constants.OVS_DPDK_PORT_TYPES:
|
||||||
|
self._update_ingress_bw_limit_for_dpdk_port(
|
||||||
|
port_name, max_bw_in_bits, max_burst_in_bits)
|
||||||
|
else:
|
||||||
|
self._update_ingress_bw_limit_for_port(
|
||||||
|
port_name, max_bw_in_bits, max_burst_in_bits)
|
||||||
|
|
||||||
def get_ingress_bw_limit_for_port(self, port_name):
|
def get_ingress_bw_limit_for_port(self, port_name):
|
||||||
max_kbps = None
|
max_kbps = None
|
||||||
qos_max_kbps = None
|
qos_max_kbps = None
|
||||||
@ -772,17 +812,18 @@ class OVSBridge(BaseOVS):
|
|||||||
other_config = qos_res['other_config']
|
other_config = qos_res['other_config']
|
||||||
max_bw_in_bits = other_config.get('max-rate')
|
max_bw_in_bits = other_config.get('max-rate')
|
||||||
if max_bw_in_bits is not None:
|
if max_bw_in_bits is not None:
|
||||||
qos_max_kbps = int(max_bw_in_bits) / 1000
|
qos_max_kbps = int(max_bw_in_bits) / common_constants.SI_BASE
|
||||||
|
|
||||||
queue_res = self.find_queue(port_name, QOS_DEFAULT_QUEUE)
|
queue_res = self.find_queue(port_name, QOS_DEFAULT_QUEUE)
|
||||||
if queue_res:
|
if queue_res:
|
||||||
other_config = queue_res['other_config']
|
other_config = queue_res['other_config']
|
||||||
max_bw_in_bits = other_config.get('max-rate')
|
max_bw_in_bits = other_config.get('max-rate')
|
||||||
if max_bw_in_bits is not None:
|
if max_bw_in_bits is not None:
|
||||||
queue_max_kbps = int(max_bw_in_bits) / 1000
|
queue_max_kbps = int(max_bw_in_bits) / common_constants.SI_BASE
|
||||||
max_burst_in_bits = other_config.get('burst')
|
max_burst_in_bits = other_config.get('burst')
|
||||||
if max_burst_in_bits is not None:
|
if max_burst_in_bits is not None:
|
||||||
max_burst_kbit = int(max_burst_in_bits) / 1000
|
max_burst_kbit = (
|
||||||
|
int(max_burst_in_bits) / common_constants.SI_BASE)
|
||||||
|
|
||||||
if qos_max_kbps == queue_max_kbps:
|
if qos_max_kbps == queue_max_kbps:
|
||||||
max_kbps = qos_max_kbps
|
max_kbps = qos_max_kbps
|
||||||
@ -791,7 +832,24 @@ class OVSBridge(BaseOVS):
|
|||||||
"queue max-rate %(queue_max_kbps)s",
|
"queue max-rate %(queue_max_kbps)s",
|
||||||
{'qos_max_kbps': qos_max_kbps,
|
{'qos_max_kbps': qos_max_kbps,
|
||||||
'queue_max_kbps': queue_max_kbps})
|
'queue_max_kbps': queue_max_kbps})
|
||||||
|
return max_kbps, max_burst_kbit
|
||||||
|
|
||||||
|
def get_ingress_bw_limit_for_dpdk_port(self, port_name):
|
||||||
|
max_kbps = None
|
||||||
|
max_burst_kbit = None
|
||||||
|
res = self.find_qos(port_name)
|
||||||
|
if res:
|
||||||
|
other_config = res['other_config']
|
||||||
|
max_bw_in_bytes = other_config.get("cir")
|
||||||
|
if max_bw_in_bytes is not None:
|
||||||
|
max_kbps = common_utils.bits_to_kilobits(
|
||||||
|
common_utils.bytes_to_bits(int(max_bw_in_bytes)),
|
||||||
|
common_constants.SI_BASE)
|
||||||
|
max_burst_in_bytes = other_config.get("cbs")
|
||||||
|
if max_burst_in_bytes is not None:
|
||||||
|
max_burst_kbit = common_utils.bits_to_kilobits(
|
||||||
|
common_utils.bytes_to_bits(int(max_burst_in_bytes)),
|
||||||
|
common_constants.SI_BASE)
|
||||||
return max_kbps, max_burst_kbit
|
return max_kbps, max_burst_kbit
|
||||||
|
|
||||||
def delete_ingress_bw_limit_for_port(self, port_name):
|
def delete_ingress_bw_limit_for_port(self, port_name):
|
||||||
|
@ -20,14 +20,13 @@ from neutron_lib.services.qos import constants as qos_consts
|
|||||||
|
|
||||||
from neutron._i18n import _
|
from neutron._i18n import _
|
||||||
from neutron.agent.linux import ip_lib
|
from neutron.agent.linux import ip_lib
|
||||||
|
from neutron.common import constants
|
||||||
|
from neutron.common import utils
|
||||||
|
|
||||||
|
|
||||||
INGRESS_QDISC_ID = "ffff:"
|
INGRESS_QDISC_ID = "ffff:"
|
||||||
MAX_MTU_VALUE = 65535
|
MAX_MTU_VALUE = 65535
|
||||||
|
|
||||||
SI_BASE = 1000
|
|
||||||
IEC_BASE = 1024
|
|
||||||
|
|
||||||
LATENCY_UNIT = "ms"
|
LATENCY_UNIT = "ms"
|
||||||
BW_LIMIT_UNIT = "kbit" # kilobits per second in tc's notation
|
BW_LIMIT_UNIT = "kbit" # kilobits per second in tc's notation
|
||||||
BURST_UNIT = "kbit" # kilobits in tc's notation
|
BURST_UNIT = "kbit" # kilobits in tc's notation
|
||||||
@ -66,10 +65,10 @@ def convert_to_kilobits(value, base):
|
|||||||
if value.isdigit():
|
if value.isdigit():
|
||||||
value = int(value)
|
value = int(value)
|
||||||
if input_in_bits:
|
if input_in_bits:
|
||||||
return bits_to_kilobits(value, base)
|
return utils.bits_to_kilobits(value, base)
|
||||||
else:
|
else:
|
||||||
bits_value = bytes_to_bits(value)
|
bits_value = utils.bytes_to_bits(value)
|
||||||
return bits_to_kilobits(bits_value, base)
|
return utils.bits_to_kilobits(bits_value, base)
|
||||||
unit = value[-1:]
|
unit = value[-1:]
|
||||||
if unit not in UNITS.keys():
|
if unit not in UNITS.keys():
|
||||||
raise InvalidUnit(unit=unit)
|
raise InvalidUnit(unit=unit)
|
||||||
@ -77,17 +76,8 @@ def convert_to_kilobits(value, base):
|
|||||||
if input_in_bits:
|
if input_in_bits:
|
||||||
bits_value = val * (base ** UNITS[unit])
|
bits_value = val * (base ** UNITS[unit])
|
||||||
else:
|
else:
|
||||||
bits_value = bytes_to_bits(val * (base ** UNITS[unit]))
|
bits_value = utils.bytes_to_bits(val * (base ** UNITS[unit]))
|
||||||
return bits_to_kilobits(bits_value, base)
|
return utils.bits_to_kilobits(bits_value, base)
|
||||||
|
|
||||||
|
|
||||||
def bytes_to_bits(value):
|
|
||||||
return value * 8
|
|
||||||
|
|
||||||
|
|
||||||
def bits_to_kilobits(value, base):
|
|
||||||
#NOTE(slaweq): round up that even 1 bit will give 1 kbit as a result
|
|
||||||
return int((value + (base - 1)) / base)
|
|
||||||
|
|
||||||
|
|
||||||
class TcCommand(ip_lib.IPDevice):
|
class TcCommand(ip_lib.IPDevice):
|
||||||
@ -124,10 +114,11 @@ class TcCommand(ip_lib.IPDevice):
|
|||||||
if m:
|
if m:
|
||||||
#NOTE(slaweq): because tc is giving bw limit in SI units
|
#NOTE(slaweq): because tc is giving bw limit in SI units
|
||||||
# we need to calculate it as 1000bit = 1kbit:
|
# we need to calculate it as 1000bit = 1kbit:
|
||||||
bw_limit = convert_to_kilobits(m.group(1), SI_BASE)
|
bw_limit = convert_to_kilobits(m.group(1), constants.SI_BASE)
|
||||||
#NOTE(slaweq): because tc is giving burst limit in IEC units
|
#NOTE(slaweq): because tc is giving burst limit in IEC units
|
||||||
# we need to calculate it as 1024bit = 1kbit:
|
# we need to calculate it as 1024bit = 1kbit:
|
||||||
burst_limit = convert_to_kilobits(m.group(2), IEC_BASE)
|
burst_limit = convert_to_kilobits(
|
||||||
|
m.group(2), constants.IEC_BASE)
|
||||||
return bw_limit, burst_limit
|
return bw_limit, burst_limit
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
@ -144,10 +135,10 @@ class TcCommand(ip_lib.IPDevice):
|
|||||||
return None, None
|
return None, None
|
||||||
#NOTE(slaweq): because tc is giving bw limit in SI units
|
#NOTE(slaweq): because tc is giving bw limit in SI units
|
||||||
# we need to calculate it as 1000bit = 1kbit:
|
# we need to calculate it as 1000bit = 1kbit:
|
||||||
bw_limit = convert_to_kilobits(m.group(2), SI_BASE)
|
bw_limit = convert_to_kilobits(m.group(2), constants.SI_BASE)
|
||||||
#NOTE(slaweq): because tc is giving burst limit in IEC units
|
#NOTE(slaweq): because tc is giving burst limit in IEC units
|
||||||
# we need to calculate it as 1024bit = 1kbit:
|
# we need to calculate it as 1024bit = 1kbit:
|
||||||
burst_limit = convert_to_kilobits(m.group(3), IEC_BASE)
|
burst_limit = convert_to_kilobits(m.group(3), constants.IEC_BASE)
|
||||||
return bw_limit, burst_limit
|
return bw_limit, burst_limit
|
||||||
|
|
||||||
def set_filters_bw_limit(self, bw_limit, burst_limit):
|
def set_filters_bw_limit(self, bw_limit, burst_limit):
|
||||||
|
@ -222,3 +222,7 @@ FLOATING_IP_HOST_NEEDS_BINDING = "FLOATING_IP_HOST_NEEDS_BINDING"
|
|||||||
# Possible types of values (e.g. in QoS rule types)
|
# Possible types of values (e.g. in QoS rule types)
|
||||||
VALUES_TYPE_CHOICES = "choices"
|
VALUES_TYPE_CHOICES = "choices"
|
||||||
VALUES_TYPE_RANGE = "range"
|
VALUES_TYPE_RANGE = "range"
|
||||||
|
|
||||||
|
# Units base
|
||||||
|
SI_BASE = 1000
|
||||||
|
IEC_BASE = 1024
|
||||||
|
@ -801,3 +801,12 @@ def resolve_ref(ref):
|
|||||||
if isinstance(ref, weakref.ref):
|
if isinstance(ref, weakref.ref):
|
||||||
ref = ref()
|
ref = ref()
|
||||||
return ref
|
return ref
|
||||||
|
|
||||||
|
|
||||||
|
def bytes_to_bits(value):
|
||||||
|
return value * 8
|
||||||
|
|
||||||
|
|
||||||
|
def bits_to_kilobits(value, base):
|
||||||
|
#NOTE(slaweq): round up that even 1 bit will give 1 kbit as a result
|
||||||
|
return int((value + (base - 1)) / base)
|
||||||
|
@ -137,6 +137,8 @@ OVS_DATAPATH_NETDEV = 'netdev'
|
|||||||
OVS_DPDK_VHOST_USER = 'dpdkvhostuser'
|
OVS_DPDK_VHOST_USER = 'dpdkvhostuser'
|
||||||
OVS_DPDK_VHOST_USER_CLIENT = 'dpdkvhostuserclient'
|
OVS_DPDK_VHOST_USER_CLIENT = 'dpdkvhostuserclient'
|
||||||
|
|
||||||
|
OVS_DPDK_PORT_TYPES = [OVS_DPDK_VHOST_USER, OVS_DPDK_VHOST_USER_CLIENT]
|
||||||
|
|
||||||
# default ovs vhost-user socket location
|
# default ovs vhost-user socket location
|
||||||
VHOST_USER_SOCKET_DIR = '/var/run/openvswitch'
|
VHOST_USER_SOCKET_DIR = '/var/run/openvswitch'
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ from neutron.agent.common import ovs_lib
|
|||||||
from neutron.agent.linux import ip_lib
|
from neutron.agent.linux import ip_lib
|
||||||
from neutron.agent.ovsdb.native import idlutils
|
from neutron.agent.ovsdb.native import idlutils
|
||||||
from neutron.common import utils
|
from neutron.common import utils
|
||||||
|
from neutron.plugins.ml2.drivers.openvswitch.agent.common import (
|
||||||
|
constants as agent_const)
|
||||||
from neutron.tests.common.exclusive_resources import port
|
from neutron.tests.common.exclusive_resources import port
|
||||||
from neutron.tests.common import net_helpers
|
from neutron.tests.common import net_helpers
|
||||||
from neutron.tests.functional.agent.linux import base
|
from neutron.tests.functional.agent.linux import base
|
||||||
@ -392,6 +394,27 @@ class OVSBridgeTestCase(OVSBridgeTestBase):
|
|||||||
self.assertIsNone(max_rate)
|
self.assertIsNone(max_rate)
|
||||||
self.assertIsNone(burst)
|
self.assertIsNone(burst)
|
||||||
|
|
||||||
|
def test_ingress_bw_limit_dpdk_port(self):
|
||||||
|
port_name, _ = self.create_ovs_port(
|
||||||
|
('type', agent_const.OVS_DPDK_VHOST_USER))
|
||||||
|
self.br.update_ingress_bw_limit_for_port(port_name, 700, 70)
|
||||||
|
max_rate, burst = self.br.get_ingress_bw_limit_for_dpdk_port(
|
||||||
|
port_name)
|
||||||
|
self.assertEqual(700, max_rate)
|
||||||
|
self.assertEqual(70, burst)
|
||||||
|
|
||||||
|
self.br.update_ingress_bw_limit_for_port(port_name, 750, 100)
|
||||||
|
max_rate, burst = self.br.get_ingress_bw_limit_for_dpdk_port(
|
||||||
|
port_name)
|
||||||
|
self.assertEqual(750, max_rate)
|
||||||
|
self.assertEqual(100, burst)
|
||||||
|
|
||||||
|
self.br.delete_ingress_bw_limit_for_port(port_name)
|
||||||
|
max_rate, burst = self.br.get_ingress_bw_limit_for_dpdk_port(
|
||||||
|
port_name)
|
||||||
|
self.assertIsNone(max_rate)
|
||||||
|
self.assertIsNone(burst)
|
||||||
|
|
||||||
def test_db_create_references(self):
|
def test_db_create_references(self):
|
||||||
with self.ovs.ovsdb.transaction(check_error=True) as txn:
|
with self.ovs.ovsdb.transaction(check_error=True) as txn:
|
||||||
queue = txn.add(self.ovs.ovsdb.db_create("Queue",
|
queue = txn.add(self.ovs.ovsdb.db_create("Queue",
|
||||||
|
@ -17,6 +17,8 @@ import mock
|
|||||||
from neutron_lib.services.qos import constants as qos_consts
|
from neutron_lib.services.qos import constants as qos_consts
|
||||||
|
|
||||||
from neutron.agent.linux import tc_lib
|
from neutron.agent.linux import tc_lib
|
||||||
|
from neutron.common import constants
|
||||||
|
from neutron.common import utils
|
||||||
from neutron.tests import base
|
from neutron.tests import base
|
||||||
|
|
||||||
DEVICE_NAME = "tap_device"
|
DEVICE_NAME = "tap_device"
|
||||||
@ -58,7 +60,7 @@ class BaseUnitConversionTest(object):
|
|||||||
|
|
||||||
def test_convert_to_kilobits_bits_value(self):
|
def test_convert_to_kilobits_bits_value(self):
|
||||||
value = "1000bit"
|
value = "1000bit"
|
||||||
expected_value = tc_lib.bits_to_kilobits(1000, self.base_unit)
|
expected_value = utils.bits_to_kilobits(1000, self.base_unit)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected_value,
|
expected_value,
|
||||||
tc_lib.convert_to_kilobits(value, self.base_unit)
|
tc_lib.convert_to_kilobits(value, self.base_unit)
|
||||||
@ -66,7 +68,7 @@ class BaseUnitConversionTest(object):
|
|||||||
|
|
||||||
def test_convert_to_kilobits_megabytes_value(self):
|
def test_convert_to_kilobits_megabytes_value(self):
|
||||||
value = "1m"
|
value = "1m"
|
||||||
expected_value = tc_lib.bits_to_kilobits(
|
expected_value = utils.bits_to_kilobits(
|
||||||
self.base_unit ** 2 * 8, self.base_unit)
|
self.base_unit ** 2 * 8, self.base_unit)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected_value,
|
expected_value,
|
||||||
@ -75,7 +77,7 @@ class BaseUnitConversionTest(object):
|
|||||||
|
|
||||||
def test_convert_to_kilobits_megabits_value(self):
|
def test_convert_to_kilobits_megabits_value(self):
|
||||||
value = "1mbit"
|
value = "1mbit"
|
||||||
expected_value = tc_lib.bits_to_kilobits(
|
expected_value = utils.bits_to_kilobits(
|
||||||
self.base_unit ** 2, self.base_unit)
|
self.base_unit ** 2, self.base_unit)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected_value,
|
expected_value,
|
||||||
@ -89,53 +91,15 @@ class BaseUnitConversionTest(object):
|
|||||||
tc_lib.convert_to_kilobits, value, self.base_unit
|
tc_lib.convert_to_kilobits, value, self.base_unit
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_bytes_to_bits(self):
|
|
||||||
test_values = [
|
|
||||||
(0, 0), # 0 bytes should be 0 bits
|
|
||||||
(1, 8) # 1 byte should be 8 bits
|
|
||||||
]
|
|
||||||
for input_bytes, expected_bits in test_values:
|
|
||||||
self.assertEqual(
|
|
||||||
expected_bits, tc_lib.bytes_to_bits(input_bytes)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TestSIUnitConversions(BaseUnitConversionTest, base.BaseTestCase):
|
class TestSIUnitConversions(BaseUnitConversionTest, base.BaseTestCase):
|
||||||
|
|
||||||
base_unit = tc_lib.SI_BASE
|
base_unit = constants.SI_BASE
|
||||||
|
|
||||||
def test_bits_to_kilobits(self):
|
|
||||||
test_values = [
|
|
||||||
(0, 0), # 0 bites should be 0 kilobites
|
|
||||||
(1, 1), # 1 bit should be 1 kilobit
|
|
||||||
(999, 1), # 999 bits should be 1 kilobit
|
|
||||||
(1000, 1), # 1000 bits should be 1 kilobit
|
|
||||||
(1001, 2) # 1001 bits should be 2 kilobits
|
|
||||||
]
|
|
||||||
for input_bits, expected_kilobits in test_values:
|
|
||||||
self.assertEqual(
|
|
||||||
expected_kilobits,
|
|
||||||
tc_lib.bits_to_kilobits(input_bits, self.base_unit)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TestIECUnitConversions(BaseUnitConversionTest, base.BaseTestCase):
|
class TestIECUnitConversions(BaseUnitConversionTest, base.BaseTestCase):
|
||||||
|
|
||||||
base_unit = tc_lib.IEC_BASE
|
base_unit = constants.IEC_BASE
|
||||||
|
|
||||||
def test_bits_to_kilobits(self):
|
|
||||||
test_values = [
|
|
||||||
(0, 0), # 0 bites should be 0 kilobites
|
|
||||||
(1, 1), # 1 bit should be 1 kilobit
|
|
||||||
(1023, 1), # 1023 bits should be 1 kilobit
|
|
||||||
(1024, 1), # 1024 bits should be 1 kilobit
|
|
||||||
(1025, 2) # 1025 bits should be 2 kilobits
|
|
||||||
]
|
|
||||||
for input_bits, expected_kilobits in test_values:
|
|
||||||
self.assertEqual(
|
|
||||||
expected_kilobits,
|
|
||||||
tc_lib.bits_to_kilobits(input_bits, self.base_unit)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TestTcCommand(base.BaseTestCase):
|
class TestTcCommand(base.BaseTestCase):
|
||||||
|
@ -28,6 +28,7 @@ import six
|
|||||||
import testscenarios
|
import testscenarios
|
||||||
import testtools
|
import testtools
|
||||||
|
|
||||||
|
from neutron.common import constants as common_constants
|
||||||
from neutron.common import exceptions as n_exc
|
from neutron.common import exceptions as n_exc
|
||||||
from neutron.common import utils
|
from neutron.common import utils
|
||||||
from neutron.plugins.common import utils as plugin_utils
|
from neutron.plugins.common import utils as plugin_utils
|
||||||
@ -775,3 +776,54 @@ class TestThrottler(base.BaseTestCase):
|
|||||||
|
|
||||||
obj = Klass()
|
obj = Klass()
|
||||||
obj.method()
|
obj.method()
|
||||||
|
|
||||||
|
|
||||||
|
class BaseUnitConversionTest(object):
|
||||||
|
|
||||||
|
def test_bytes_to_bits(self):
|
||||||
|
test_values = [
|
||||||
|
(0, 0), # 0 bytes should be 0 bits
|
||||||
|
(1, 8) # 1 byte should be 8 bits
|
||||||
|
]
|
||||||
|
for input_bytes, expected_bits in test_values:
|
||||||
|
self.assertEqual(
|
||||||
|
expected_bits, utils.bytes_to_bits(input_bytes)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSIUnitConversions(BaseUnitConversionTest, base.BaseTestCase):
|
||||||
|
|
||||||
|
base_unit = common_constants.SI_BASE
|
||||||
|
|
||||||
|
def test_bits_to_kilobits(self):
|
||||||
|
test_values = [
|
||||||
|
(0, 0), # 0 bites should be 0 kilobites
|
||||||
|
(1, 1), # 1 bit should be 1 kilobit
|
||||||
|
(999, 1), # 999 bits should be 1 kilobit
|
||||||
|
(1000, 1), # 1000 bits should be 1 kilobit
|
||||||
|
(1001, 2) # 1001 bits should be 2 kilobits
|
||||||
|
]
|
||||||
|
for input_bits, expected_kilobits in test_values:
|
||||||
|
self.assertEqual(
|
||||||
|
expected_kilobits,
|
||||||
|
utils.bits_to_kilobits(input_bits, self.base_unit)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestIECUnitConversions(BaseUnitConversionTest, base.BaseTestCase):
|
||||||
|
|
||||||
|
base_unit = common_constants.IEC_BASE
|
||||||
|
|
||||||
|
def test_bits_to_kilobits(self):
|
||||||
|
test_values = [
|
||||||
|
(0, 0), # 0 bites should be 0 kilobites
|
||||||
|
(1, 1), # 1 bit should be 1 kilobit
|
||||||
|
(1023, 1), # 1023 bits should be 1 kilobit
|
||||||
|
(1024, 1), # 1024 bits should be 1 kilobit
|
||||||
|
(1025, 2) # 1025 bits should be 2 kilobits
|
||||||
|
]
|
||||||
|
for input_bits, expected_kilobits in test_values:
|
||||||
|
self.assertEqual(
|
||||||
|
expected_kilobits,
|
||||||
|
utils.bits_to_kilobits(input_bits, self.base_unit)
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user