From d187803c31175e471397dd4f77040ab56d2e1073 Mon Sep 17 00:00:00 2001
From: aapostoliuk <a.apostoliuk@vyos.io>
Date: Fri, 12 Jan 2024 12:51:46 +0200
Subject: T5865: Moved ipv6 pools to named ipv6 pools in accel-ppp

Moved ipv6 pools to named ipv6 pools in accel-ppp services
---
 data/templates/accel-ppp/config_ipv6_pool.j2       | 21 ++++----
 data/templates/accel-ppp/ipoe.config.j2            |  4 ++
 data/templates/accel-ppp/l2tp.config.j2            |  4 ++
 data/templates/accel-ppp/pppoe.config.j2           |  4 ++
 data/templates/accel-ppp/sstp.config.j2            |  4 ++
 .../include/accel-ppp/client-ipv6-pool.xml.i       | 11 +++-
 .../include/accel-ppp/default-ipv6-pool.xml.i      | 17 ++++++
 .../include/version/ipoe-server-version.xml.i      |  2 +-
 .../include/version/l2tp-version.xml.i             |  2 +-
 .../include/version/pppoe-server-version.xml.i     |  2 +-
 .../include/version/sstp-version.xml.i             |  2 +-
 interface-definitions/service_ipoe-server.xml.in   |  1 +
 interface-definitions/service_pppoe-server.xml.in  |  1 +
 interface-definitions/vpn_l2tp.xml.in              |  1 +
 interface-definitions/vpn_pptp.xml.in              |  1 +
 interface-definitions/vpn_sstp.xml.in              |  1 +
 python/vyos/accel_ppp_util.py                      | 41 ++++++++------
 smoketest/scripts/cli/base_accel_ppp_test.py       | 53 +++++++++++++++++-
 smoketest/scripts/cli/test_service_ipoe-server.py  | 41 +++++++++++++-
 smoketest/scripts/cli/test_service_pppoe-server.py | 57 ++++++--------------
 smoketest/scripts/cli/test_vpn_l2tp.py             | 54 ++++++-------------
 smoketest/scripts/cli/test_vpn_pptp.py             |  6 ++-
 src/conf_mode/service_ipoe-server.py               |  5 +-
 src/conf_mode/service_pppoe-server.py              |  3 +-
 src/conf_mode/vpn_l2tp.py                          | 10 +---
 src/conf_mode/vpn_pptp.py                          |  6 ---
 src/conf_mode/vpn_sstp.py                          |  5 +-
 src/migration-scripts/ipoe-server/2-to-3           | 61 +++++++++++++++++++++
 src/migration-scripts/l2tp/6-to-7                  | 60 +++++++++++++++++++++
 src/migration-scripts/pppoe-server/7-to-8          | 61 +++++++++++++++++++++
 src/migration-scripts/sstp/5-to-6                  | 62 ++++++++++++++++++++++
 31 files changed, 465 insertions(+), 138 deletions(-)
 create mode 100644 interface-definitions/include/accel-ppp/default-ipv6-pool.xml.i
 create mode 100755 src/migration-scripts/ipoe-server/2-to-3
 create mode 100755 src/migration-scripts/l2tp/6-to-7
 create mode 100755 src/migration-scripts/pppoe-server/7-to-8
 create mode 100755 src/migration-scripts/sstp/5-to-6

diff --git a/data/templates/accel-ppp/config_ipv6_pool.j2 b/data/templates/accel-ppp/config_ipv6_pool.j2
index a1562a1eb..86efdc1e1 100644
--- a/data/templates/accel-ppp/config_ipv6_pool.j2
+++ b/data/templates/accel-ppp/config_ipv6_pool.j2
@@ -3,20 +3,19 @@
 AdvAutonomousFlag=1
 verbose=1
 
-{%     if client_ipv6_pool.prefix is vyos_defined %}
 [ipv6-pool]
-{%         for prefix, options in client_ipv6_pool.prefix.items() %}
-{{ prefix }},{{ options.mask }}
-{%         endfor %}
-{%         if client_ipv6_pool.delegate is vyos_defined %}
-{%             for prefix, options in client_ipv6_pool.delegate.items() %}
-delegate={{ prefix }},{{ options.delegation_prefix }}
+{%     for pool_name, pool_config in client_ipv6_pool.items() %}
+{%         if pool_config.prefix is vyos_defined %}
+{%             for prefix, options in pool_config.prefix.items() %}
+{{ prefix }},{{ options.mask }},name={{ pool_name }}
 {%             endfor %}
 {%         endif %}
-{%     endif %}
-
-{%     if client_ipv6_pool.delegate is vyos_defined %}
+{%         if pool_config.delegate is vyos_defined %}
+{%             for prefix, options in pool_config.delegate.items() %}
+delegate={{ prefix }},{{ options.delegation_prefix }},name={{ pool_name }}
+{%             endfor %}
+{%         endif %}
+{%     endfor %}
 [ipv6-dhcp]
 verbose=1
-{%     endif %}
 {% endif %}
diff --git a/data/templates/accel-ppp/ipoe.config.j2 b/data/templates/accel-ppp/ipoe.config.j2
index 588f3d462..8b022eaa5 100644
--- a/data/templates/accel-ppp/ipoe.config.j2
+++ b/data/templates/accel-ppp/ipoe.config.j2
@@ -58,6 +58,10 @@ password=csid
 {% if default_pool is vyos_defined %}
 ip-pool={{ default_pool }}
 {% endif %}
