summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniil Baturin <daniil@vyos.io>2024-03-13 13:18:26 +0100
committerGitHub <noreply@github.com>2024-03-13 13:18:26 +0100
commit4dfc9b7c195e9cf3f57afbf8c84d701b73e83a8f (patch)
treece70aa88cdd993bba7b797adef58b7ee6162aa76
parent729d6785686284a61504dbfb8217888a485510dd (diff)
parent306e83a66e2e580417d87e3871200cad6c09cb49 (diff)
downloadvyos-1x-4dfc9b7c195e9cf3f57afbf8c84d701b73e83a8f.tar.gz
vyos-1x-4dfc9b7c195e9cf3f57afbf8c84d701b73e83a8f.zip
Merge pull request #3129 from vyos/mergify/bp/sagitta/pr-3125
radvd: T6118: add nat64prefix support RFC8781 (backport #3125)
-rw-r--r--data/templates/router-advert/radvd.conf.j27
-rw-r--r--interface-definitions/service_router-advert.xml.in30
-rwxr-xr-xsmoketest/scripts/cli/test_service_router-advert.py28
-rwxr-xr-xsrc/conf_mode/service_router-advert.py18
4 files changed, 80 insertions, 3 deletions
diff --git a/data/templates/router-advert/radvd.conf.j2 b/data/templates/router-advert/radvd.conf.j2
index 4ef4751dd..97180d164 100644
--- a/data/templates/router-advert/radvd.conf.j2
+++ b/data/templates/router-advert/radvd.conf.j2
@@ -50,6 +50,13 @@ interface {{ iface }} {
{% endfor %}
};
{% endif %}
+{% if iface_config.nat64prefix is vyos_defined %}
+{% for nat64prefix, nat64prefix_options in iface_config.nat64prefix.items() %}
+ nat64prefix {{ nat64prefix }} {
+ AdvValidLifetime {{ nat64prefix_options.valid_lifetime }};
+ };
+{% endfor %}
+{% endif %}
{% if iface_config.prefix is vyos_defined %}
{% for prefix, prefix_options in iface_config.prefix.items() %}
prefix {{ prefix }} {
diff --git a/interface-definitions/service_router-advert.xml.in b/interface-definitions/service_router-advert.xml.in
index 16c29022d..166a4a0cf 100644
--- a/interface-definitions/service_router-advert.xml.in
+++ b/interface-definitions/service_router-advert.xml.in
@@ -225,6 +225,36 @@
</leafNode>
</children>
</tagNode>
+ <tagNode name="nat64prefix">
+ <properties>
+ <help>NAT64 prefix included in the router advertisements</help>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 prefix to be advertized</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv6-prefix"/>
+ </constraint>
+ </properties>
+ <children>
+ <leafNode name="valid-lifetime">
+ <properties>
+ <help>Time in seconds that the prefix will remain valid</help>
+ <completionHelp>
+ <list>infinity</list>
+ </completionHelp>
+ <valueHelp>
+ <format>u32:4-65528</format>
+ <description>Time in seconds that the prefix will remain valid</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 4-65528"/>
+ </constraint>
+ </properties>
+ <defaultValue>65528</defaultValue>
+ </leafNode>
+ </children>
+ </tagNode>
<tagNode name="prefix">
<properties>
<help>IPv6 prefix to be advertised in Router Advertisements (RAs)</help>
diff --git a/smoketest/scripts/cli/test_service_router-advert.py b/smoketest/scripts/cli/test_service_router-advert.py
index 5fc2019fd..d1ff25a58 100755
--- a/smoketest/scripts/cli/test_service_router-advert.py
+++ b/smoketest/scripts/cli/test_service_router-advert.py
@@ -195,6 +195,34 @@ class TestServiceRADVD(VyOSUnitTestSHIM.TestCase):
for src in ra_src:
self.assertIn(f' {src};', config)
+ def test_nat64prefix(self):
+ nat64prefix = '64:ff9b::/96'
+ nat64prefix_invalid = '64:ff9b::/44'
+
+ self.cli_set(base_path + ['nat64prefix', nat64prefix])
+
+ # and another invalid prefix
+ # Invalid NAT64 prefix length for "2001:db8::/34", can only be one of:
+ # /32, /40, /48, /56, /64, /96
+ self.cli_set(base_path + ['nat64prefix', nat64prefix_invalid])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['nat64prefix', nat64prefix_invalid])
+
+ # NAT64 valid-lifetime must not be smaller then "interval max"
+ self.cli_set(base_path + ['nat64prefix', nat64prefix, 'valid-lifetime', '500'])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['nat64prefix', nat64prefix, 'valid-lifetime'])
+
+ # commit changes
+ self.cli_commit()
+
+ config = read_file(RADVD_CONF)
+
+ tmp = f'nat64prefix {nat64prefix}' + ' {'
+ self.assertIn(tmp, config)
+ self.assertIn('AdvValidLifetime 65528;', config) # default
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/service_router-advert.py b/src/conf_mode/service_router-advert.py
index dbb47de4e..88d767bb8 100755
--- a/src/conf_mode/service_router-advert.py
+++ b/src/conf_mode/service_router-advert.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2022 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -17,6 +17,8 @@
import os
from sys import exit
+from ipaddress import IPv6Network
+
from vyos.base import Warning
from vyos.config import Config
from vyos.template import render
@@ -47,7 +49,9 @@ def verify(rtradv):
return None
for interface, interface_config in rtradv['interface'].items():
- if 'prefix' in interface:
+ interval_max = int(interface_config['interval']['max'])
+
+ if 'prefix' in interface_config:
for prefix, prefix_config in interface_config['prefix'].items():
valid_lifetime = prefix_config['valid_lifetime']
if valid_lifetime == 'infinity':
@@ -60,6 +64,15 @@ def verify(rtradv):
if not (int(valid_lifetime) >= int(preferred_lifetime)):
raise ConfigError('Prefix valid-lifetime must be greater then or equal to preferred-lifetime')
+ if 'nat64prefix' in interface_config:
+ nat64_supported_lengths = [32, 40, 48, 56, 64, 96]
+ for prefix, prefix_config in interface_config['nat64prefix'].items():
+ if IPv6Network(prefix).prefixlen not in nat64_supported_lengths:
+ raise ConfigError(f'Invalid NAT64 prefix length for "{prefix}", can only be one of: /' + ', /'.join(nat64_supported_lengths))
+
+ if int(prefix_config['valid_lifetime']) < interval_max:
+ raise ConfigError(f'NAT64 valid-lifetime must not be smaller then "interval max" which is "{interval_max}"!')
+
if 'name_server' in interface_config:
if len(interface_config['name_server']) > 3:
raise ConfigError('No more then 3 IPv6 name-servers supported!')
@@ -72,7 +85,6 @@ def verify(rtradv):
# ensure stale RDNSS info gets removed in a timely fashion, this
# should not be greater than 2*MaxRtrAdvInterval.
lifetime = int(interface_config['name_server_lifetime'])
- interval_max = int(interface_config['interval']['max'])
if lifetime > 0:
if lifetime < int(interval_max):
raise ConfigError(f'RDNSS lifetime must be at least "{interval_max}" seconds!')