Merge "Clean duplicated QoS bandwidth related methods in ovs_lib module" into stable/xena

This commit is contained in:
Zuul 2022-04-05 12:29:11 +00:00 committed by Gerrit Code Review
commit 2a6da048a5
8 changed files with 230 additions and 250 deletions

View File

@ -771,56 +771,6 @@ class OVSBridge(BaseOVS):
return return
self._set_egress_bw_limit_for_port(port_name, 0, 0, check_error=False) self._set_egress_bw_limit_for_port(port_name, 0, 0, check_error=False)
def find_qos(self, port_name):
qos = self.ovsdb.db_find(
'QoS',
('external_ids', '=', {'id': port_name}),
columns=['_uuid', 'other_config']).execute(check_error=True)
if qos:
return qos[0]
def find_queue(self, port_name, queue_type):
queues = self.ovsdb.db_find(
'Queue',
('external_ids', '=', {'id': port_name,
'queue_type': str(queue_type)}),
columns=['_uuid', 'other_config']).execute(check_error=True)
if queues:
return queues[0]
def _update_bw_limit_queue(self, txn, port_name, queue_uuid, queue_type,
other_config):
if queue_uuid:
txn.add(self.ovsdb.db_set(
'Queue', queue_uuid,
('other_config', other_config)))
else:
external_ids = {'id': port_name,
'queue_type': str(queue_type)}
queue_uuid = txn.add(
self.ovsdb.db_create(
'Queue', external_ids=external_ids,
other_config=other_config))
return queue_uuid
def _update_bw_limit_profile(self, txn, port_name, qos_uuid,
queue_uuid, queue_type, qos_other_config):
queues = {queue_type: queue_uuid}
if qos_uuid:
txn.add(self.ovsdb.db_set(
'QoS', qos_uuid, ('queues', queues)))
txn.add(self.ovsdb.db_set(
'QoS', qos_uuid, ('other_config', qos_other_config)))
else:
external_ids = {'id': port_name}
qos_uuid = txn.add(
self.ovsdb.db_create(
'QoS', external_ids=external_ids,
type='linux-htb',
queues=queues,
other_config=qos_other_config))
return qos_uuid
def _update_bw_limit_profile_dpdk(self, txn, port_name, qos_uuid, def _update_bw_limit_profile_dpdk(self, txn, port_name, qos_uuid,
other_config): other_config):
if qos_uuid: if qos_uuid:
@ -835,120 +785,85 @@ class OVSBridge(BaseOVS):
return qos_uuid return qos_uuid
def _update_ingress_bw_limit_for_port( def _update_ingress_bw_limit_for_port(
self, port_name, max_bw_in_bits, max_burst_in_bits): self, port_name, max_kbps, max_burst_kbps):
qos_other_config = { queue_id = self._update_queue(
'max-rate': str(int(max_bw_in_bits)) port_name, QOS_DEFAULT_QUEUE,
} qos_constants.RULE_TYPE_BANDWIDTH_LIMIT,
queue_other_config = { max_kbps=max_kbps, max_burst_kbps=max_burst_kbps)
'max-rate': str(int(max_bw_in_bits)), qos_id, qos_queues = self._find_qos(
'burst': str(int(max_burst_in_bits)), port_name,
} qos_constants.RULE_TYPE_BANDWIDTH_LIMIT)
qos = self.find_qos(port_name) if qos_queues:
queue = self.find_queue(port_name, QOS_DEFAULT_QUEUE) qos_queues[QOS_DEFAULT_QUEUE] = queue_id
qos_uuid = qos['_uuid'] if qos else None else:
queue_uuid = queue['_uuid'] if queue else None qos_queues = {QOS_DEFAULT_QUEUE: queue_id}
with self.ovsdb.transaction(check_error=True) as txn: qos_id = self._update_qos(
queue_uuid = self._update_bw_limit_queue( port_name,
txn, port_name, queue_uuid, QOS_DEFAULT_QUEUE, qos_constants.RULE_TYPE_BANDWIDTH_LIMIT,
queue_other_config qos_id=qos_id, queues=qos_queues)
) self._set_port_qos(port_name, qos_id=qos_id)
qos_uuid = self._update_bw_limit_profile(
txn, port_name, qos_uuid, queue_uuid, QOS_DEFAULT_QUEUE,
qos_other_config
)
txn.add(self.ovsdb.db_set(
'Port', port_name, ('qos', qos_uuid)))
def _update_ingress_bw_limit_for_dpdk_port( def _update_ingress_bw_limit_for_dpdk_port(
self, port_name, max_bw_in_bits, max_burst_in_bits): self, port_name, max_kbps, max_burst_kbps):
# cir and cbs should be set in bytes instead of bits # cir and cbs should be set in bytes instead of bits
max_bw_in_bits = max_kbps * p_const.SI_BASE
max_burst_in_bits = max_burst_kbps * p_const.SI_BASE
qos_other_config = { qos_other_config = {
'cir': str(max_bw_in_bits // 8), 'cir': str(max_bw_in_bits // 8),
'cbs': str(max_burst_in_bits // 8) 'cbs': str(max_burst_in_bits // 8)
} }
qos = self.find_qos(port_name) qos_id, qos_queues = self._find_qos(port_name)
qos_uuid = qos['_uuid'] if qos else None
with self.ovsdb.transaction(check_error=True) as txn: with self.ovsdb.transaction(check_error=True) as txn:
qos_uuid = self._update_bw_limit_profile_dpdk( qos_uuid = self._update_bw_limit_profile_dpdk(
txn, port_name, qos_uuid, qos_other_config) txn, port_name, qos_id, qos_other_config)
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_port(self, port_name, max_kbps, def update_ingress_bw_limit_for_port(self, port_name, max_kbps,
max_burst_kbps): max_burst_kbps):
max_bw_in_bits = max_kbps * p_const.SI_BASE
max_burst_in_bits = max_burst_kbps * p_const.SI_BASE
port_type = self._get_port_val(port_name, "type") port_type = self._get_port_val(port_name, "type")
if port_type in constants.OVS_DPDK_PORT_TYPES: if port_type in constants.OVS_DPDK_PORT_TYPES:
self._update_ingress_bw_limit_for_dpdk_port( self._update_ingress_bw_limit_for_dpdk_port(
port_name, max_bw_in_bits, max_burst_in_bits) port_name, max_kbps, max_burst_kbps)
else: else:
self._update_ingress_bw_limit_for_port( self._update_ingress_bw_limit_for_port(
port_name, max_bw_in_bits, max_burst_in_bits) port_name, max_kbps, max_burst_kbps)
def get_ingress_bw_limit_for_port(self, port_name): def get_ingress_bw_limit_for_port(self, port_name):
max_kbps = None
qos_max_kbps = None qos_max_kbps = None
queue_max_kbps = None
max_burst_kbit = None max_burst_kbit = None
qos_res = self.find_qos(port_name) queue = self._find_queue(
if qos_res: port_name, _type=qos_constants.RULE_TYPE_BANDWIDTH_LIMIT)
other_config = qos_res['other_config'] if queue:
other_config = queue['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: qos_max_kbps = int(int(max_bw_in_bits) / p_const.SI_BASE)
qos_max_kbps = int(max_bw_in_bits) / p_const.SI_BASE
queue_res = self.find_queue(port_name, QOS_DEFAULT_QUEUE)
if queue_res:
other_config = queue_res['other_config']
max_bw_in_bits = other_config.get('max-rate')
if max_bw_in_bits is not None:
queue_max_kbps = int(max_bw_in_bits) / p_const.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 = ( max_burst_kbit = int(int(max_burst_in_bits) / p_const.SI_BASE)
int(max_burst_in_bits) / p_const.SI_BASE)
if qos_max_kbps == queue_max_kbps: return qos_max_kbps, max_burst_kbit
max_kbps = qos_max_kbps
else:
LOG.warning("qos max-rate %(qos_max_kbps)s is not equal to "
"queue max-rate %(queue_max_kbps)s",
{'qos_max_kbps': qos_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(float(max_bw_in_bytes))),
p_const.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(float(max_burst_in_bytes))),
p_const.SI_BASE)
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):
self.ovsdb.db_clear('Port', port_name, qos_id, qos_queues = self._find_qos(
'qos').execute(check_error=False) port_name,
qos = self.find_qos(port_name) qos_constants.RULE_TYPE_BANDWIDTH_LIMIT)
queue = self.find_queue(port_name, QOS_DEFAULT_QUEUE) if not qos_queues:
with self.ovsdb.transaction(check_error=True) as txn: return
if qos: if QOS_DEFAULT_QUEUE in qos_queues.keys():
txn.add(self.ovsdb.db_destroy('QoS', qos['_uuid'])) queue_uuid = qos_queues.pop(QOS_DEFAULT_QUEUE)
if queue: if qos_queues:
txn.add(self.ovsdb.db_destroy('Queue', queue['_uuid'])) self._update_qos(
port_name,
qos_constants.RULE_TYPE_BANDWIDTH_LIMIT,
qos_id=qos_id, queues=qos_queues)
self.ovsdb.db_clear('Port', port_name, 'qos').execute(
check_error=False)
if not qos_queues:
self._delete_qos(qos_id)
self._delete_queue(
queue_uuid, qos_constants.RULE_TYPE_BANDWIDTH_LIMIT)
def set_controller_field(self, field, value): def set_controller_field(self, field, value):
attr = [(field, value)] attr = [(field, value)]
@ -1017,13 +932,19 @@ class OVSBridge(BaseOVS):
def update_minimum_bandwidth_queue(self, port_id, egress_port_names, def update_minimum_bandwidth_queue(self, port_id, egress_port_names,
queue_num, min_kbps): queue_num, min_kbps):
queue_num = int(queue_num) queue_num = int(queue_num)
queue_id = self._update_queue(port_id, queue_num, min_kbps=min_kbps) queue_id = self._update_queue(
qos_id, qos_queues = self._find_qos() port_id, queue_num, qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH,
min_kbps=min_kbps)
qos_id, qos_queues = self._find_qos(
self._min_bw_qos_id,
qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH)
if qos_queues: if qos_queues:
qos_queues[queue_num] = queue_id qos_queues[queue_num] = queue_id
else: else:
qos_queues = {queue_num: queue_id} qos_queues = {queue_num: queue_id}
qos_id = self._update_qos( qos_id = self._update_qos(
self._min_bw_qos_id,
qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH,
qos_id=qos_id, queues=qos_queues) qos_id=qos_id, queues=qos_queues)
for egress_port_name in egress_port_names: for egress_port_name in egress_port_names:
self._set_port_qos(egress_port_name, qos_id=qos_id) self._set_port_qos(egress_port_name, qos_id=qos_id)
@ -1036,18 +957,29 @@ class OVSBridge(BaseOVS):
return return
queue_num = int(queue['external_ids']['queue-num']) queue_num = int(queue['external_ids']['queue-num'])
self._unset_queue_for_minimum_bandwidth(queue_num) self._unset_queue_for_minimum_bandwidth(queue_num)
qos_id, qos_queues = self._find_qos() qos_id, qos_queues = self._find_qos(
self._min_bw_qos_id,
qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH)
if not qos_queues: if not qos_queues:
return return
if queue_num in qos_queues.keys(): if queue_num in qos_queues.keys():
qos_queues.pop(queue_num) qos_queues.pop(queue_num)
self._update_qos( self._update_qos(
self._min_bw_qos_id,
qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH,
qos_id=qos_id, queues=qos_queues) qos_id=qos_id, queues=qos_queues)
self._delete_queue(queue['_uuid']) self._delete_queue(
queue['_uuid'], qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH)
def clear_minimum_bandwidth_qos(self): def clear_bandwidth_qos(self):
qoses = self._list_qos( qoses = []
qos_type=qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH) qos_types = [
(self._min_bw_qos_id,
qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH),
(None,
qos_constants.RULE_TYPE_BANDWIDTH_LIMIT)]
for rule_type_id, qos_type in qos_types:
qoses += self._list_qos(_id=rule_type_id, qos_type=qos_type)
for qos in qoses: for qos in qoses:
qos_id = qos['_uuid'] qos_id = qos['_uuid']
@ -1059,21 +991,20 @@ class OVSBridge(BaseOVS):
colmuns=['name']).execute(check_error=True) colmuns=['name']).execute(check_error=True)
for port in ports: for port in ports:
self._set_port_qos(port['name']) self._set_port_qos(port['name'])
self.ovsdb.db_destroy('QoS', qos_id).execute(check_error=True) self._delete_qos(qos_id)
for queue_uuid in queues.values(): for queue_uuid in queues.values():
self._delete_queue(queue_uuid) self._delete_queue(queue_uuid)
def _update_queue(self, port_id, queue_num, max_kbps=None, def _update_queue(self, port_id, queue_num, queue_type, max_kbps=None,
max_burst_kbps=None, min_kbps=None): max_burst_kbps=None, min_kbps=None):
other_config = {} other_config = {}
if max_kbps: if max_kbps:
other_config['max-rate'] = str(max_kbps * 1000) other_config['max-rate'] = str(int(max_kbps) * p_const.SI_BASE)
if max_burst_kbps: other_config['burst'] = str(int(max_burst_kbps) * p_const.SI_BASE)
other_config['burst'] = str(max_burst_kbps * 1000)
if min_kbps: if min_kbps:
other_config['min-rate'] = str(min_kbps * 1000) other_config['min-rate'] = str(min_kbps * p_const.SI_BASE)
queue = self._find_queue(port_id) queue = self._find_queue(port_id, _type=queue_type)
if queue and queue['_uuid']: if queue and queue['_uuid']:
if queue['other_config'] != other_config: if queue['other_config'] != other_config:
self.set_db_attribute('Queue', queue['_uuid'], 'other_config', self.set_db_attribute('Queue', queue['_uuid'], 'other_config',
@ -1082,12 +1013,12 @@ class OVSBridge(BaseOVS):
# NOTE(ralonsoh): "external_ids" is a map of string-string pairs # NOTE(ralonsoh): "external_ids" is a map of string-string pairs
external_ids = { external_ids = {
'port': str(port_id), 'port': str(port_id),
'type': str(qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH), 'type': str(queue_type),
'queue-num': str(queue_num)} 'queue-num': str(queue_num)}
self.ovsdb.db_create( self.ovsdb.db_create(
'Queue', other_config=other_config, 'Queue', other_config=other_config,
external_ids=external_ids).execute(check_error=True) external_ids=external_ids).execute(check_error=True)
queue = self._find_queue(port_id) queue = self._find_queue(port_id, _type=queue_type)
return queue['_uuid'] return queue['_uuid']
def _find_queue(self, port_id, _type=None): def _find_queue(self, port_id, _type=None):
@ -1113,16 +1044,23 @@ class OVSBridge(BaseOVS):
if queue['external_ids'].get('type') == str(_type)] if queue['external_ids'].get('type') == str(_type)]
return queues return queues
def _delete_queue(self, queue_id): def _delete_qos(self, qos_id):
try: try:
self.ovsdb.db_destroy('Queue', queue_id).execute(check_error=True) self.ovsdb.db_destroy('QoS', qos_id).execute(check_error=True)
except idlutils.RowNotFound:
LOG.info('OVS QoS %s was already deleted', str(qos_id))
def _delete_queue(self, queue_id, qos_type=None):
try:
self.ovsdb.db_destroy('Queue', queue_id).execute(
check_error=True)
except idlutils.RowNotFound: except idlutils.RowNotFound:
LOG.info('OVS Queue %s was already deleted', queue_id) LOG.info('OVS Queue %s was already deleted', queue_id)
except RuntimeError as exc: except RuntimeError as exc:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
if 'referential integrity violation' not in str(exc): if 'referential integrity violation' not in str(exc):
return return
qos_regs = self._list_qos() qos_regs = self._list_qos(qos_type=qos_type)
qos_uuids = [] qos_uuids = []
for qos_reg in qos_regs: for qos_reg in qos_regs:
queue_nums = [num for num, q in qos_reg['queues'].items() queue_nums = [num for num, q in qos_reg['queues'].items()
@ -1134,17 +1072,17 @@ class OVSBridge(BaseOVS):
{'queue': str(queue_id), {'queue': str(queue_id),
'qoses': ', '.join(sorted(qos_uuids))}) 'qoses': ', '.join(sorted(qos_uuids))})
def _update_qos(self, qos_id=None, queues=None): def _update_qos(self, rule_type_id, rule_type, qos_id=None, queues=None):
queues = queues or {} queues = queues or {}
if not qos_id: if not qos_id:
external_ids = {'id': self._min_bw_qos_id, external_ids = {'id': rule_type_id,
'_type': qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH} '_type': rule_type}
self.ovsdb.db_create( self.ovsdb.db_create(
'QoS', 'QoS',
type='linux-htb', type='linux-htb',
queues=queues, queues=queues,
external_ids=external_ids).execute(check_error=True) external_ids=external_ids).execute(check_error=True)
qos_id, _ = self._find_qos() qos_id, _ = self._find_qos(rule_type_id, rule_type)
else: else:
self.clear_db_attribute('QoS', qos_id, 'queues') self.clear_db_attribute('QoS', qos_id, 'queues')
if queues: if queues:
@ -1167,8 +1105,8 @@ class OVSBridge(BaseOVS):
return self.ovsdb.db_find( return self.ovsdb.db_find(
'QoS', colmuns=['_uuid', 'queues']).execute(check_error=True) 'QoS', colmuns=['_uuid', 'queues']).execute(check_error=True)
def _find_qos(self): def _find_qos(self, rule_type_id, qos_type=None):
qos_regs = self._list_qos(_id=self._min_bw_qos_id) qos_regs = self._list_qos(_id=rule_type_id, qos_type=qos_type)
if qos_regs: if qos_regs:
queues = {num: queue.uuid queues = {num: queue.uuid
for num, queue in qos_regs[0]['queues'].items()} for num, queue in qos_regs[0]['queues'].items()}

