Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

qos: T6225: Fix QoS random-detect policy (backport #3400) #3401

Merged
merged 1 commit into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions python/vyos/qos/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,14 @@ def _get_dsfield(self, value):
else:
return value

def _calc_random_detect_queue_params(self, avg_pkt, max_thr, limit=None, min_thr=None, mark_probability=None):
def _calc_random_detect_queue_params(self, avg_pkt, max_thr, limit=None, min_thr=None,
mark_probability=None, precedence=0):
params = dict()
avg_pkt = int(avg_pkt)
max_thr = int(max_thr)
mark_probability = int(mark_probability)
limit = int(limit) if limit else 4 * max_thr
min_thr = int(min_thr) if min_thr else (9 * max_thr) // 18
min_thr = int(min_thr) if min_thr else ((9 + precedence) * max_thr) // 18

params['avg_pkt'] = avg_pkt
params['limit'] = limit * avg_pkt
Expand Down
34 changes: 13 additions & 21 deletions python/vyos/qos/randomdetect.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,25 @@ class RandomDetect(QoSBase):
# https://man7.org/linux/man-pages/man8/tc.8.html
def update(self, config, direction):

tmp = f'tc qdisc add dev {self._interface} root handle {self._parent}:0 dsmark indices 8 set_tc_index'
# # Generalized Random Early Detection
handle = self._parent
tmp = f'tc qdisc add dev {self._interface} root handle {self._parent}:0 gred setup DPs 8 default 0 grio'
self._cmd(tmp)

tmp = f'tc filter add dev {self._interface} parent {self._parent}:0 protocol ip prio 1 tcindex mask 0xe0 shift 5'
self._cmd(tmp)

# Generalized Random Early Detection
handle = self._parent +1
tmp = f'tc qdisc add dev {self._interface} parent {self._parent}:0 handle {handle}:0 gred setup DPs 8 default 0 grio'
self._cmd(tmp)

bandwidth = self._rate_convert(config['bandwidth'])

# set VQ (virtual queue) parameters
for precedence, precedence_config in config['precedence'].items():
precedence = int(precedence)
avg_pkt = int(precedence_config['average_packet'])
limit = int(precedence_config['queue_limit']) * avg_pkt
min_val = int(precedence_config['minimum_threshold']) * avg_pkt
max_val = int(precedence_config['maximum_threshold']) * avg_pkt

tmp = f'tc qdisc change dev {self._interface} handle {handle}:0 gred limit {limit} min {min_val} max {max_val} avpkt {avg_pkt} '

burst = (2 * int(precedence_config['minimum_threshold']) + int(precedence_config['maximum_threshold'])) // 3
probability = 1 / int(precedence_config['mark_probability'])
tmp += f'burst {burst} bandwidth {bandwidth} probability {probability} DP {precedence} prio {8 - precedence:x}'

qparams = self._calc_random_detect_queue_params(
avg_pkt=precedence_config.get('average_packet'),
max_thr=precedence_config.get('maximum_threshold'),
limit=precedence_config.get('queue_limit'),
min_thr=precedence_config.get('minimum_threshold'),
mark_probability=precedence_config.get('mark_probability'),
precedence=precedence
)
tmp = f'tc qdisc change dev {self._interface} handle {handle}:0 gred limit {qparams["limit"]} min {qparams["min_val"]} max {qparams["max_val"]} avpkt {qparams["avg_pkt"]} '
tmp += f'burst {qparams["burst"]} bandwidth {bandwidth} probability {qparams["probability"]} DP {precedence} prio {8 - precedence:x}'
self._cmd(tmp)

# call base class
Expand Down
8 changes: 5 additions & 3 deletions smoketest/scripts/cli/test_qos.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,6 @@ def test_07_priority_queue(self):
self.cli_commit()

def test_08_random_detect(self):
self.skipTest('tc returns invalid JSON here - needs iproute2 fix')
bandwidth = 5000

first = True
Expand All @@ -467,8 +466,11 @@ def test_08_random_detect(self):
bandwidth = 5000
for interface in self._interfaces:
tmp = get_tc_qdisc_json(interface)
import pprint
pprint.pprint(tmp)
self.assertTrue('gred' in tmp.get('kind'))
self.assertEqual(8, len(tmp.get('options', {}).get('vqs')))
self.assertEqual(8, tmp.get('options', {}).get('dp_cnt'))
self.assertEqual(0, tmp.get('options', {}).get('dp_default'))
self.assertTrue(tmp.get('options', {}).get('grio'))

def test_09_rate_control(self):
bandwidth = 5000
Expand Down
29 changes: 15 additions & 14 deletions src/conf_mode/qos.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
from vyos.utils.process import run
from vyos import ConfigError
from vyos import airbag
from vyos.xml_ref import relative_defaults


airbag.enable()

map_vyops_tc = {
Expand Down Expand Up @@ -115,27 +118,25 @@ def get_config(config=None):
for rd_name in list(qos['policy'][policy]):
# There are eight precedence levels - ensure all are present
# to be filled later down with the appropriate default values
default_precedence = {'precedence' : { '0' : {}, '1' : {}, '2' : {}, '3' : {},
'4' : {}, '5' : {}, '6' : {}, '7' : {} }}
default_p_val = relative_defaults(
['qos', 'policy', 'random-detect', rd_name, 'precedence'],
{'precedence': {'0': {}}},
get_first_key=True, recursive=True
)['0']
default_p_val = {key.replace('-', '_'): value for key, value in default_p_val.items()}
default_precedence = {
'precedence': {'0': default_p_val, '1': default_p_val,
'2': default_p_val, '3': default_p_val,
'4': default_p_val, '5': default_p_val,
'6': default_p_val, '7': default_p_val}}

qos['policy']['random_detect'][rd_name] = dict_merge(
default_precedence, qos['policy']['random_detect'][rd_name])

qos = conf.merge_defaults(qos, recursive=True)

for policy in qos.get('policy', []):
for p_name, p_config in qos['policy'][policy].items():
if 'precedence' in p_config:
# precedence settings are a bit more complex as they are
# calculated under specific circumstances:
for precedence in p_config['precedence']:
max_thr = int(qos['policy'][policy][p_name]['precedence'][precedence]['maximum_threshold'])
if 'minimum_threshold' not in qos['policy'][policy][p_name]['precedence'][precedence]:
qos['policy'][policy][p_name]['precedence'][precedence]['minimum_threshold'] = str(
int((9 + int(precedence)) * max_thr) // 18);

if 'queue_limit' not in qos['policy'][policy][p_name]['precedence'][precedence]:
qos['policy'][policy][p_name]['precedence'][precedence]['queue_limit'] = \
str(int(4 * max_thr))
# cleanup empty match config
if 'class' in p_config:
for cls, cls_config in p_config['class'].items():
Expand Down
Loading