diff options
| -rwxr-xr-x | smoketest/scripts/cli/test_nat64.py | 33 | ||||
| -rwxr-xr-x | src/conf_mode/nat64.py | 22 |
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(): |
