summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface-definitions/include/qos/queue-average-packet.xml.i16
-rw-r--r--interface-definitions/include/qos/queue-mark-probability.xml.i16
-rw-r--r--interface-definitions/include/qos/queue-maximum-threshold.xml.i16
-rw-r--r--interface-definitions/include/qos/queue-minimum-threshold.xml.i15
-rw-r--r--interface-definitions/qos.xml.in67
-rw-r--r--python/vyos/qos/base.py29
-rwxr-xr-xsmoketest/scripts/cli/test_qos.py64
7 files changed, 167 insertions, 56 deletions
diff --git a/interface-definitions/include/qos/queue-average-packet.xml.i b/interface-definitions/include/qos/queue-average-packet.xml.i
new file mode 100644
index 000000000..2f8bfe266
--- /dev/null
+++ b/interface-definitions/include/qos/queue-average-packet.xml.i
@@ -0,0 +1,16 @@
+<!-- include start from qos/queue-average-packet.xml.i -->
+<leafNode name="average-packet">
+ <properties>
+ <help>Average packet size (bytes)</help>
+ <valueHelp>
+ <format>u32:16-10240</format>
+ <description>Average packet size in bytes</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 16-10240"/>
+ </constraint>
+ <constraintErrorMessage>Average packet size must be between 16 and 10240</constraintErrorMessage>
+ </properties>
+ <defaultValue>1024</defaultValue>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/qos/queue-mark-probability.xml.i b/interface-definitions/include/qos/queue-mark-probability.xml.i
new file mode 100644
index 000000000..1a2862845
--- /dev/null
+++ b/interface-definitions/include/qos/queue-mark-probability.xml.i
@@ -0,0 +1,16 @@
+<!-- include start from qos/queue-mark-probability.xml.i -->
+<leafNode name="mark-probability">
+ <properties>
+ <help>Mark probability for random detection</help>
+ <valueHelp>
+ <format>u32</format>
+ <description>Numeric value (1/N)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--positive"/>
+ </constraint>
+ <constraintErrorMessage>Mark probability must be greater than 0</constraintErrorMessage>
+ </properties>
+ <defaultValue>10</defaultValue>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/qos/queue-maximum-threshold.xml.i b/interface-definitions/include/qos/queue-maximum-threshold.xml.i
new file mode 100644
index 000000000..66d17ccc4
--- /dev/null
+++ b/interface-definitions/include/qos/queue-maximum-threshold.xml.i
@@ -0,0 +1,16 @@
+<!-- include start from qos/queue-maximum-threshold.xml.i -->
+<leafNode name="maximum-threshold">
+ <properties>
+ <help>Maximum threshold for random detection</help>
+ <valueHelp>
+ <format>u32:0-4096</format>
+ <description>Maximum threshold in packets</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 0-4096"/>
+ </constraint>
+ <constraintErrorMessage>Threshold must be between 0 and 4096</constraintErrorMessage>
+ </properties>
+ <defaultValue>18</defaultValue>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/qos/queue-minimum-threshold.xml.i b/interface-definitions/include/qos/queue-minimum-threshold.xml.i
new file mode 100644
index 000000000..81e12d6e2
--- /dev/null
+++ b/interface-definitions/include/qos/queue-minimum-threshold.xml.i
@@ -0,0 +1,15 @@
+<!-- include start from qos/queue-minimum-threshold.xml.i -->
+<leafNode name="minimum-threshold">
+ <properties>
+ <help>Minimum threshold for random detection</help>
+ <valueHelp>
+ <format>u32:0-4096</format>
+ <description>Minimum threshold in packets</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 0-4096"/>
+ </constraint>
+ <constraintErrorMessage>Threshold must be between 0 and 4096</constraintErrorMessage>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/qos.xml.in b/interface-definitions/qos.xml.in
index 7618c3027..8f9ae3fa6 100644
--- a/interface-definitions/qos.xml.in
+++ b/interface-definitions/qos.xml.in
@@ -470,61 +470,10 @@
</properties>
<children>
#include <include/qos/queue-limit-1-4294967295.xml.i>
- <leafNode name="average-packet">
- <properties>
- <help>Average packet size (bytes)</help>
- <valueHelp>
- <format>u32:16-10240</format>
- <description>Average packet size in bytes</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 0-100"/>
- </constraint>
- <constraintErrorMessage>Average packet size must be between 16 and 10240</constraintErrorMessage>
- </properties>
- <defaultValue>1024</defaultValue>
- </leafNode>
- <leafNode name="mark-probability">
- <properties>
- <help>Mark probability for this precedence</help>
- <valueHelp>
- <format>&lt;number&gt;</format>
- <description>Numeric value (1/N)</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--positive"/>
- </constraint>
- <constraintErrorMessage>Mark probability must be greater than 0</constraintErrorMessage>
- </properties>
- <defaultValue>10</defaultValue>
- </leafNode>
- <leafNode name="maximum-threshold">
- <properties>
- <help>Maximum threshold for random detection</help>
- <valueHelp>
- <format>u32:0-4096</format>
- <description>Maximum Threshold in packets</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 0-4096"/>
- </constraint>
- <constraintErrorMessage>Threshold must be between 0 and 4096</constraintErrorMessage>
- </properties>
- <defaultValue>18</defaultValue>
- </leafNode>
- <leafNode name="minimum-threshold">
- <properties>
- <help>Minimum threshold for random detection</help>
- <valueHelp>
- <format>u32:0-4096</format>
- <description>Maximum Threshold in packets</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 0-4096"/>
- </constraint>
- <constraintErrorMessage>Threshold must be between 0 and 4096</constraintErrorMessage>
- </properties>
- </leafNode>
+ #include <include/qos/queue-average-packet.xml.i>
+ #include <include/qos/queue-maximum-threshold.xml.i>
+ #include <include/qos/queue-minimum-threshold.xml.i>
+ #include <include/qos/queue-mark-probability.xml.i>
</children>
</tagNode>
</children>
@@ -697,6 +646,10 @@
#include <include/qos/interval.xml.i>
#include <include/qos/class-match.xml.i>
#include <include/qos/class-priority.xml.i>
+ #include <include/qos/queue-average-packet.xml.i>
+ #include <include/qos/queue-maximum-threshold.xml.i>
+ #include <include/qos/queue-minimum-threshold.xml.i>
+ #include <include/qos/queue-mark-probability.xml.i>
#include <include/qos/queue-limit-1-4294967295.xml.i>
#include <include/qos/queue-type.xml.i>
<leafNode name="queue-type">
@@ -759,6 +712,10 @@
</properties>
<defaultValue>20</defaultValue>
</leafNode>
+ #include <include/qos/queue-average-packet.xml.i>
+ #include <include/qos/queue-maximum-threshold.xml.i>
+ #include <include/qos/queue-minimum-threshold.xml.i>
+ #include <include/qos/queue-mark-probability.xml.i>
#include <include/qos/queue-limit-1-4294967295.xml.i>
#include <include/qos/queue-type.xml.i>
<leafNode name="queue-type">
diff --git a/python/vyos/qos/base.py b/python/vyos/qos/base.py
index c8e881ee2..f9366c6b1 100644
--- a/python/vyos/qos/base.py
+++ b/python/vyos/qos/base.py
@@ -90,6 +90,23 @@ class QoSBase:
else:
return value
+ def _calc_random_detect_queue_params(self, avg_pkt, max_thr, limit=None, min_thr=None, mark_probability=None):
+ 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
+
+ params['avg_pkt'] = avg_pkt
+ params['limit'] = limit * avg_pkt
+ params['min_val'] = min_thr * avg_pkt
+ params['max_val'] = max_thr * avg_pkt
+ params['burst'] = (2 * min_thr + max_thr) // 3
+ params['probability'] = 1 / mark_probability
+
+ return params
+
def _build_base_qdisc(self, config : dict, cls_id : int):
"""
Add/replace qdisc for every class (also default is a class). This is
@@ -144,6 +161,18 @@ class QoSBase:
elif queue_type == 'random-detect':
default_tc += f' red'
+ qparams = self._calc_random_detect_queue_params(
+ avg_pkt=dict_search('average_packet', config),
+ max_thr=dict_search('maximum_threshold', config),
+ limit=dict_search('queue_limit', config),
+ min_thr=dict_search('minimum_threshold', config),
+ mark_probability=dict_search('mark_probability', config)
+ )
+
+ default_tc += f' limit {qparams["limit"]} avpkt {qparams["avg_pkt"]}'
+ default_tc += f' max {qparams["max_val"]} min {qparams["min_val"]}'
+ default_tc += f' burst {qparams["burst"]} probability {qparams["probability"]}'
+
self._cmd(default_tc)
elif queue_type == 'drop-tail':
diff --git a/smoketest/scripts/cli/test_qos.py b/smoketest/scripts/cli/test_qos.py
index 1eb4b5cfb..4f41e36cd 100755
--- a/smoketest/scripts/cli/test_qos.py
+++ b/smoketest/scripts/cli/test_qos.py
@@ -581,7 +581,6 @@ class TestQoS(VyOSUnitTestSHIM.TestCase):
dport = int(match_config['dport'])
self.assertEqual(f'{dport:x}', filter['options']['match']['value'])
-
def test_11_shaper(self):
bandwidth = 250
default_bandwidth = 20
@@ -635,6 +634,69 @@ class TestQoS(VyOSUnitTestSHIM.TestCase):
class_bandwidth += 1
class_ceil += 1
+ def test_12_shaper_with_red_queue(self):
+ bandwidth = 100
+ default_bandwidth = 100
+ default_burst = 100
+ interface = self._interfaces[0]
+ class_bandwidth = 50
+ dst_address = '192.0.2.8/32'
+
+ shaper_name = f'qos-shaper-{interface}'
+ self.cli_set(base_path + ['interface', interface, 'egress', shaper_name])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'bandwidth', f'{bandwidth}mbit'])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'default', 'bandwidth', f'{default_bandwidth}%'])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'default', 'burst', f'{default_burst}'])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'default', 'queue-type', 'random-detect'])
+
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'class', '2', 'bandwidth', f'{class_bandwidth}mbit'])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'class', '2', 'match', '10', 'ip', 'destination', 'address', dst_address])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'class', '2', 'queue-type', 'random-detect'])
+
+ # commit changes
+ self.cli_commit()
+
+ # check root htb config
+ output = cmd(f'tc class show dev {interface}')
+
+ config_entries = (
+ f'prio 0 rate {class_bandwidth}Mbit ceil 50Mbit burst 15Kb', # specified class
+ f'prio 7 rate {default_bandwidth}Mbit ceil 100Mbit burst {default_burst}b', # default class
+ )
+ for config_entry in config_entries:
+ self.assertIn(config_entry, output)
+
+ output = cmd(f'tc -d qdisc show dev {interface}')
+ config_entries = (
+ 'qdisc red', # use random detect
+ 'limit 72Kb min 9Kb max 18Kb ewma 3 probability 0.1', # default config for random detect
+ )
+ for config_entry in config_entries:
+ self.assertIn(config_entry, output)
+
+ # test random detect queue params
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'default', 'queue-limit', '1024'])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'default', 'average-packet', '1024'])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'default', 'maximum-threshold', '32'])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'default', 'minimum-threshold', '16'])
+
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'class', '2', 'queue-limit', '1024'])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'class', '2', 'average-packet', '512'])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'class', '2', 'maximum-threshold', '32'])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'class', '2', 'minimum-threshold', '16'])
+ self.cli_set(base_path + ['policy', 'shaper', shaper_name, 'class', '2', 'mark-probability', '20'])
+
+ self.cli_commit()
+
+ output = cmd(f'tc -d qdisc show dev {interface}')
+ config_entries = (
+ 'qdisc red', # use random detect
+ 'limit 1Mb min 16Kb max 32Kb ewma 3 probability 0.1', # default config for random detect
+ 'limit 512Kb min 8Kb max 16Kb ewma 3 probability 0.05', # class config for random detect
+ )
+ for config_entry in config_entries:
+ self.assertIn(config_entry, output)
+
if __name__ == '__main__':
unittest.main(verbosity=2)