+{% if default_ipv6_pool is vyos_defined %}
+ipv6-pool={{ default_ipv6_pool }}
+ipv6-pool-delegate={{ default_ipv6_pool }}
+{% endif %}
 {% if gateway_address is vyos_defined %}
 {%     for gw_addr in gateway_address %}
 gw-ip-address={{ gw_addr }}
diff --git a/data/templates/accel-ppp/l2tp.config.j2 b/data/templates/accel-ppp/l2tp.config.j2
index 49755254a..f041e278e 100644
--- a/data/templates/accel-ppp/l2tp.config.j2
+++ b/data/templates/accel-ppp/l2tp.config.j2
@@ -51,6 +51,10 @@ host-name={{ lns.host_name }}
 {% if default_pool is vyos_defined %}
 ip-pool={{ default_pool }}
 {% endif %}
+{% if default_ipv6_pool is vyos_defined %}
+ipv6-pool={{ default_ipv6_pool }}
+ipv6-pool-delegate={{ default_ipv6_pool }}
+{% endif %}
 
 [client-ip-range]
 0.0.0.0/0
diff --git a/data/templates/accel-ppp/pppoe.config.j2 b/data/templates/accel-ppp/pppoe.config.j2
index 4bb1c4450..fb8a11366 100644
--- a/data/templates/accel-ppp/pppoe.config.j2
+++ b/data/templates/accel-ppp/pppoe.config.j2
@@ -143,6 +143,10 @@ noauth=1
 {% if default_pool is vyos_defined %}
 ip-pool={{ default_pool }}
 {% endif %}
+{% if default_ipv6_pool is vyos_defined %}
+ipv6-pool={{ default_ipv6_pool }}
+ipv6-pool-delegate={{ default_ipv6_pool }}
+{% endif %}
 
 {% if limits is vyos_defined %}
 [connlimit]
diff --git a/data/templates/accel-ppp/sstp.config.j2 b/data/templates/accel-ppp/sstp.config.j2
index 014ae1235..51f7dfca8 100644
--- a/data/templates/accel-ppp/sstp.config.j2
+++ b/data/templates/accel-ppp/sstp.config.j2
@@ -39,6 +39,10 @@ ssl-keyfile=/run/accel-pppd/sstp-cert.key
 {% if default_pool is vyos_defined %}
 ip-pool={{ default_pool }}
 {% endif %}
