[Qos] ingress bandwidth limit by ovs is not accurate

According to Open vSwitch FAQ [1], max-rate value which is set for
all queues in qos is set as link speed in case when it is not specified.
This can lead to inaccurate ingress bandwidth limits in case when QoS is
applied e.g. directly on tapXXX port (which is "tun" interface type) and
configured bandwidth limit is higher than interface's link_speed.
This patch set max-rate parameter in qos's other_config table to not use
default value determined by Open vSwitch and to make rate limits more
accurate.

The modification is covered by functional tests in
https://github.com/openstack/neutron/blob/master/neutron/tests/
functional/agent/test_ovs_lib.py.

[1] http://docs.openvswitch.org/en/latest/faq/qos/

Change-Id: Id937216a724fbf776298efd11f74ac71056cfe06
Closes-Bug: #1730605
(cherry picked from commit c43317e380)
This commit is contained in:
Zachary 2017-11-14 15:48:54 +08:00 committed by Slawek Kaplonski
parent 8c5fc0fa6a
commit adc344c065

View File

@ -702,23 +702,30 @@ class OVSBridge(BaseOVS):
return queue_uuid return queue_uuid
def _update_bw_limit_profile(self, txn, port_name, qos_uuid, def _update_bw_limit_profile(self, txn, port_name, qos_uuid,
queue_uuid, queue_type): queue_uuid, queue_type, qos_other_config):
queues = {queue_type: queue_uuid} queues = {queue_type: queue_uuid}
if qos_uuid: if qos_uuid:
txn.add(self.ovsdb.db_set( txn.add(self.ovsdb.db_set(
'QoS', qos_uuid, ('queues', queues))) 'QoS', qos_uuid, ('queues', queues)))
txn.add(self.ovsdb.db_set(
'QoS', qos_uuid, ('other_config', qos_other_config)))
else: else:
external_ids = {'id': port_name} external_ids = {'id': port_name}
qos_uuid = txn.add( qos_uuid = txn.add(
self.ovsdb.db_create( self.ovsdb.db_create(
'QoS', external_ids=external_ids, type='linux-htb', 'QoS', external_ids=external_ids,
queues=queues)) type='linux-htb',
queues=queues,
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_ingress_bw_limit_for_port(self, port_name, max_kbps,
max_burst_kbps): max_burst_kbps):
max_bw_in_bits = str(max_kbps * 1000) max_bw_in_bits = str(max_kbps * 1000)
max_burst_in_bits = str(max_burst_kbps * 1000) max_burst_in_bits = str(max_burst_kbps * 1000)
qos_other_config = {
'max-rate': max_bw_in_bits
}
queue_other_config = { queue_other_config = {
'max-rate': max_bw_in_bits, 'max-rate': max_bw_in_bits,
'burst': max_burst_in_bits, 'burst': max_burst_in_bits,
@ -734,7 +741,8 @@ class OVSBridge(BaseOVS):
) )
qos_uuid = self._update_bw_limit_profile( qos_uuid = self._update_bw_limit_profile(
txn, port_name, qos_uuid, queue_uuid, QOS_DEFAULT_QUEUE txn, port_name, qos_uuid, queue_uuid, QOS_DEFAULT_QUEUE,
qos_other_config
) )
txn.add(self.ovsdb.db_set( txn.add(self.ovsdb.db_set(
@ -742,16 +750,35 @@ class OVSBridge(BaseOVS):
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
queue_max_kbps = None
max_burst_kbit = None max_burst_kbit = None
res = self.find_queue(port_name, QOS_DEFAULT_QUEUE)
if res: qos_res = self.find_qos(port_name)
other_config = res['other_config'] if qos_res:
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:
max_kbps = int(max_bw_in_bits) / 1000 qos_max_kbps = int(max_bw_in_bits) / 1000
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) / 1000
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) / 1000
if qos_max_kbps == queue_max_kbps:
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 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):