Add Create/Destroy API to OVS QoS BW Limiting
Add infrastructure needed for the implementations (CLI and native) and add API to ovs_lib Add functional tests for ovs_lib blueprint ml2-ovs-qos-with-bwlimiting Change-Id: Ided0740548987ca91f1549f251c7906e6449f91d
This commit is contained in:
parent
b17f865f85
commit
be1d242fa3
|
@ -455,6 +455,81 @@ class OVSBridge(BaseOVS):
|
|||
txn.add(self.ovsdb.db_set('Controller',
|
||||
controller_uuid, *attr))
|
||||
|
||||
def _create_qos_bw_limit_queue(self, port_name, max_bw_in_bits,
|
||||
max_burst_in_bits):
|
||||
external_ids = {'id': port_name}
|
||||
queue_other_config = {'min-rate': max_bw_in_bits,
|
||||
'max-rate': max_bw_in_bits,
|
||||
'burst': max_burst_in_bits}
|
||||
|
||||
self.ovsdb.db_create(
|
||||
'Queue', external_ids=external_ids,
|
||||
other_config=queue_other_config).execute(check_error=True)
|
||||
|
||||
def _create_qos_bw_limit_profile(self, port_name, max_bw_in_bits):
|
||||
external_ids = {'id': port_name}
|
||||
queue = self.ovsdb.db_find(
|
||||
'Queue',
|
||||
('external_ids', '=', {'id': port_name}),
|
||||
columns=['_uuid']).execute(
|
||||
check_error=True)
|
||||
queues = {}
|
||||
queues[0] = queue[0]['_uuid']
|
||||
qos_other_config = {'max-rate': max_bw_in_bits}
|
||||
self.ovsdb.db_create('QoS', external_ids=external_ids,
|
||||
other_config=qos_other_config,
|
||||
type='linux-htb',
|
||||
queues=queues).execute(check_error=True)
|
||||
|
||||
def create_qos_bw_limit_for_port(self, port_name, max_kbps,
|
||||
max_burst_kbps):
|
||||
# TODO(QoS) implement this with transactions,
|
||||
# or roll back on failure
|
||||
max_bw_in_bits = str(max_kbps * 1000)
|
||||
max_burst_in_bits = str(max_burst_kbps * 1000)
|
||||
|
||||
self._create_qos_bw_limit_queue(port_name, max_bw_in_bits,
|
||||
max_burst_in_bits)
|
||||
self._create_qos_bw_limit_profile(port_name, max_bw_in_bits)
|
||||
|
||||
qos = self.ovsdb.db_find('QoS',
|
||||
('external_ids', '=', {'id': port_name}),
|
||||
columns=['_uuid']).execute(check_error=True)
|
||||
qos_profile = qos[0]['_uuid']
|
||||
self.set_db_attribute('Port', port_name, 'qos', qos_profile,
|
||||
check_error=True)
|
||||
|
||||
def get_qos_bw_limit_for_port(self, port_name):
|
||||
|
||||
res = self.ovsdb.db_find(
|
||||
'Queue',
|
||||
('external_ids', '=', {'id': port_name}),
|
||||
columns=['other_config']).execute(check_error=True)
|
||||
|
||||
if res is None or len(res) == 0:
|
||||
return None, None
|
||||
|
||||
other_config = res[0]['other_config']
|
||||
max_kbps = int(other_config['max-rate']) / 1000
|
||||
max_burst_kbps = int(other_config['burst']) / 1000
|
||||
return max_kbps, max_burst_kbps
|
||||
|
||||
def del_qos_bw_limit_for_port(self, port_name):
|
||||
qos = self.ovsdb.db_find('QoS',
|
||||
('external_ids', '=', {'id': port_name}),
|
||||
columns=['_uuid']).execute(check_error=True)
|
||||
qos_row = qos[0]['_uuid']
|
||||
|
||||
queue = self.ovsdb.db_find('Queue',
|
||||
('external_ids', '=', {'id': port_name}),
|
||||
columns=['_uuid']).execute(check_error=True)
|
||||
queue_row = queue[0]['_uuid']
|
||||
|
||||
with self.ovsdb.transaction(check_error=True) as txn:
|
||||
txn.add(self.ovsdb.db_set('Port', port_name, ('qos', [])))
|
||||
txn.add(self.ovsdb.db_destroy('QoS', qos_row))
|
||||
txn.add(self.ovsdb.db_destroy('Queue', queue_row))
|
||||
|
||||
def __enter__(self):
|
||||
self.create()
|
||||
return self
|
||||
|
|
|
@ -161,6 +161,29 @@ class API(object):
|
|||
:returns: :class:`Command` with field value result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def db_create(self, table, **col_values):
|
||||
"""Create a command to create new record
|
||||
|
||||
:param table: The OVS table containing the record to be created
|
||||
:type table: string
|
||||
:param col_values: The columns and their associated values
|
||||
to be set after create
|
||||
:type col_values: Dictionary of columns id's and values
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def db_destroy(self, table, record):
|
||||
"""Create a command to destroy a record
|
||||
|
||||
:param table: The OVS table containing the record to be destroyed
|
||||
:type table: string
|
||||
:param record: The record id (name/uuid) to be destroyed
|
||||
:type record: uuid/string
|
||||
:returns: :class:`Command` with no result
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def db_set(self, table, record, *col_values):
|
||||
"""Create a command to set fields in a record
|
||||
|
|
|
@ -169,6 +169,12 @@ class OvsdbIdl(api.API):
|
|||
def br_set_external_id(self, name, field, value):
|
||||
return cmd.BrSetExternalIdCommand(self, name, field, value)
|
||||
|
||||
def db_create(self, table, **col_values):
|
||||
return cmd.DbCreateCommand(self, table, **col_values)
|
||||
|
||||
def db_destroy(self, table, record):
|
||||
return cmd.DbDestroyCommand(self, table, record)
|
||||
|
||||
def db_set(self, table, record, *col_values):
|
||||
return cmd.DbSetCommand(self, table, record, *col_values)
|
||||
|
||||
|
|
|
@ -184,6 +184,15 @@ class OvsdbVsctl(ovsdb.API):
|
|||
return BaseCommand(self.context, 'br-get-external-id',
|
||||
args=[name, field])
|
||||
|
||||
def db_create(self, table, **col_values):
|
||||
args = [table]
|
||||
args += _set_colval_args(*col_values.items())
|
||||
return BaseCommand(self.context, 'create', args=args)
|
||||
|
||||
def db_destroy(self, table, record):
|
||||
args = [table, record]
|
||||
return BaseCommand(self.context, 'destroy', args=args)
|
||||
|
||||
def db_set(self, table, record, *col_values):
|
||||
args = [table, record]
|
||||
args += _set_colval_args(*col_values)
|
||||
|
@ -256,8 +265,11 @@ def _set_colval_args(*col_values):
|
|||
col, k, op, ovsdb.py_to_val(v)) for k, v in val.items()]
|
||||
elif (isinstance(val, collections.Sequence)
|
||||
and not isinstance(val, six.string_types)):
|
||||
args.append(
|
||||
"%s%s%s" % (col, op, ",".join(map(ovsdb.py_to_val, val))))
|
||||
if len(val) == 0:
|
||||
args.append("%s%s%s" % (col, op, "[]"))
|
||||
else:
|
||||
args.append(
|
||||
"%s%s%s" % (col, op, ",".join(map(ovsdb.py_to_val, val))))
|
||||
else:
|
||||
args.append("%s%s%s" % (col, op, ovsdb.py_to_val(val)))
|
||||
return args
|
||||
|
|
|
@ -148,6 +148,30 @@ class BrSetExternalIdCommand(BaseCommand):
|
|||
br.external_ids = external_ids
|
||||
|
||||
|
||||
class DbCreateCommand(BaseCommand):
|
||||
def __init__(self, api, table, **columns):
|
||||
super(DbCreateCommand, self).__init__(api)
|
||||
self.table = table
|
||||
self.columns = columns
|
||||
|
||||
def run_idl(self, txn):
|
||||
row = txn.insert(self.api._tables[self.table])
|
||||
for col, val in self.columns.items():
|
||||
setattr(row, col, val)
|
||||
self.result = row
|
||||
|
||||
|
||||
class DbDestroyCommand(BaseCommand):
|
||||
def __init__(self, api, table, record):
|
||||
super(DbDestroyCommand, self).__init__(api)
|
||||
self.table = table
|
||||
self.record = record
|
||||
|
||||
def run_idl(self, txn):
|
||||
record = idlutils.row_by_record(self.api.idl, self.table, self.record)
|
||||
record.delete()
|
||||
|
||||
|
||||
class DbSetCommand(BaseCommand):
|
||||
def __init__(self, api, table, record, *col_values):
|
||||
super(DbSetCommand, self).__init__(api)
|
||||
|
|
|
@ -261,6 +261,17 @@ class OVSBridgeTestCase(OVSBridgeTestBase):
|
|||
controller,
|
||||
'connection_mode'))
|
||||
|
||||
def test_qos_bw_limit(self):
|
||||
port_name, _ = self.create_ovs_port()
|
||||
self.br.create_qos_bw_limit_for_port(port_name, 700, 70)
|
||||
max_rate, burst = self.br.get_qos_bw_limit_for_port(port_name)
|
||||
self.assertEqual(700, max_rate)
|
||||
self.assertEqual(70, burst)
|
||||
self.br.del_qos_bw_limit_for_port(port_name)
|
||||
max_rate, burst = self.br.get_qos_bw_limit_for_port(port_name)
|
||||
self.assertIsNone(max_rate)
|
||||
self.assertIsNone(burst)
|
||||
|
||||
|
||||
class OVSLibTestCase(base.BaseOVSLinuxTestCase):
|
||||
|
||||
|
|
Loading…
Reference in New Issue