summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsmoketest/scripts/cli/test_nat64.py33
-rwxr-xr-xsrc/conf_mode/nat64.py22
2 files changed, 42 insertions, 13 deletions
diff --git a/smoketest/scripts/cli/test_nat64.py b/smoketest/scripts/cli/test_nat64.py
index dc0eb0abc..1a0172ccd 100755
--- a/smoketest/scripts/cli/test_nat64.py
+++ b/smoketest/scripts/cli/test_nat64.py
@@ -108,6 +108,39 @@ class TestNAT64(VyOSUnitTestSHIM.TestCase):
else:
self.fail(f'Unexpected protocol: {protocol}')
+ def test_snat64_single_instance(self):
+ # Pool ports must not overlap the kernel's local port range
+ tmp = sysctl_read(['net', 'ipv4', 'ip_local_port_range'])
+ _, local_port_max = map(int, tmp.split())
+ pool_port = f'{local_port_max +1}-{local_port_max +1000}'
+
+ rule_100_path = src_path + ['rule', '100']
+ self.cli_set(rule_100_path + ['source', 'prefix', '64:ff9b::/96'])
+ self.cli_set(
+ rule_100_path + ['translation', 'pool', '10', 'address', '192.0.2.10']
+ )
+ self.cli_set(rule_100_path + ['translation', 'pool', '10', 'port', pool_port])
+
+ rule_200_path = src_path + ['rule', '200']
+ self.cli_set(rule_200_path + ['source', 'prefix', '64:ff9c::/96'])
+ self.cli_set(
+ rule_200_path + ['translation', 'pool', '10', 'address', '192.0.2.20']
+ )
+ self.cli_set(rule_200_path + ['translation', 'pool', '10', 'port', pool_port])
+
+ # Jool supports only one netfilter NAT64 instance per network namespace,
+ # but does not refuse a second one - verify has to reject it
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ # Removing the second rule must make the config valid
+ self.cli_delete(rule_200_path)
+ self.cli_commit()
+
+ # The rejected commit must not have left an instance for rule 200 behind
+ self.assertTrue(os.path.exists('/run/jool/instance-100.json'))
+ self.assertFalse(os.path.exists('/run/jool/instance-200.json'))
+
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/src/conf_mode/nat64.py b/src/conf_mode/nat64.py
index 8afeeafe4..7bec596ee 100755
--- a/src/conf_mode/nat64.py
+++ b/src/conf_mode/nat64.py
@@ -77,11 +77,6 @@ def verify(nat64) -> None:
rules[num] = {'deleted': True}
continue
- # If the user changes the mode, recreate the instance else Jool fails with:
- # Jool error: Sorry; you can't change an instance's framework for now.
- if config_diff.is_node_changed(base_rule + [f'instance-{num}', 'mode']):
- rules[num]['recreate'] = True
-
# If the user changes the pool6, recreate the instance else Jool fails with:
# Jool error: Sorry; you can't change a NAT64 instance's pool6 for now.
if dict_search('source.prefix', rules[num]) and config_diff.is_node_changed(
@@ -100,15 +95,16 @@ def verify(nat64) -> None:
ephemeral_port_min, ephemeral_port_max = map(int, tmp.split())
if dict_search('source.rule', nat64):
- # Ensure only 1 netfilter instance per namespace
- nf_rules = filter(
- lambda i: 'deleted' not in i and i.get('mode') == 'netfilter',
- nat64['source']['rule'].values(),
- )
- next(nf_rules, None) # Discard the first element
- if next(nf_rules, None) is not None:
+ # https://nicmx.github.io/Jool/en/intro-jool.html
+ # Every instance uses the netfilter framework, and Jool supports only
+ # one of those per network namespace. Jool does not refuse a second
+ # instance, so the limit has to be enforced here.
+ active_rules = [
+ r for r, i in nat64['source']['rule'].items() if 'deleted' not in i
+ ]
+ if len(active_rules) > 1:
raise ConfigError(
- 'Jool permits only 1 NAT64 netfilter instance (per network namespace)'
+ 'Jool supports only 1 NAT64 netfilter instance (per network namespace)'
)
for rule, instance in nat64['source']['rule'].items():