summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2023-02-13 17:38:16 +0100
committerGitHub <noreply@github.com>2023-02-13 17:38:16 +0100
commit5e56daaff4ec53a387abbd3ad879e916a2bfa373 (patch)
tree3a9a3d1823e01287c52a38cc67c0b7061bc901ce
parent9c481b00cae8ed1d121c809fb5edc24a937525e9 (diff)
parente7e81746e6ad01ce644cd7b584233464f91d9380 (diff)
downloadvyos-1x-5e56daaff4ec53a387abbd3ad879e916a2bfa373.tar.gz
vyos-1x-5e56daaff4ec53a387abbd3ad879e916a2bfa373.zip
Merge pull request #1813 from sever-sever/T4971-eq
T4971: PPPoE server add named ip pool and attr Framed-Pool
-rw-r--r--data/templates/accel-ppp/config_ip_pool.j210
-rw-r--r--data/templates/accel-ppp/pppoe.config.tmpl15
-rw-r--r--interface-definitions/include/accel-ppp/client-ip-pool-name.xml.i18
-rw-r--r--interface-definitions/service_ipoe-server.xml.in14
-rw-r--r--interface-definitions/service_pppoe-server.xml.in1
-rw-r--r--python/vyos/configverify.py16
-rw-r--r--python/vyos/util.py22
-rwxr-xr-xsmoketest/scripts/cli/test_service_pppoe-server.py29
-rw-r--r--src/tests/test_dict_search.py25
9 files changed, 131 insertions, 19 deletions
diff --git a/data/templates/accel-ppp/config_ip_pool.j2 b/data/templates/accel-ppp/config_ip_pool.j2
index 3b0f68084..f61a4f148 100644
--- a/data/templates/accel-ppp/config_ip_pool.j2
+++ b/data/templates/accel-ppp/config_ip_pool.j2
@@ -11,4 +11,14 @@ gw-ip-address={{ gateway_address }}
{{ subnet }}
{% endfor %}
{% endif %}
+{% if client_ip_pool.name is defined and client_ip_pool.name is not none %}
+{% for pool, pool_config in client_ip_pool.name.items() %}
+{% if pool_config.subnet is defined and pool_config.subnet is not none %}
+{{ pool_config.subnet }},name={{ pool }}
+{% endif %}
+{% if pool_config.gateway_address is defined and pool_config.gateway_address is not none %}
+gw-ip-address={{ pool_config.gateway_address }}
+{% endif %}
+{% endfor %}
+{% endif %}
{% endif %}
diff --git a/data/templates/accel-ppp/pppoe.config.tmpl b/data/templates/accel-ppp/pppoe.config.tmpl
index 46f462166..b37004f5b 100644
--- a/data/templates/accel-ppp/pppoe.config.tmpl
+++ b/data/templates/accel-ppp/pppoe.config.tmpl
@@ -136,6 +136,21 @@ pado-delay={{ pado_delay_param.value }}
called-sid={{ authentication.radius.called_sid_format }}
{% endif %}
+{% if authentication is defined and authentication.mode is defined and authentication.mode == 'local' %}
+{% if client_ip_pool is defined and client_ip_pool is not none %}
+{% if client_ip_pool.name is defined and client_ip_pool.name is not none %}
+{% for pool, pool_config in client_ip_pool.name.items() %}
+{% if pool_config.subnet is defined and pool_config.subnet is not none %}
+ip-pool={{ pool }}
+{% if pool_config.gateway_address is defined and pool_config.gateway_address is not none %}
+gw-ip-address={{ pool_config.gateway_address }}/{{ pool_config.subnet.split('/')[1] }}
+{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% endif %}
+{% endif %}
+
{% if limits is defined %}
[connlimit]
{% if limits.connection_limit is defined and limits.connection_limit is not none %}
diff --git a/interface-definitions/include/accel-ppp/client-ip-pool-name.xml.i b/interface-definitions/include/accel-ppp/client-ip-pool-name.xml.i
new file mode 100644
index 000000000..654b6727e
--- /dev/null
+++ b/interface-definitions/include/accel-ppp/client-ip-pool-name.xml.i
@@ -0,0 +1,18 @@
+<!-- include start from accel-ppp/client-ip-pool-name.xml.i -->
+<tagNode name="name">
+ <properties>
+ <help>Pool name</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>Name of IP pool</description>
+ </valueHelp>
+ <constraint>
+ <regex>[-_a-zA-Z0-9.]+</regex>
+ </constraint>
+ </properties>
+ <children>
+ #include <include/accel-ppp/gateway-address.xml.i>
+ #include <include/accel-ppp/client-ip-pool-subnet-single.xml.i>
+ </children>
+</tagNode>
+<!-- include end -->
diff --git a/interface-definitions/service_ipoe-server.xml.in b/interface-definitions/service_ipoe-server.xml.in
index b9279793c..d81ec99f9 100644
--- a/interface-definitions/service_ipoe-server.xml.in
+++ b/interface-definitions/service_ipoe-server.xml.in
@@ -117,19 +117,7 @@
<help>Client IP pools and gateway setting</help>
</properties>
<children>
- <tagNode name="name">
- <properties>
- <help>Pool name</help>
- <constraint>
- <regex>[-_a-zA-Z0-9]+</regex>
- </constraint>
- <constraintErrorMessage>Client IP pool is limited to alphanumerical characters and can contain hyphen and underscores</constraintErrorMessage>
- </properties>
- <children>
- #include <include/accel-ppp/gateway-address.xml.i>
- #include <include/accel-ppp/client-ip-pool-subnet-single.xml.i>
- </children>
- </tagNode>
+ #include <include/accel-ppp/client-ip-pool-name.xml.i>
</children>
</node>
#include <include/accel-ppp/client-ipv6-pool.xml.i>
diff --git a/interface-definitions/service_pppoe-server.xml.in b/interface-definitions/service_pppoe-server.xml.in
index 25ab6f9a0..65868226b 100644
--- a/interface-definitions/service_pppoe-server.xml.in
+++ b/interface-definitions/service_pppoe-server.xml.in
@@ -56,6 +56,7 @@
<children>
#include <include/accel-ppp/client-ip-pool-start-stop.xml.i>
#include <include/accel-ppp/client-ip-pool-subnet.xml.i>
+ #include <include/accel-ppp/client-ip-pool-name.xml.i>
</children>
</node>
#include <include/accel-ppp/client-ipv6-pool.xml.i>
diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py
index a35ea0b74..47cf218ee 100644
--- a/python/vyos/configverify.py
+++ b/python/vyos/configverify.py
@@ -1,4 +1,4 @@
-# Copyright 2020-2021 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2020-2023 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
@@ -23,6 +23,7 @@
from vyos import ConfigError
from vyos.util import dict_search
+from vyos.util import dict_search_recursive
def verify_mtu(config):
"""
@@ -355,7 +356,17 @@ def verify_accel_ppp_base_service(config):
if 'key' not in radius_config:
raise ConfigError(f'Missing RADIUS secret key for server "{server}"')
- if 'gateway_address' not in config:
+ # Check global gateway or gateway in named pool
+ gateway = False
+ if 'gateway_address' in config:
+ gateway = True
+ else:
+ if dict_search_recursive(config, 'gateway_address', ['client_ip_pool', 'name']):
+ for _, v in config['client_ip_pool']['name'].items():
+ if 'gateway_address' in v:
+ gateway = True
+ break
+ if not gateway:
raise ConfigError('Server requires gateway-address to be configured!')
if 'name_server_ipv4' in config:
@@ -427,4 +438,3 @@ def verify_common_route_maps(config):
for protocol, protocol_config in config['redistribute'].items():
if 'route_map' in protocol_config:
verify_route_map(protocol_config['route_map'], config)
-
diff --git a/python/vyos/util.py b/python/vyos/util.py
index 5c6409341..32a5ae116 100644
--- a/python/vyos/util.py
+++ b/python/vyos/util.py
@@ -1,4 +1,4 @@
-# Copyright 2020-2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2020-2023 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
@@ -720,6 +720,26 @@ def dict_search(path, dict_object):
c = c.get(p, {})
return c.get(parts[-1], None)
+def dict_search_recursive(dict_object, key, path=[]):
+ """ Traverse a dictionary recurisvely and return the value of the key
+ we are looking for.
+ Thankfully copied from https://stackoverflow.com/a/19871956
+ Modified to yield optional path to found keys
+ """
+ if isinstance(dict_object, list):
+ for i in dict_object:
+ new_path = path + [i]
+ for x in dict_search_recursive(i, key, new_path):
+ yield x
+ elif isinstance(dict_object, dict):
+ if key in dict_object:
+ new_path = path + [key]
+ yield dict_object[key], new_path
+ for k, j in dict_object.items():
+ new_path = path + [k]
+ for x in dict_search_recursive(j, key, new_path):
+ yield x
+
def convert_data(data):
"""Convert multiple types of data to types usable in CLI
diff --git a/smoketest/scripts/cli/test_service_pppoe-server.py b/smoketest/scripts/cli/test_service_pppoe-server.py
index e5acff265..8514801a8 100755
--- a/smoketest/scripts/cli/test_service_pppoe-server.py
+++ b/smoketest/scripts/cli/test_service_pppoe-server.py
@@ -175,6 +175,35 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
self.assertTrue(process_named_running(self._process_name))
+ def test_pppoe_server_client_ip_pool_name(self):
+ # Test configuration of named client pools
+ self.basic_config()
+
+ subnet = '192.0.2.0/24'
+ gateway = '192.0.2.1'
+ pool = 'VYOS'
+
+ subnet_name = f'{subnet},name'
+ gw_ip_prefix = f'{gateway}/24'
+
+ self.set(['client-ip-pool', 'name', pool, 'subnet', subnet])
+ self.set(['client-ip-pool', 'name', pool, 'gateway-address', gateway])
+ self.cli_delete(self._base_path + ['gateway-address'])
+
+ # commit changes
+ self.cli_commit()
+
+ # Validate configuration values
+ conf = ConfigParser(allow_no_value=True, delimiters='=')
+ conf.read(self._config_file)
+
+ # Validate configuration
+ self.assertEqual(conf['ip-pool'][subnet_name], pool)
+ self.assertEqual(conf['ip-pool']['gw-ip-address'], gateway)
+ self.assertEqual(conf['pppoe']['ip-pool'], pool)
+ self.assertEqual(conf['pppoe']['gw-ip-address'], gw_ip_prefix)
+
+
def test_pppoe_server_client_ipv6_pool(self):
# Test configuration of IPv6 client pools
self.basic_config()
diff --git a/src/tests/test_dict_search.py b/src/tests/test_dict_search.py
index 6a0fc74ad..deee9a657 100644
--- a/src/tests/test_dict_search.py
+++ b/src/tests/test_dict_search.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-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
@@ -16,14 +16,28 @@
from unittest import TestCase
from vyos.util import dict_search
+from vyos.util import dict_search_recursive
data = {
'string': 'fooo',
'nested': {'string': 'bar', 'empty': '', 'list': ['foo', 'bar']},
+ 'non': {},
'list': ['bar', 'baz'],
- 'dict': {'key_1': {}, 'key_2': 'vyos'}
+ 'dict': {'key_1': {}, 'key_2': 'vyos'},
+ 'interfaces': {'dummy': {'dum0': {'address': ['192.0.2.17/29']}},
+ 'ethernet': {'eth0': {'address': ['2001:db8::1/64', '192.0.2.1/29'],
+ 'description': 'Test123',
+ 'duplex': 'auto',
+ 'hw_id': '00:00:00:00:00:01',
+ 'speed': 'auto'},
+ 'eth1': {'address': ['192.0.2.9/29'],
+ 'description': 'Test456',
+ 'duplex': 'auto',
+ 'hw_id': '00:00:00:00:00:02',
+ 'speed': 'auto'}}}
}
+
class TestDictSearch(TestCase):
def setUp(self):
pass
@@ -55,3 +69,10 @@ class TestDictSearch(TestCase):
def test_nested_list(self):
# TestDictSearch: Return list items when querying nested list
self.assertEqual(dict_search('nested.list', data), data['nested']['list'])
+
+ def test_dict_search_recursive(self):
+ # Test nested search in dictionary
+ tmp = list(dict_search_recursive(data, 'hw_id'))
+ self.assertEqual(len(tmp), 2)
+ tmp = list(dict_search_recursive(data, 'address'))
+ self.assertEqual(len(tmp), 3)