View File

@ -40,7 +40,7 @@ class QosOVSAgentDriver(qos.QosLinuxAgentDriver):
def consume_api(self, agent_api): def consume_api(self, agent_api):
self.agent_api = agent_api self.agent_api = agent_api
def _minimum_bandwidth_initialize(self): def _qos_bandwidth_initialize(self):
"""Clear QoS setting at agent restart. """Clear QoS setting at agent restart.
This is for clearing stale settings (such as ports and QoS tables This is for clearing stale settings (such as ports and QoS tables
@ -49,12 +49,12 @@ class QosOVSAgentDriver(qos.QosLinuxAgentDriver):
rebuild. There is no performance impact however the QoS feature will rebuild. There is no performance impact however the QoS feature will
be down until the QoS rules are rebuilt. be down until the QoS rules are rebuilt.
""" """
self.br_int.clear_minimum_bandwidth_qos() self.br_int.clear_bandwidth_qos()
def initialize(self): def initialize(self):
self.br_int = self.agent_api.request_int_br() self.br_int = self.agent_api.request_int_br()
self.cookie = self.br_int.default_cookie self.cookie = self.br_int.default_cookie
self._minimum_bandwidth_initialize() self._qos_bandwidth_initialize()
def create_bandwidth_limit(self, port, rule): def create_bandwidth_limit(self, port, rule):
self.update_bandwidth_limit(port, rule) self.update_bandwidth_limit(port, rule)

View File

@ -41,7 +41,7 @@ def monkeypatch_init_handler():
def monkeypatch_qos(): def monkeypatch_qos():
mock.patch.object(ovs_lib.OVSBridge, 'clear_minimum_bandwidth_qos').start() mock.patch.object(ovs_lib.OVSBridge, 'clear_bandwidth_qos').start()
if "qos" in cfg.CONF.service_plugins: if "qos" in cfg.CONF.service_plugins:
mock.patch.object(qos_extension.QosAgentExtension, mock.patch.object(qos_extension.QosAgentExtension,
'_process_reset_port').start() '_process_reset_port').start()

View File

@ -19,7 +19,6 @@ from neutron_lib.services.qos import constants as qos_consts
from neutronclient.common import exceptions from neutronclient.common import exceptions
from oslo_utils import uuidutils from oslo_utils import uuidutils
from neutron.agent.common import ovs_lib
from neutron.agent.linux import tc_lib from neutron.agent.linux import tc_lib
from neutron.common import utils from neutron.common import utils
from neutron.tests.common.agents import l2_extensions from neutron.tests.common.agents import l2_extensions
@ -364,7 +363,8 @@ class TestBwLimitQoSOvs(_TestBwLimitQoS, base.BaseFullStackTestCase):
elif direction == constants.INGRESS_DIRECTION: elif direction == constants.INGRESS_DIRECTION:
utils.wait_until_true( utils.wait_until_true(
lambda: vm.bridge.get_ingress_bw_limit_for_port( lambda: vm.bridge.get_ingress_bw_limit_for_port(
vm.port.name) == (limit, burst)) vm.port.name) == (limit, burst),
timeout=10)
def test_bw_limit_qos_port_removed(self): def test_bw_limit_qos_port_removed(self):
"""Test if rate limit config is properly removed when whole port is """Test if rate limit config is properly removed when whole port is
@ -382,9 +382,11 @@ class TestBwLimitQoSOvs(_TestBwLimitQoS, base.BaseFullStackTestCase):
# Delete port with qos policy attached # Delete port with qos policy attached
vm.destroy(delete_port=True) vm.destroy(delete_port=True)
self._wait_for_bw_rule_removed(vm, self.direction) self._wait_for_bw_rule_removed(vm, self.direction)
self.assertIsNone(vm.bridge.find_qos(vm.port.name)) qos_id, qos_queues = vm.bridge._find_qos(
self.assertIsNone(vm.bridge.find_queue(vm.port.name, vm.port.name,
ovs_lib.QOS_DEFAULT_QUEUE)) qos_consts.RULE_TYPE_BANDWIDTH_LIMIT)
self.assertIsNone(qos_id)
self.assertIsNone(qos_queues)
class TestBwLimitQoSLinuxbridge(_TestBwLimitQoS, base.BaseFullStackTestCase): class TestBwLimitQoSLinuxbridge(_TestBwLimitQoS, base.BaseFullStackTestCase):

View File

@ -72,9 +72,9 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
for device in self.elements_to_clean['devices']: for device in self.elements_to_clean['devices']:
ip_lib.IPDevice(device).link.delete() ip_lib.IPDevice(device).link.delete()
for qos in self.elements_to_clean['qoses']: for qos in self.elements_to_clean['qoses']:
self.ovs.ovsdb.db_destroy('QoS', qos).execute() self.ovs.ovsdb.db_destroy('QoS', qos).execute(log_errors=False)
for queue in self.elements_to_clean['queues']: for queue in self.elements_to_clean['queues']:
self.ovs.ovsdb.db_destroy('Queue', queue).execute() self.ovs.ovsdb.db_destroy('Queue', queue).execute(log_errors=False)
def _list_queues(self, queue_id=None): def _list_queues(self, queue_id=None):
queues = self.ovs.ovsdb.db_list( queues = self.ovs.ovsdb.db_list(
@ -88,7 +88,9 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
return None return None
return queues return queues
def _create_queue(self, max_kbps=int(MAX_RATE_DEFAULT / 1000), def _create_queue(self,
queue_type=qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH,
max_kbps=int(MAX_RATE_DEFAULT / 1000),
max_burst_kbps=int(BURST_DEFAULT / 1000), max_burst_kbps=int(BURST_DEFAULT / 1000),
min_kbps=int(MIN_RATE_DEFAULT / 1000), min_kbps=int(MIN_RATE_DEFAULT / 1000),
neutron_port_id=None, queue_num=None): neutron_port_id=None, queue_num=None):
@ -96,6 +98,7 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
if not neutron_port_id else neutron_port_id) if not neutron_port_id else neutron_port_id)
queue_num = QUEUE_NUM_DEFAULT if not queue_num else queue_num queue_num = QUEUE_NUM_DEFAULT if not queue_num else queue_num
queue_id = self.ovs._update_queue(neutron_port_id, queue_num, queue_id = self.ovs._update_queue(neutron_port_id, queue_num,
queue_type,
max_kbps=max_kbps, max_kbps=max_kbps,
max_burst_kbps=max_burst_kbps, max_burst_kbps=max_burst_kbps,
min_kbps=min_kbps) min_kbps=min_kbps)
@ -103,15 +106,19 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
self.elements_to_clean['queues'].append(queue_id) self.elements_to_clean['queues'].append(queue_id)
return queue_id, neutron_port_id return queue_id, neutron_port_id
def _create_qos(self, qos_id=None, queues=None): def _create_qos(self, qos_id=None, queues=None,
qos_id = self.ovs._update_qos(qos_id=qos_id, queues=queues) rule_type_id=None,
rule_type=qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH):
qos_id = self.ovs._update_qos(
rule_type_id, rule_type, qos_id=qos_id, queues=queues)
self.elements_to_clean['qoses'].append(qos_id) self.elements_to_clean['qoses'].append(qos_id)
return qos_id return qos_id
def _list_qos(self, qos_id=None): def _list_qos(self, qos_id=None):
qoses = self.ovs.ovsdb.db_list( qoses = self.ovs.ovsdb.db_list(
'QoS', 'QoS',
columns=('_uuid', 'queues', 'external_ids', 'type')).execute() columns=('_uuid', 'queues', 'other_config', 'external_ids', 'type')
).execute()
if qos_id: if qos_id:
for qos in (qos for qos in qoses if qos['_uuid'] == qos_id): for qos in (qos for qos in qoses if qos['_uuid'] == qos_id):
return qos return qos
@ -163,7 +170,9 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
def _check_no_minbw_qos(self): def _check_no_minbw_qos(self):
"""Asserts that there are no min BW qos/queues for this OVS instance""" """Asserts that there are no min BW qos/queues for this OVS instance"""
qos_id, qos_queues = self.ovs._find_qos() qos_id, qos_queues = self.ovs._find_qos(
self.ovs._min_bw_qos_id,
qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH)
if not qos_id and not qos_queues: if not qos_id and not qos_queues:
return return
@ -259,9 +268,13 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
def test__delete_queue_still_used_in_a_qos(self): def test__delete_queue_still_used_in_a_qos(self):
queue_id, port_id = self._create_queue() queue_id, port_id = self._create_queue()
queues = {1: queue_id} queues = {1: queue_id}
qos_id_1 = self._create_qos(queues=queues) qos_id_1 = self._create_qos(
queues=queues,
rule_type_id=self.ovs._min_bw_qos_id)
self.ovs._min_bw_qos_id = uuidutils.generate_uuid() self.ovs._min_bw_qos_id = uuidutils.generate_uuid()
qos_id_2 = self._create_qos(queues=queues) qos_id_2 = self._create_qos(
queues=queues,
rule_type_id=self.ovs._min_bw_qos_id)
with mock.patch.object(ovs_lib.LOG, 'error') as mock_error: with mock.patch.object(ovs_lib.LOG, 'error') as mock_error:
self.assertRaises(RuntimeError, self.ovs._delete_queue, self.assertRaises(RuntimeError, self.ovs._delete_queue,
queue_id) queue_id)
@ -276,7 +289,9 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
queue_id, port_id = self._create_queue() queue_id, port_id = self._create_queue()
queues = {1: queue_id} queues = {1: queue_id}
qos_id = self._create_qos(queues=queues) qos_id = self._create_qos(
queues=queues,
rule_type_id=self.ovs._min_bw_qos_id)
external_ids = {'id': str(self.ovs._min_bw_qos_id), external_ids = {'id': str(self.ovs._min_bw_qos_id),
'_type': qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH} '_type': qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH}
expected = {'_uuid': qos_id, expected = {'_uuid': qos_id,
@ -291,7 +306,9 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
queue_id_1, _ = self._create_queue() queue_id_1, _ = self._create_queue()
queues = {1: queue_id_1} queues = {1: queue_id_1}
qos_id = self._create_qos(queues=queues) qos_id = self._create_qos(
queues=queues,
rule_type_id=self.ovs._min_bw_qos_id)
external_ids = {'id': str(self.ovs._min_bw_qos_id), external_ids = {'id': str(self.ovs._min_bw_qos_id),
'_type': qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH} '_type': qos_constants.RULE_TYPE_MINIMUM_BANDWIDTH}
expected = {'_uuid': qos_id, expected = {'_uuid': qos_id,
@ -305,7 +322,10 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
queue_id_2, _ = self._create_queue() queue_id_2, _ = self._create_queue()
queues[2] = queue_id_2 queues[2] = queue_id_2
self._create_qos(qos_id=qos_id, queues=queues) self._create_qos(
qos_id=qos_id,
queues=queues,
rule_type_id=self.ovs._min_bw_qos_id)
self._check_value(expected, self._list_qos, qos_id, self._check_value(expected, self._list_qos, qos_id,
keys_to_check=['_uuid', 'type', 'external_ids']) keys_to_check=['_uuid', 'type', 'external_ids'])
qos = self._list_qos(qos_id) qos = self._list_qos(qos_id)
@ -316,8 +336,11 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
def test__find_qos(self): def test__find_qos(self):
queue_id, _ = self._create_queue() queue_id, _ = self._create_queue()
queues = {1: queue_id} queues = {1: queue_id}
qos_id = self._create_qos(queues=queues) qos_id = self._create_qos(
self._check_value((qos_id, queues), self.ovs._find_qos) queues=queues,
rule_type_id=self.ovs._min_bw_qos_id)
self._check_value((qos_id, queues), self.ovs._find_qos,
self.ovs._min_bw_qos_id)
def test__set_port_qos(self): def test__set_port_qos(self):
port_name = ('port-' + uuidutils.generate_uuid())[:8] port_name = ('port-' + uuidutils.generate_uuid())[:8]
@ -325,7 +348,8 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
self._create_port(port_name) self._create_port(port_name)
self._check_value([], self._find_port_qos, port_name) self._check_value([], self._find_port_qos, port_name)
qos_id = self._create_qos() qos_id = self._create_qos(
rule_type_id=self.ovs._min_bw_qos_id)
self.ovs._set_port_qos(port_name, qos_id=qos_id) self.ovs._set_port_qos(port_name, qos_id=qos_id)
self._check_value(qos_id, self._find_port_qos, port_name) self._check_value(qos_id, self._find_port_qos, port_name)
@ -345,6 +369,75 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
bridge_ports.sort() bridge_ports.sort()
self.assertEqual(device_names, bridge_ports) self.assertEqual(device_names, bridge_ports)
def test_egress_bw_limit(self):
port_name = ('port-' + uuidutils.generate_uuid())[:8]
self._create_bridge()
self._create_port(port_name)
self.ovs.create_egress_bw_limit_for_port(port_name, 700, 70)
max_rate, burst = self.ovs.get_egress_bw_limit_for_port(port_name)
self.assertEqual(700, max_rate)
self.assertEqual(70, burst)
self.ovs.delete_egress_bw_limit_for_port(port_name)
max_rate, burst = self.ovs.get_egress_bw_limit_for_port(port_name)
self.assertIsNone(max_rate)
self.assertIsNone(burst)
def test_ingress_bw_limit(self):
port_name = ('port-' + uuidutils.generate_uuid())[:8]
self._create_bridge()
self._create_port(port_name)
self.ovs.update_ingress_bw_limit_for_port(port_name, 700, 70)
qos_id = self._find_port_qos(port_name)
qos = self._list_qos(qos_id)
queue_id = qos['queues'][0].uuid
external_ids = {'port': str(port_name),
'type': qos_constants.RULE_TYPE_BANDWIDTH_LIMIT,
'queue-num': '0'}
other_config = {'burst': '70000',
'max-rate': '700000'}
expected = {'_uuid': queue_id,
'external_ids': external_ids,
'other_config': other_config}
self._check_value(expected, self._list_queues, queue_id)
self.elements_to_clean['qoses'].append(qos_id)
self.elements_to_clean['queues'].append(queue_id)
self.ovs.update_ingress_bw_limit_for_port(port_name, 750, 100)
expected['other_config'] = {'burst': '100000',
'max-rate': '750000'}
self.ovs.delete_ingress_bw_limit_for_port(port_name)
self.assertIsNone(self._list_qos(qos_id))
def test_ingress_bw_limit_dpdk_port(self):
port_name = ('port-' + uuidutils.generate_uuid())[:8]
self._create_bridge()
self._create_port(port_name)
self.ovs.ovsdb.db_set(
'Interface', port_name,
('type', ovs_constants.OVS_DPDK_VHOST_USER)).execute()
self.ovs.update_ingress_bw_limit_for_port(port_name, 700, 70)
qos_id = self._find_port_qos(port_name)
external_ids = {'id': str(port_name)}
other_config = {'cir': str(700 * p_const.SI_BASE // 8),
'cbs': str(70 * p_const.SI_BASE // 8)}
expected = {'_uuid': qos_id,
'external_ids': external_ids,
'other_config': other_config,
'queues': {},
'type': 'egress-policer'}
self._check_value(expected, self._list_qos, qos_id)
self.ovs.update_ingress_bw_limit_for_port(port_name, 750, 100)
expected['other_config'] = {'cir': str(750 * p_const.SI_BASE // 8),
'cbs': str(100 * p_const.SI_BASE // 8)}
self._check_value(expected, self._list_qos, qos_id)
self.ovs.delete_ingress_bw_limit_for_port(port_name)
qos = self._list_qos(qos_id)
self.assertEqual(0, len(qos['queues']))
def test__set_queue_for_minimum_bandwidth(self): def test__set_queue_for_minimum_bandwidth(self):
self._create_bridge() self._create_bridge()
self.ovs._set_queue_for_minimum_bandwidth(1234) self.ovs._set_queue_for_minimum_bandwidth(1234)
@ -368,8 +461,9 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
queue_num = 1 queue_num = 1
queue_id, port_id = self._create_queue(neutron_port_id=self.port_id) queue_id, port_id = self._create_queue(neutron_port_id=self.port_id)
queues = {queue_num: queue_id} queues = {queue_num: queue_id}
qos_id = self._create_qos(queues=queues) qos_id = self._create_qos(
queues=queues,
rule_type_id=self.ovs._min_bw_qos_id)
self.ovs.update_minimum_bandwidth_queue(self.port_id, [port_name], self.ovs.update_minimum_bandwidth_queue(self.port_id, [port_name],
queue_num, 1800) queue_num, 1800)
self._check_value(qos_id, self._find_port_qos, port_name) self._check_value(qos_id, self._find_port_qos, port_name)
@ -410,7 +504,9 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
queue_id_1, neutron_port_id_1 = self._create_queue(queue_num=1) queue_id_1, neutron_port_id_1 = self._create_queue(queue_num=1)
queue_id_2, neutron_port_id_2 = self._create_queue(queue_num=2) queue_id_2, neutron_port_id_2 = self._create_queue(queue_num=2)
queues = {1: queue_id_1, 2: queue_id_2} queues = {1: queue_id_1, 2: queue_id_2}
qos_id = self._create_qos(queues=queues) qos_id = self._create_qos(
queues=queues,
rule_type_id=self.ovs._min_bw_qos_id)
self._check_value({'_uuid': qos_id}, self._list_qos, qos_id, self._check_value({'_uuid': qos_id}, self._list_qos, qos_id,
keys_to_check=['_uuid']) keys_to_check=['_uuid'])
qos = self._list_qos(qos_id) qos = self._list_qos(qos_id)
@ -443,19 +539,21 @@ class BaseOVSTestCase(base.BaseSudoTestCase):
queue = self._list_queues(queue_id) queue = self._list_queues(queue_id)
self.assertEqual(queue_id, queue['_uuid']) self.assertEqual(queue_id, queue['_uuid'])
def test_clear_minimum_bandwidth_qos(self): def test_clear_bandwidth_qos(self):
queue_id_1, _ = self._create_queue(queue_num=1) queue_id_1, _ = self._create_queue(queue_num=1)
queue_id_2, _ = self._create_queue(queue_num=2) queue_id_2, _ = self._create_queue(queue_num=2)
queue_id_3, port_id_3 = self._create_queue() queue_id_3, port_id_3 = self._create_queue()
queues = {1: queue_id_1, 2: queue_id_2} queues = {1: queue_id_1, 2: queue_id_2}
qos_id = self._create_qos(queues=queues) qos_id = self._create_qos(
queues=queues,
rule_type_id=self.ovs._min_bw_qos_id)
# NOTE(ralonsoh): we need to clean only the QoS rule created in this # NOTE(ralonsoh): we need to clean only the QoS rule created in this
# test in order to avoid any interference with other tests. # test in order to avoid any interference with other tests.
qoses = self.ovs._list_qos(_id=self.ovs._min_bw_qos_id) qoses = self.ovs._list_qos(_id=self.ovs._min_bw_qos_id)
with mock.patch.object(self.ovs, '_list_qos') as mock_list_qos: with mock.patch.object(self.ovs, '_list_qos') as mock_list_qos:
mock_list_qos.return_value = qoses mock_list_qos.side_effect = [qoses, []]
self.ovs.clear_minimum_bandwidth_qos() self.ovs.clear_bandwidth_qos()
self._check_value(None, self._list_qos, qos_id=qos_id) self._check_value(None, self._list_qos, qos_id=qos_id)
self._check_value(None, self._list_queues, queue_id=queue_id_1) self._check_value(None, self._list_queues, queue_id=queue_id_1)
self._check_value(None, self._list_queues, queue_id=queue_id_2) self._check_value(None, self._list_queues, queue_id=queue_id_2)

View File

@ -176,7 +176,7 @@ class OVSAgentTestFramework(base.BaseOVSLinuxTestCase, OVSOFControllerHelper):
self._bridge_classes()['br_phys'](self.br_phys).create() self._bridge_classes()['br_phys'](self.br_phys).create()
ext_mgr = ext_manager.L2AgentExtensionsManager(self.config) ext_mgr = ext_manager.L2AgentExtensionsManager(self.config)
with mock.patch.object(ovs_qos_driver.QosOVSAgentDriver, with mock.patch.object(ovs_qos_driver.QosOVSAgentDriver,
'_minimum_bandwidth_initialize'): '_qos_bandwidth_initialize'):
agent = ovs_agent.OVSNeutronAgent(self._bridge_classes(), agent = ovs_agent.OVSNeutronAgent(self._bridge_classes(),
ext_mgr, self.config) ext_mgr, self.config)
self.addCleanup(self.ovs.delete_bridge, self.br_int) self.addCleanup(self.ovs.delete_bridge, self.br_int)

View File

@ -421,55 +421,6 @@ class OVSBridgeTestCase(OVSBridgeTestBase):
controller, controller,
'connection_mode')) 'connection_mode'))
def test_egress_bw_limit(self):
port_name, _ = self.create_ovs_port()
self.br.create_egress_bw_limit_for_port(port_name, 700, 70)
max_rate, burst = self.br.get_egress_bw_limit_for_port(port_name)
self.assertEqual(700, max_rate)
self.assertEqual(70, burst)
self.br.delete_egress_bw_limit_for_port(port_name)
max_rate, burst = self.br.get_egress_bw_limit_for_port(port_name)
self.assertIsNone(max_rate)
self.assertIsNone(burst)
def test_ingress_bw_limit(self):
port_name, _ = self.create_ovs_port()
self.br.update_ingress_bw_limit_for_port(port_name, 700, 70)
max_rate, burst = self.br.get_ingress_bw_limit_for_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_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_port(port_name)
self.assertIsNone(max_rate)
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",

View File

@ -41,7 +41,7 @@ class QosOVSAgentDriverTestCase(ovs_test_base.OVSAgentConfigTestBase):
self.context = context.get_admin_context() self.context = context.get_admin_context()
self.qos_driver = qos_driver.QosOVSAgentDriver() self.qos_driver = qos_driver.QosOVSAgentDriver()
self.mock_clear_minimum_bandwidth_qos = mock.patch.object( self.mock_clear_minimum_bandwidth_qos = mock.patch.object(
self.qos_driver, '_minimum_bandwidth_initialize').start() self.qos_driver, '_qos_bandwidth_initialize').start()
os_ken_app = mock.Mock() os_ken_app = mock.Mock()
self.agent_api = ovs_ext_api.OVSAgentExtensionAPI( self.agent_api = ovs_ext_api.OVSAgentExtensionAPI(
ovs_bridge.OVSAgentBridge( ovs_bridge.OVSAgentBridge(
@ -59,7 +59,6 @@ class QosOVSAgentDriverTestCase(ovs_test_base.OVSAgentConfigTestBase):
self.qos_driver.br_int.get_egress_bw_limit_for_port = mock.Mock( self.qos_driver.br_int.get_egress_bw_limit_for_port = mock.Mock(
return_value=(1000, 10)) return_value=(1000, 10))
self.get_egress = self.qos_driver.br_int.get_egress_bw_limit_for_port self.get_egress = self.qos_driver.br_int.get_egress_bw_limit_for_port
self.get_ingress = self.qos_driver.br_int.get_ingress_bw_limit_for_port
self.qos_driver.br_int.del_egress_bw_limit_for_port = mock.Mock() self.qos_driver.br_int.del_egress_bw_limit_for_port = mock.Mock()
self.delete_egress = ( self.delete_egress = (
self.qos_driver.br_int.delete_egress_bw_limit_for_port) self.qos_driver.br_int.delete_egress_bw_limit_for_port)
@ -122,8 +121,6 @@ class QosOVSAgentDriverTestCase(ovs_test_base.OVSAgentConfigTestBase):
def test_create_new_rules(self): def test_create_new_rules(self):
self.qos_driver.br_int.get_egress_bw_limit_for_port = mock.Mock( self.qos_driver.br_int.get_egress_bw_limit_for_port = mock.Mock(
return_value=(None, None)) return_value=(None, None))
self.qos_driver.br_int.get_ingress_bw_limit_for_port = mock.Mock(
return_value=(None, None))
self.qos_driver.create(self.port, self.qos_policy) self.qos_driver.create(self.port, self.qos_policy)
self.assertEqual(0, self.delete_egress.call_count) self.assertEqual(0, self.delete_egress.call_count)
self.assertEqual(0, self.delete_ingress.call_count) self.assertEqual(0, self.delete_ingress.call_count)
@ -153,18 +150,12 @@ class QosOVSAgentDriverTestCase(ovs_test_base.OVSAgentConfigTestBase):
self.update_ingress.assert_not_called() self.update_ingress.assert_not_called()
def _test_delete_rules(self, qos_policy): def _test_delete_rules(self, qos_policy):
self.qos_driver.br_int.get_ingress_bw_limit_for_port = mock.Mock(
return_value=(self.rules[1].max_kbps,
self.rules[1].max_burst_kbps))
self.qos_driver.create(self.port, qos_policy) self.qos_driver.create(self.port, qos_policy)
self.qos_driver.delete(self.port, qos_policy) self.qos_driver.delete(self.port, qos_policy)
self.delete_egress.assert_called_once_with(self.port_name) self.delete_egress.assert_called_once_with(self.port_name)
self.delete_ingress.assert_called_once_with(self.port_name) self.delete_ingress.assert_called_once_with(self.port_name)
def _test_delete_rules_no_policy(self): def _test_delete_rules_no_policy(self):
self.qos_driver.br_int.get_ingress_bw_limit_for_port = mock.Mock(
return_value=(self.rules[1].max_kbps,
self.rules[1].max_burst_kbps))
self.qos_driver.delete(self.port) self.qos_driver.delete(self.port)
self.delete_egress.assert_called_once_with(self.port_name) self.delete_egress.assert_called_once_with(self.port_name)
self.delete_ingress.assert_called_once_with(self.port_name) self.delete_ingress.assert_called_once_with(self.port_name)