+{% if default_ipv6_pool is vyos_defined %}
+ipv6-pool={{ default_ipv6_pool }}
+ipv6-pool-delegate={{ default_ipv6_pool }}
+{% endif %}
 
 {# Common IP pool definitions #}
 {% include 'accel-ppp/config_ip_pool.j2' %}
diff --git a/interface-definitions/include/accel-ppp/client-ipv6-pool.xml.i b/interface-definitions/include/accel-ppp/client-ipv6-pool.xml.i
index 774741a5e..0c8c2e34c 100644
--- a/interface-definitions/include/accel-ppp/client-ipv6-pool.xml.i
+++ b/interface-definitions/include/accel-ppp/client-ipv6-pool.xml.i
@@ -1,7 +1,14 @@
 <!-- include start from accel-ppp/client-ipv6-pool.xml.i -->
-<node name="client-ipv6-pool">
+<tagNode name="client-ipv6-pool">
   <properties>
     <help>Pool of client IPv6 addresses</help>
+    <valueHelp>
+      <format>txt</format>
+      <description>Name of IPv6 pool</description>
+    </valueHelp>
+    <constraint>
+      #include <include/constraint/alpha-numeric-hyphen-underscore-dot.xml.i>
+    </constraint>
   </properties>
   <children>
     <tagNode name="prefix">
@@ -58,5 +65,5 @@
       </children>
     </tagNode>
   </children>
-</node>
+</tagNode>
 <!-- include end -->
diff --git a/interface-definitions/include/accel-ppp/default-ipv6-pool.xml.i b/interface-definitions/include/accel-ppp/default-ipv6-pool.xml.i
new file mode 100644
index 000000000..1093f6713
--- /dev/null
+++ b/interface-definitions/include/accel-ppp/default-ipv6-pool.xml.i
@@ -0,0 +1,17 @@
+<!-- include start from accel-ppp/default-pool.xml.i -->
+<leafNode name="default-ipv6-pool">
+  <properties>
+    <help>Default client IPv6 pool name</help>
+    <completionHelp>
+      <path>${COMP_WORDS[@]:1:${#COMP_WORDS[@]}-3} client-ipv6-pool</path>
+    </completionHelp>
+    <valueHelp>
+      <format>txt</format>
+      <description>Default IPv6 pool</description>
+    </valueHelp>
+    <constraint>
+      #include <include/constraint/alpha-numeric-hyphen-underscore-dot.xml.i>
+    </constraint>
+  </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/version/ipoe-server-version.xml.i b/interface-definitions/include/version/ipoe-server-version.xml.i
index e5983ab39..659433382 100644
--- a/interface-definitions/include/version/ipoe-server-version.xml.i
+++ b/interface-definitions/include/version/ipoe-server-version.xml.i
@@ -1,3 +1,3 @@
 <!-- include start from include/version/ipoe-server-version.xml.i -->
-<syntaxVersion component='ipoe-server' version='2'></syntaxVersion>
+<syntaxVersion component='ipoe-server' version='3'></syntaxVersion>
 <!-- include end -->
diff --git a/interface-definitions/include/version/l2tp-version.xml.i b/interface-definitions/include/version/l2tp-version.xml.i
index f4507d93b..793cd5d0c 100644
--- a/interface-definitions/include/version/l2tp-version.xml.i
+++ b/interface-definitions/include/version/l2tp-version.xml.i
@@ -1,3 +1,3 @@
 <!-- include start from include/version/l2tp-version.xml.i -->
-<syntaxVersion component='l2tp' version='6'></syntaxVersion>
+<syntaxVersion component='l2tp' version='7'></syntaxVersion>
 <!-- include end -->
diff --git a/interface-definitions/include/version/pppoe-server-version.xml.i b/interface-definitions/include/version/pppoe-server-version.xml.i
index deed702f0..02f98cc16 100644
--- a/interface-definitions/include/version/pppoe-server-version.xml.i
+++ b/interface-definitions/include/version/pppoe-server-version.xml.i
@@ -1,3 +1,3 @@
 <!-- include start from include/version/pppoe-server-version.xml.i -->
-<syntaxVersion component='pppoe-server' version='7'></syntaxVersion>
+<syntaxVersion component='pppoe-server' version='8'></syntaxVersion>
 <!-- include end -->
diff --git a/interface-definitions/include/version/sstp-version.xml.i b/interface-definitions/include/version/sstp-version.xml.i
index 3ac54a3de..5e30950d8 100644
--- a/interface-definitions/include/version/sstp-version.xml.i
+++ b/interface-definitions/include/version/sstp-version.xml.i
@@ -1,3 +1,3 @@
 <!-- include start from include/version/sstp-version.xml.i -->
-<syntaxVersion component='sstp' version='5'></syntaxVersion>
+<syntaxVersion component='sstp' version='6'></syntaxVersion>
 <!-- include end -->
diff --git a/interface-definitions/service_ipoe-server.xml.in b/interface-definitions/service_ipoe-server.xml.in
index edfe6a34c..eeec2aeef 100644
--- a/interface-definitions/service_ipoe-server.xml.in
+++ b/interface-definitions/service_ipoe-server.xml.in
@@ -183,6 +183,7 @@
             </children>
           </node>
           #include <include/accel-ppp/default-pool.xml.i>
+          #include <include/accel-ppp/default-ipv6-pool.xml.i>
         </children>
       </node>
     </children>
diff --git a/interface-definitions/service_pppoe-server.xml.in b/interface-definitions/service_pppoe-server.xml.in
index f1b369936..6fdc2a65a 100644
--- a/interface-definitions/service_pppoe-server.xml.in
+++ b/interface-definitions/service_pppoe-server.xml.in
@@ -274,6 +274,7 @@
             </children>
           </node>
           #include <include/accel-ppp/default-pool.xml.i>
+          #include <include/accel-ppp/default-ipv6-pool.xml.i>
         </children>
       </node>
     </children>
diff --git a/interface-definitions/vpn_l2tp.xml.in b/interface-definitions/vpn_l2tp.xml.in
index 3e2d00e6b..d3fb58433 100644
--- a/interface-definitions/vpn_l2tp.xml.in
+++ b/interface-definitions/vpn_l2tp.xml.in
@@ -154,6 +154,7 @@
                 </children>
               </node>
               #include <include/accel-ppp/default-pool.xml.i>
+              #include <include/accel-ppp/default-ipv6-pool.xml.i>
             </children>
           </node>
         </children>
diff --git a/interface-definitions/vpn_pptp.xml.in b/interface-definitions/vpn_pptp.xml.in
index 7bb8db798..ec622b5d0 100644
--- a/interface-definitions/vpn_pptp.xml.in
+++ b/interface-definitions/vpn_pptp.xml.in
@@ -134,6 +134,7 @@
                 </children>
               </node>
               #include <include/accel-ppp/default-pool.xml.i>
+              #include <include/accel-ppp/default-ipv6-pool.xml.i>
             </children>
           </node>
         </children>
diff --git a/interface-definitions/vpn_sstp.xml.in b/interface-definitions/vpn_sstp.xml.in
index a1b69f990..2727540be 100644
--- a/interface-definitions/vpn_sstp.xml.in
+++ b/interface-definitions/vpn_sstp.xml.in
@@ -36,6 +36,7 @@
             <defaultValue>443</defaultValue>
           </leafNode>
           #include <include/accel-ppp/default-pool.xml.i>
+          #include <include/accel-ppp/default-ipv6-pool.xml.i>
           <node name="ppp-options">
             <properties>
               <help>PPP (Point-to-Point Protocol) settings</help>
diff --git a/python/vyos/accel_ppp_util.py b/python/vyos/accel_ppp_util.py
index 757d447a2..2f029e042 100644
--- a/python/vyos/accel_ppp_util.py
+++ b/python/vyos/accel_ppp_util.py
@@ -1,4 +1,4 @@
-# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -22,9 +22,9 @@
 # makes use of it!
 
 from vyos import ConfigError
+from vyos.base import Warning
 from vyos.utils.dict import dict_search
 
-
 def get_pools_in_order(data: dict) -> list:
     """Return a list of dictionaries representing pool data in the order
     in which they should be allocated. Pool must be defined before we can
@@ -156,38 +156,47 @@ def verify_accel_ppp_base_service(config, local_users=True):
                 "Not more then three IPv6 DNS name-servers " "can be configured"
             )
 
-    if "client_ipv6_pool" in config:
-        ipv6_pool = config["client_ipv6_pool"]
-        if "delegate" in ipv6_pool:
-            if "prefix" not in ipv6_pool:
-                raise ConfigError(
-                    'IPv6 "delegate" also requires "prefix" to be defined!'
-                )
-
-            for delegate in ipv6_pool["delegate"]:
-                if "delegation_prefix" not in ipv6_pool["delegate"][delegate]:
-                    raise ConfigError("delegation-prefix length required!")
 
 
 def verify_accel_ppp_ip_pool(vpn_config):
     """
     Common helper function which must be used by Accel-PPP
     services (pptp, l2tp, sstp, pppoe) to verify client-ip-pool
+    and client-ipv6-pool
     """
     if dict_search("client_ip_pool", vpn_config):
         for pool_name, pool_config in vpn_config["client_ip_pool"].items():
             next_pool = dict_search(f"next_pool", pool_config)
             if next_pool:
                 if next_pool not in vpn_config["client_ip_pool"]:
-                    raise ConfigError(f'Next pool "{next_pool}" does not exist')
+                    raise ConfigError(
+                        f'Next pool "{next_pool}" does not exist')
                 if not dict_search(f"range", pool_config):
                     raise ConfigError(
                         f'Pool "{pool_name}" does not contain range but next-pool exists'
                     )
-
     if not dict_search("gateway_address", vpn_config):
-        raise ConfigError("Server requires gateway-address to be configured!")
+        Warning("IPv4 Server requires gateway-address to be configured!")
+
     default_pool = dict_search("default_pool", vpn_config)
     if default_pool:
         if default_pool not in dict_search("client_ip_pool", vpn_config):
             raise ConfigError(f'Default pool "{default_pool}" does not exists')
+
+    if 'client_ipv6_pool' in vpn_config:
+        for ipv6_pool, ipv6_pool_config in vpn_config['client_ipv6_pool'].items():
+            if 'delegate' in ipv6_pool_config and 'prefix' not in ipv6_pool_config:
+                raise ConfigError(
+                    f'IPoE IPv6 deletate-prefix requires IPv6 prefix to be configured in "{ipv6_pool}"!')
+
+    if dict_search('authentication.mode', vpn_config) in ['local', 'noauth']:
+        if not dict_search('client_ip_pool', vpn_config) and not dict_search(
+                'client_ipv6_pool', vpn_config):
+            raise ConfigError(
+                "L2TP local auth mode requires local client-ip-pool or client-ipv6-pool to be configured!")
+        if dict_search('client_ip_pool', vpn_config) and not dict_search(
+                'default_pool', vpn_config):
+            Warning("'default-pool' is not defined")
+        if dict_search('client_ipv6_pool', vpn_config) and not dict_search(
+                'default_ipv6_pool', vpn_config):
+            Warning("'default-ipv6-pool' is not defined")
diff --git a/smoketest/scripts/cli/base_accel_ppp_test.py b/smoketest/scripts/cli/base_accel_ppp_test.py
index 1ea5db898..6219a0a4c 100644
--- a/smoketest/scripts/cli/base_accel_ppp_test.py
+++ b/smoketest/scripts/cli/base_accel_ppp_test.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2020-2023 VyOS maintainers and contributors
+# Copyright (C) 2020-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
@@ -441,3 +441,54 @@ class BasicAccelPPPTest:
 {second_subnet},name={second_pool},next={third_pool}
 {first_subnet},name={first_pool},next={second_pool}"""
             self.assertIn(pool_config, config)
+
+        def test_accel_ipv6_pool(self):
+            # Test configuration of IPv6 client pools
+            self.basic_config(is_gateway=False, is_client_pool=False)
+
+            # Enable IPv6
+            allow_ipv6 = 'allow'
+            self.set(['ppp-options', 'ipv6', allow_ipv6])
+
+            pool_name = 'ipv6_test_pool'
+            prefix_1 = '2001:db8:fffe::/56'
+            prefix_mask = '64'
+            prefix_2 = '2001:db8:ffff::/56'
+            client_prefix_1 = f'{prefix_1},{prefix_mask}'
+            client_prefix_2 = f'{prefix_2},{prefix_mask}'
+            self.set(
+                ['client-ipv6-pool', pool_name, 'prefix', prefix_1, 'mask',
+                 prefix_mask])
+            self.set(
+                ['client-ipv6-pool', pool_name, 'prefix', prefix_2, 'mask',
+                 prefix_mask])
+
+            delegate_1_prefix = '2001:db8:fff1::/56'
+            delegate_2_prefix = '2001:db8:fff2::/56'
+            delegate_mask = '64'
+            self.set(
+                ['client-ipv6-pool', pool_name, 'delegate', delegate_1_prefix,
+                 'delegation-prefix', delegate_mask])
+            self.set(
+                ['client-ipv6-pool', pool_name, 'delegate', delegate_2_prefix,
+                 'delegation-prefix', delegate_mask])
+
+            # commit changes
+            self.cli_commit()
+
+            # Validate configuration values
+            conf = ConfigParser(allow_no_value=True, delimiters='=',
+                                strict=False)
+            conf.read(self._config_file)
+
+            for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
+                self.assertEqual(conf['modules'][tmp], None)
+
+            self.assertEqual(conf['ppp']['ipv6'], allow_ipv6)
+
+            config = self.getConfig("ipv6-pool")
+            pool_config = f"""{client_prefix_1},name={pool_name}
+{client_prefix_2},name={pool_name}
+delegate={delegate_1_prefix},{delegate_mask},name={pool_name}
+delegate={delegate_2_prefix},{delegate_mask},name={pool_name}"""
+            self.assertIn(pool_config, config)
diff --git a/smoketest/scripts/cli/test_service_ipoe-server.py b/smoketest/scripts/cli/test_service_ipoe-server.py
index 6e95b3bd1..cec6adb09 100755
--- a/smoketest/scripts/cli/test_service_ipoe-server.py
+++ b/smoketest/scripts/cli/test_service_ipoe-server.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2022-2023 VyOS maintainers and contributors
+# Copyright (C) 2022-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
@@ -188,6 +188,45 @@ gw-ip-address={third_gateway.split('/')[0]}
 {first_subnet},name={first_pool},next={second_pool}"""
         self.assertIn(pool_config, config)
 
+    def test_accel_ipv6_pool(self):
+        # Test configuration of IPv6 client pools
+        self.basic_config(is_gateway=False, is_client_pool=False)
+
+        pool_name = 'ipv6_test_pool'
+        prefix_1 = '2001:db8:fffe::/56'
+        prefix_mask = '64'
+        prefix_2 = '2001:db8:ffff::/56'
+        client_prefix_1 = f'{prefix_1},{prefix_mask}'
+        client_prefix_2 = f'{prefix_2},{prefix_mask}'
+        self.set(['client-ipv6-pool', pool_name, 'prefix', prefix_1, 'mask',
+                  prefix_mask])
+        self.set(['client-ipv6-pool', pool_name, 'prefix', prefix_2, 'mask',
+                  prefix_mask])
+
+        delegate_1_prefix = '2001:db8:fff1::/56'
+        delegate_2_prefix = '2001:db8:fff2::/56'
+        delegate_mask = '64'
+        self.set(['client-ipv6-pool', pool_name, 'delegate', delegate_1_prefix,
+                  'delegation-prefix', delegate_mask])
+        self.set(['client-ipv6-pool', pool_name, 'delegate', delegate_2_prefix,
+                  'delegation-prefix', delegate_mask])
+
+        # commit changes
+        self.cli_commit()
+
+        # Validate configuration values
+        conf = ConfigParser(allow_no_value=True, delimiters='=', strict=False)
+        conf.read(self._config_file)
+
+        for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
+            self.assertEqual(conf['modules'][tmp], None)
+
+        config = self.getConfig("ipv6-pool")
+        pool_config = f"""{client_prefix_1},name={pool_name}
+{client_prefix_2},name={pool_name}
+delegate={delegate_1_prefix},{delegate_mask},name={pool_name}
+delegate={delegate_2_prefix},{delegate_mask},name={pool_name}"""
+        self.assertIn(pool_config, config)
 
 if __name__ == "__main__":
     unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_pppoe-server.py b/smoketest/scripts/cli/test_service_pppoe-server.py
index fa3bb87db..11d5b8b78 100755
--- a/smoketest/scripts/cli/test_service_pppoe-server.py
+++ b/smoketest/scripts/cli/test_service_pppoe-server.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2022-2023 VyOS maintainers and contributors
+# Copyright (C) 2022-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
@@ -93,6 +93,13 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
         interface_cache = '128000'
         self.set(['ppp-options', 'interface-cache', interface_cache])
 
+        # ipv6
+        allow_ipv6 = 'allow'
+        random = 'random'
+        self.set(['ppp-options', 'ipv6', allow_ipv6])
+        self.set(['ppp-options', 'ipv6-intf-id', random])
+        self.set(['ppp-options', 'ipv6-accept-peer-intf-id'])
+        self.set(['ppp-options', 'ipv6-peer-intf-id', random])
         # commit changes
         self.cli_commit()
 
@@ -118,6 +125,15 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
         # check interface-cache
         self.assertEqual(conf['ppp']['unit-cache'], interface_cache)
 
+        #check ipv6
+        for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
+            self.assertEqual(conf['modules'][tmp], None)
+
+        self.assertEqual(conf['ppp']['ipv6'], allow_ipv6)
+        self.assertEqual(conf['ppp']['ipv6-intf-id'], random)
+        self.assertEqual(conf['ppp']['ipv6-peer-intf-id'], random)
+        self.assertTrue(conf['ppp'].getboolean('ipv6-accept-peer-intf-id'))
+
     def test_pppoe_server_authentication_protocols(self):
         # Test configuration of local authentication for PPPoE server
         self.basic_config()
@@ -154,45 +170,6 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
         self.assertEqual(conf['shaper']['fwmark'], fwmark)
         self.assertEqual(conf['shaper']['down-limiter'], limiter)
 
-    def test_pppoe_server_client_ipv6_pool(self):
-        # Test configuration of IPv6 client pools
-        self.basic_config()
-
-        # Enable IPv6
-        allow_ipv6 = 'allow'
-        random = 'random'
-        self.set(['ppp-options', 'ipv6', allow_ipv6])
-        self.set(['ppp-options', 'ipv6-intf-id', random])
-        self.set(['ppp-options', 'ipv6-accept-peer-intf-id'])
-        self.set(['ppp-options', 'ipv6-peer-intf-id', random])
-
-        prefix = '2001:db8:ffff::/64'
-        prefix_mask = '128'
-        client_prefix = f'{prefix},{prefix_mask}'
-        self.set(['client-ipv6-pool', 'prefix', prefix, 'mask', prefix_mask])
-
-        delegate_prefix = '2001:db8::/40'
-        delegate_mask = '56'
-        self.set(['client-ipv6-pool', 'delegate', delegate_prefix, 'delegation-prefix', delegate_mask])
-
-        # commit changes
-        self.cli_commit()
-
-        # Validate configuration values
-        conf = ConfigParser(allow_no_value=True, delimiters='=')
-        conf.read(self._config_file)
-
-        for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
-            self.assertEqual(conf['modules'][tmp], None)
-
-        self.assertEqual(conf['ppp']['ipv6'], allow_ipv6)
-        self.assertEqual(conf['ppp']['ipv6-intf-id'], random)
-        self.assertEqual(conf['ppp']['ipv6-peer-intf-id'], random)
-        self.assertTrue(conf['ppp'].getboolean('ipv6-accept-peer-intf-id'))
-
-        self.assertEqual(conf['ipv6-pool'][client_prefix], None)
-        self.assertEqual(conf['ipv6-pool']['delegate'], f'{delegate_prefix},{delegate_mask}')
-
     def test_accel_radius_authentication(self):
         radius_called_sid = 'ifname:mac'
 
diff --git a/smoketest/scripts/cli/test_vpn_l2tp.py b/smoketest/scripts/cli/test_vpn_l2tp.py
index 5b3e419bd..129a9c602 100755
--- a/smoketest/scripts/cli/test_vpn_l2tp.py
+++ b/smoketest/scripts/cli/test_vpn_l2tp.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-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
@@ -55,6 +55,13 @@ class TestVPNL2TPServer(BasicAccelPPPTest.TestCase):
         self.set(['ppp-options', 'lcp-echo-interval', lcp_echo_interval])
         self.set(['ppp-options', 'lcp-echo-timeout', lcp_echo_timeout])
 
+        allow_ipv6 = 'allow'
+        random = 'random'
+        self.set(['ppp-options', 'ipv6', allow_ipv6])
+        self.set(['ppp-options', 'ipv6-intf-id', random])
+        self.set(['ppp-options', 'ipv6-accept-peer-intf-id'])
+        self.set(['ppp-options', 'ipv6-peer-intf-id', random])
+
         # commit changes
         self.cli_commit()
 
@@ -76,6 +83,13 @@ class TestVPNL2TPServer(BasicAccelPPPTest.TestCase):
         self.assertEqual(conf['ppp']['lcp-echo-timeout'], lcp_echo_timeout)
         self.assertEqual(conf['ppp']['lcp-echo-failure'], lcp_echo_failure)
 
+        for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
+            self.assertEqual(conf['modules'][tmp], None)
+        self.assertEqual(conf['ppp']['ipv6'], allow_ipv6)
+        self.assertEqual(conf['ppp']['ipv6-intf-id'], random)
+        self.assertEqual(conf['ppp']['ipv6-peer-intf-id'], random)
+        self.assertTrue(conf['ppp'].getboolean('ipv6-accept-peer-intf-id'))
+
     def test_l2tp_server_authentication_protocols(self):
         # Test configuration of local authentication for PPPoE server
         self.basic_config()
@@ -92,44 +106,6 @@ class TestVPNL2TPServer(BasicAccelPPPTest.TestCase):
 
         self.assertEqual(conf['modules']['auth_mschap_v2'], None)
 
-    def test_l2tp_server_client_ipv6_pool(self):
-        # Test configuration of IPv6 client pools
-        self.basic_config()
-
-        # Enable IPv6
-        allow_ipv6 = 'allow'
-        random = 'random'
-        self.set(['ppp-options', 'ipv6', allow_ipv6])
-        self.set(['ppp-options', 'ipv6-intf-id', random])
-        self.set(['ppp-options', 'ipv6-accept-peer-intf-id'])
-        self.set(['ppp-options', 'ipv6-peer-intf-id', random])
-
-        prefix = '2001:db8:ffff::/64'
-        prefix_mask = '128'
-        client_prefix = f'{prefix},{prefix_mask}'
-        self.set(['client-ipv6-pool', 'prefix', prefix, 'mask', prefix_mask])
-
-        delegate_prefix = '2001:db8::/40'
-        delegate_mask = '56'
-        self.set(['client-ipv6-pool', 'delegate', delegate_prefix, 'delegation-prefix', delegate_mask])
-
-        # commit changes
-        self.cli_commit()
-
-        # Validate configuration values
-        conf = ConfigParser(allow_no_value=True, delimiters='=')
-        conf.read(self._config_file)
-
-        for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
-            self.assertEqual(conf['modules'][tmp], None)
-
-        self.assertEqual(conf['ppp']['ipv6'], allow_ipv6)
-        self.assertEqual(conf['ppp']['ipv6-intf-id'], random)
-        self.assertEqual(conf['ppp']['ipv6-peer-intf-id'], random)
-        self.assertTrue(conf['ppp'].getboolean('ipv6-accept-peer-intf-id'))
-
-        self.assertEqual(conf['ipv6-pool'][client_prefix], None)
-        self.assertEqual(conf['ipv6-pool']['delegate'], f'{delegate_prefix},{delegate_mask}')
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_vpn_pptp.py b/smoketest/scripts/cli/test_vpn_pptp.py
index 0d9ea312e..f3fce822b 100755
--- a/smoketest/scripts/cli/test_vpn_pptp.py
+++ b/smoketest/scripts/cli/test_vpn_pptp.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-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
@@ -218,6 +218,10 @@ class TestVPNPPTPServer(BasicAccelPPPTest.TestCase):
         self.assertEqual(f"req-limit=0", server[4])
         self.assertEqual(f"fail-time=0", server[5])
 
+    @unittest.skip("IPv6 is not implemented in PPTP")
+    def test_accel_ipv6_pool(self):
+        pass
+
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/src/conf_mode/service_ipoe-server.py b/src/conf_mode/service_ipoe-server.py
index 36f00dec5..6df6f3dc7 100755
--- a/src/conf_mode/service_ipoe-server.py
+++ b/src/conf_mode/service_ipoe-server.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2018-2023 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
@@ -79,9 +79,6 @@ def verify(ipoe):
             if 'key' not in radius_config:
                 raise ConfigError(f'Missing RADIUS secret key for server "{server}"')
 
-    if 'client_ipv6_pool' in ipoe:
-        if 'delegate' in ipoe['client_ipv6_pool'] and 'prefix' not in ipoe['client_ipv6_pool']:
-            raise ConfigError('IPoE IPv6 deletate-prefix requires IPv6 prefix to be configured!')
 
     return None
 
diff --git a/src/conf_mode/service_pppoe-server.py b/src/conf_mode/service_pppoe-server.py
index 7c624f034..31299a15c 100755
--- a/src/conf_mode/service_pppoe-server.py
+++ b/src/conf_mode/service_pppoe-server.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2018-2023 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
@@ -85,6 +85,7 @@ def verify(pppoe):
         if not dict_search('authentication.radius.dynamic_author.key', pppoe):
             raise ConfigError('DA/CoE server key required!')
 
+
     return None
 
 
diff --git a/src/conf_mode/vpn_l2tp.py b/src/conf_mode/vpn_l2tp.py
index 1a91951b4..b569ca140 100755
--- a/src/conf_mode/vpn_l2tp.py
+++ b/src/conf_mode/vpn_l2tp.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
+# Copyright (C) 2019-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
@@ -70,15 +70,9 @@ def verify(l2tp):
         if not dict_search('authentication.radius.dynamic_author.key', l2tp):
             raise ConfigError('DA/CoE server key required!')
 
-    if dict_search('authentication.mode', l2tp) in ['local', 'noauth']:
-        if not dict_search('client_ip_pool', l2tp) and not dict_search('client_ipv6_pool', l2tp):
-            raise ConfigError(
-                "L2TP local auth mode requires local client-ip-pool or client-ipv6-pool to be configured!")
-        if dict_search('client_ip_pool', l2tp) and not dict_search('default_pool', l2tp):
-            Warning("'default-pool' is not defined")
-
     verify_accel_ppp_ip_pool(l2tp)
 
+
     if 'wins_server' in l2tp and len(l2tp['wins_server']) > 2:
         raise ConfigError(
             'Not more then two WINS name-servers can be configured')
diff --git a/src/conf_mode/vpn_pptp.py b/src/conf_mode/vpn_pptp.py
index f769be39f..0629625bf 100755
--- a/src/conf_mode/vpn_pptp.py
+++ b/src/conf_mode/vpn_pptp.py
@@ -80,12 +80,6 @@ def verify(pptp):
                 raise ConfigError(
                     f'Missing RADIUS secret key for server "{server}"')
 
-    if auth_mode == 'local' or auth_mode == 'noauth':
-        if not dict_search('client_ip_pool', pptp):
-            raise ConfigError(
-                'PPTP local auth mode requires local client-ip-pool '
-                'to be configured!')
-
     verify_accel_ppp_ip_pool(pptp)
 
     if 'name_server' in pptp:
diff --git a/src/conf_mode/vpn_sstp.py b/src/conf_mode/vpn_sstp.py
index 6bf9307e1..a84513a0f 100755
--- a/src/conf_mode/vpn_sstp.py
+++ b/src/conf_mode/vpn_sstp.py
@@ -74,11 +74,8 @@ def verify(sstp):
         raise ConfigError(f'"{proto}" port "{port}" is used by another service')
 
     verify_accel_ppp_base_service(sstp)
-
-    if 'client_ip_pool' not in sstp and 'client_ipv6_pool' not in sstp:
-        raise ConfigError('Client IP subnet required')
-
     verify_accel_ppp_ip_pool(sstp)
+
     #
     # SSL certificate checks
     #
diff --git a/src/migration-scripts/ipoe-server/2-to-3 b/src/migration-scripts/ipoe-server/2-to-3
new file mode 100755
index 000000000..d4ae0a7ba
--- /dev/null
+++ b/src/migration-scripts/ipoe-server/2-to-3
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 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
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Migrating to named ipv6 pools
+
+import os
+
+from sys import argv
+from sys import exit
+from vyos.configtree import ConfigTree
+
+
+if len(argv) < 2:
+    print("Must specify file name!")
+    exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+    config_file = f.read()
+
+config = ConfigTree(config_file)
+base = ['service', 'ipoe-server']
+pool_base = base + ['client-ipv6-pool']
+if not config.exists(base):
+    exit(0)
+
+if not config.exists(pool_base):
+    exit(0)
+
+ipv6_pool_name = 'ipv6-pool'
+config.copy(pool_base, pool_base + [ipv6_pool_name])
+
+if config.exists(pool_base + ['prefix']):
+    config.delete(pool_base + ['prefix'])
+    config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
+if config.exists(pool_base + ['delegate']):
+    config.delete(pool_base + ['delegate'])
+
+# format as tag node
+config.set_tag(pool_base)
+
+try:
+    with open(file_name, 'w') as f:
+        f.write(config.to_string())
+except OSError as e:
+    print("Failed to save the modified config: {}".format(e))
+    exit(1)
diff --git a/src/migration-scripts/l2tp/6-to-7 b/src/migration-scripts/l2tp/6-to-7
new file mode 100755
index 000000000..f49c4ab08
--- /dev/null
+++ b/src/migration-scripts/l2tp/6-to-7
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 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
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Migrating to named ipv6 pools
+
+import os
+
+from sys import argv
+from sys import exit
+from vyos.configtree import ConfigTree
+
+
+if len(argv) < 2:
+    print("Must specify file name!")
+    exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+    config_file = f.read()
+
+config = ConfigTree(config_file)
+base = ['vpn', 'l2tp', 'remote-access']
+pool_base = base + ['client-ipv6-pool']
+if not config.exists(base):
+    exit(0)
+
+if not config.exists(pool_base):
+    exit(0)
+
+ipv6_pool_name = 'ipv6-pool'
+config.copy(pool_base, pool_base + [ipv6_pool_name])
+
+if config.exists(pool_base + ['prefix']):
+    config.delete(pool_base + ['prefix'])
+    config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
+if config.exists(pool_base + ['delegate']):
+    config.delete(pool_base + ['delegate'])
+# format as tag node
+config.set_tag(pool_base)
+
+try:
+    with open(file_name, 'w') as f:
+        f.write(config.to_string())
+except OSError as e:
+    print("Failed to save the modified config: {}".format(e))
+    exit(1)
diff --git a/src/migration-scripts/pppoe-server/7-to-8 b/src/migration-scripts/pppoe-server/7-to-8
new file mode 100755
index 000000000..b0d9bb464
--- /dev/null
+++ b/src/migration-scripts/pppoe-server/7-to-8
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 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
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Migrating to named ipv6 pools
+
+import os
+
+from sys import argv
+from sys import exit
+from vyos.configtree import ConfigTree
+
+
+if len(argv) < 2:
+    print("Must specify file name!")
+    exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+    config_file = f.read()
+
+config = ConfigTree(config_file)
+base = ['service', 'pppoe-server']
+pool_base = base + ['client-ipv6-pool']
+if not config.exists(base):
+    exit(0)
+
+if not config.exists(pool_base):
+    exit(0)
+
+ipv6_pool_name = 'ipv6-pool'
+config.copy(pool_base, pool_base + [ipv6_pool_name])
+
+if config.exists(pool_base + ['prefix']):
+    config.delete(pool_base + ['prefix'])
+    config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
+if config.exists(pool_base + ['delegate']):
+    config.delete(pool_base + ['delegate'])
+
+# format as tag node
+config.set_tag(pool_base)
+
+try:
+    with open(file_name, 'w') as f:
+        f.write(config.to_string())
+except OSError as e:
+    print("Failed to save the modified config: {}".format(e))
+    exit(1)
diff --git a/src/migration-scripts/sstp/5-to-6 b/src/migration-scripts/sstp/5-to-6
new file mode 100755
index 000000000..bac9975b2
--- /dev/null
+++ b/src/migration-scripts/sstp/5-to-6
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 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
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Migrating to named ipv6 pools
+
+import os
+import pprint
+
+from sys import argv
+from sys import exit
+from vyos.configtree import ConfigTree
+
+
+if len(argv) < 2:
+    print("Must specify file name!")
+    exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+    config_file = f.read()
+
+config = ConfigTree(config_file)
+base = ['vpn', 'sstp']
+pool_base = base + ['client-ipv6-pool']
+if not config.exists(base):
+    exit(0)
+
+if not config.exists(pool_base):
+    exit(0)
+
+ipv6_pool_name = 'ipv6-pool'
+config.copy(pool_base, pool_base + [ipv6_pool_name])
+
+if config.exists(pool_base + ['prefix']):
+    config.delete(pool_base + ['prefix'])
+    config.set(base + ['default-ipv6-pool'], value=ipv6_pool_name)
+if config.exists(pool_base + ['delegate']):
+    config.delete(pool_base + ['delegate'])
+
+# format as tag node
+config.set_tag(pool_base)
+
+try:
+    with open(file_name, 'w') as f:
+        f.write(config.to_string())
+except OSError as e:
+    print("Failed to save the modified config: {}".format(e))
+    exit(1)
-- 
cgit v1.2.3