summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2026-05-26 08:34:20 +0200
committerGitHub <noreply@github.com>2026-05-26 08:34:20 +0200
commit567e968f5c6ee86360151144bd8239ec2cdca12b (patch)
tree81ef5b86ce6bfc636c944c35b898cc99a3de94b3
parent9534f4202e4430b4a58caa28603e5594178fd745 (diff)
parenta3f1a67981299d281f6831ea077830d37c4c4740 (diff)
downloadvyos-1x-567e968f5c6ee86360151144bd8239ec2cdca12b.tar.gz
vyos-1x-567e968f5c6ee86360151144bd8239ec2cdca12b.zip
Merge pull request #5179 from josephillips85/current
Policy: T8823: validation of GE and LE according FRR instructions
-rwxr-xr-xsmoketest/scripts/cli/test_policy.py51
-rwxr-xr-xsrc/conf_mode/policy.py20
2 files changed, 71 insertions, 0 deletions
diff --git a/smoketest/scripts/cli/test_policy.py b/smoketest/scripts/cli/test_policy.py
index 76a9d09a5..304bbdbc8 100755
--- a/smoketest/scripts/cli/test_policy.py
+++ b/smoketest/scripts/cli/test_policy.py
@@ -709,6 +709,57 @@ class TestPolicy(VyOSUnitTestSHIM.TestCase):
for rule in test_range:
tmp = f'ip prefix-list {prefix_list} seq {rule} permit {prefix} le {rule}'
self.assertIn(tmp, config)
+
+ def test_prefix_list_ge_le_validation(self):
+ # FRR requires mask_length <= ge <= le for prefix-list rules
+ base = base_path + ['prefix-list', 'getest', 'rule', '10']
+ base6 = base_path + ['prefix-list6', 'getest6', 'rule', '10']
+
+ # ge < mask_length should be rejected
+ self.cli_set(base + ['action', 'permit'])
+ self.cli_set(base + ['prefix', '192.0.2.0/24'])
+ self.cli_set(base + ['ge', '16'])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base + ['ge'])
+
+ # le < mask_length should be rejected
+ self.cli_set(base + ['le', '16'])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base + ['le'])
+
+ # ge > le should be rejected
+ self.cli_set(base + ['ge', '28'])
+ self.cli_set(base + ['le', '26'])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base + ['ge'])
+ self.cli_delete(base + ['le'])
+
+ # valid ge <= le >= mask_length should commit
+ self.cli_set(base + ['ge', '25'])
+ self.cli_set(base + ['le', '28'])
+ self.cli_commit()
+ self.cli_delete(base_path + ['prefix-list', 'getest'])
+
+ # same checks for prefix-list6
+ self.cli_set(base6 + ['action', 'permit'])
+ self.cli_set(base6 + ['prefix', '2a06:9801:2c0::/44'])
+ self.cli_set(base6 + ['ge', '48'])
+ self.cli_set(base6 + ['le', '44'])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base6 + ['ge'])
+ self.cli_delete(base6 + ['le'])
+
+ # valid IPv6 ge/le
+ self.cli_set(base6 + ['ge', '48'])
+ self.cli_set(base6 + ['le', '64'])
+ self.cli_commit()
+ self.cli_delete(base_path + ['prefix-list6', 'getest6'])
+ self.cli_commit()
+
def test_route_map_community_set(self):
test_data = {
"community-configuration": {
diff --git a/src/conf_mode/policy.py b/src/conf_mode/policy.py
index 689365724..171ef23fd 100755
--- a/src/conf_mode/policy.py
+++ b/src/conf_mode/policy.py
@@ -167,6 +167,26 @@ def verify(config_dict):
if 'prefix' not in rule_config:
raise ConfigError(f'A prefix {mandatory_error}')
+ mask_len = int(rule_config['prefix'].split('/')[1])
+ ge = dict_search('ge', rule_config)
+ le = dict_search('le', rule_config)
+
+ if ge and int(ge) < mask_len:
+ raise ConfigError(
+ f'{policy_hr} {instance} rule {rule}: "ge" ({ge}) must be >= '
+ f'prefix length ({mask_len})'
+ )
+ if le and int(le) < mask_len:
+ raise ConfigError(
+ f'{policy_hr} {instance} rule {rule}: "le" ({le}) must be >= '
+ f'prefix length ({mask_len})'
+ )
+ if ge and le and int(ge) > int(le):
+ raise ConfigError(
+ f'{policy_hr} {instance} rule {rule}: "ge" ({ge}) must be <= '
+ f'"le" ({le})'
+ )
+
if rule_config in entries:
raise ConfigError(
f'Rule "{rule}" contains a duplicate prefix definition!')