From db494f512ae62eab3d90b786da5f8d855b45ec7d Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sat, 17 Oct 2026 20:55:12 +0200 Subject: wlb: T9472: honour limit threshold "above" on rules "limit threshold above" was ignored. The rule always matched the traffic below the rate, the same as the default "below". With "above" the rule now matches the traffic exceeding the rate. --- python/vyos/wanloadbalance.py | 4 +++- smoketest/scripts/cli/test_load-balancing_wan.py | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/python/vyos/wanloadbalance.py b/python/vyos/wanloadbalance.py index fc9fb1ade..a8cd87350 100644 --- a/python/vyos/wanloadbalance.py +++ b/python/vyos/wanloadbalance.py @@ -117,7 +117,9 @@ def nft_rule(rule_conf, rule_id, local=False, exclude=False, limit=False, weight output.append('ct state new') if limit and 'limit' in rule_conf and 'rate' in rule_conf['limit']: - output.append(f'limit rate {rule_conf["limit"]["rate"]}/{rule_conf["limit"]["period"]}') + # "above" matches the traffic exceeding the rate, "below" the rest + over = 'over ' if rule_conf['limit'].get('threshold') == 'above' else '' + output.append(f'limit rate {over}{rule_conf["limit"]["rate"]}/{rule_conf["limit"]["period"]}') if 'burst' in rule_conf['limit']: output.append(f'burst {rule_conf["limit"]["burst"]} packets') diff --git a/smoketest/scripts/cli/test_load-balancing_wan.py b/smoketest/scripts/cli/test_load-balancing_wan.py index c46c445bb..c48a30a4c 100755 --- a/smoketest/scripts/cli/test_load-balancing_wan.py +++ b/smoketest/scripts/cli/test_load-balancing_wan.py @@ -787,6 +787,30 @@ printf 'WLB_INTERFACE_NAME=%s WLB_SCRIPT_IFACE=%s\\n' \\ cmd_in_netns('wlb-lan', f'ping -c 20 -i 0.05 -W 1 {lab_target}') counts = self.lab_count_echo_requests(len(isps)) self.assertTrue(all(counts), msg=f'echo requests per ISP: {counts}') + def test_limit_threshold_above(self): + # the threshold was ignored, "above" behaved like "below" + isps = ['eth231', 'eth232'] + self.lab_setup('eth230', isps) + for index, ifname in enumerate(isps, start=1): + self.lab_health(ifname, index) + # connections beyond one per second go to isp2, all others to isp1 + rule = base_path + ['wan', 'rule', '10'] + self.cli_set(rule + ['inbound-interface', 'eth230']) + self.cli_set(rule + ['interface', 'eth232']) + self.cli_set(rule + ['limit', 'rate', '1']) + self.cli_set(rule + ['limit', 'burst', '1']) + self.cli_set(rule + ['limit', 'threshold', 'above']) + self.cli_set(base_path + ['wan', 'rule', '20', 'inbound-interface', 'eth230']) + self.cli_set(base_path + ['wan', 'rule', '20', 'interface', 'eth231']) + self.cli_commit() + + self.lab_wait_status({'eth231': 'ACTIVE', 'eth232': 'ACTIVE'}) + found, out = self.wait_for_result(lambda: wlb_chain('wlb_mangle_prerouting'), + lambda out: 'limit rate over 1/second burst 1 packets' in out, timeout=15) + self.assertTrue(found, msg=out) + + answers = [self.lab_connect() for _ in range(10)] + self.assertGreaterEqual(answers.count('isp2 peer=10.250.2.1'), 5, msg=answers) if __name__ == '__main__': unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on()) -- cgit v1.2.3