summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/chrony/chrony.conf.j210
-rw-r--r--interface-definitions/service_dhcpv6-server.xml.in2
-rw-r--r--interface-definitions/service_ntp.xml.in36
-rw-r--r--[-rwxr-xr-x]op-mode-definitions/generate-system-login-user.xml.in0
-rw-r--r--python/vyos/qos/base.py50
-rw-r--r--python/vyos/utils/network.py2
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcp-server.py13
-rwxr-xr-xsmoketest/scripts/cli/test_service_ntp.py33
-rwxr-xr-xsrc/conf_mode/service_dhcp-server.py21
-rwxr-xr-xsrc/conf_mode/service_ntp.py4
10 files changed, 134 insertions, 37 deletions
diff --git a/data/templates/chrony/chrony.conf.j2 b/data/templates/chrony/chrony.conf.j2
index d02fbf71d..e3f078fdc 100644
--- a/data/templates/chrony/chrony.conf.j2
+++ b/data/templates/chrony/chrony.conf.j2
@@ -21,7 +21,17 @@ ntsdumpdir /run/chrony
pidfile {{ config_file | replace('.conf', '.pid') }}
# Determine when will the next leap second occur and what is the current offset
+{% if leap_second is vyos_defined('timezone') %}
leapsectz right/UTC
+{% elif leap_second is vyos_defined('ignore') %}
+leapsecmode ignore
+{% elif leap_second is vyos_defined('smear') %}
+leapsecmode slew
+maxslewrate 1000
+smoothtime 400 0.001024 leaponly
+{% elif leap_second is vyos_defined('system') %}
+leapsecmode system
+{% endif %}
user {{ user }}
diff --git a/interface-definitions/service_dhcpv6-server.xml.in b/interface-definitions/service_dhcpv6-server.xml.in
index b838f42e0..a64da83ae 100644
--- a/interface-definitions/service_dhcpv6-server.xml.in
+++ b/interface-definitions/service_dhcpv6-server.xml.in
@@ -11,7 +11,7 @@
#include <include/generic-disable-node.xml.i>
<node name="global-parameters">
<properties>
- <help>Additional global parameters for DHCPv6 server</help>
+ <help>Global options sent to all clients</help>
</properties>
<children>
#include <include/name-server-ipv6.xml.i>
diff --git a/interface-definitions/service_ntp.xml.in b/interface-definitions/service_ntp.xml.in
index 65a45d7a1..c057b62b5 100644
--- a/interface-definitions/service_ntp.xml.in
+++ b/interface-definitions/service_ntp.xml.in
@@ -9,6 +9,38 @@
<priority>900</priority>
</properties>
<children>
+ #include <include/allow-client.xml.i>
+ #include <include/generic-interface.xml.i>
+ #include <include/listen-address.xml.i>
+ #include <include/interface/vrf.xml.i>
+ <leafNode name="leap-second">
+ <properties>
+ <help>Leap second behavior</help>
+ <completionHelp>
+ <list>ignore smear system timezone</list>
+ </completionHelp>
+ <valueHelp>
+ <format>ignore</format>
+ <description>No correction is applied to the clock for the leap second</description>
+ </valueHelp>
+ <valueHelp>
+ <format>smear</format>
+ <description>Correct served time slowly be slewing instead of stepping</description>
+ </valueHelp>
+ <valueHelp>
+ <format>system</format>
+ <description>Kernel steps the system clock forward or backward</description>
+ </valueHelp>
+ <valueHelp>
+ <format>timezone</format>
+ <description>Use UTC timezone database to determine when will the next leap second occur</description>
+ </valueHelp>
+ <constraint>
+ <regex>(ignore|smear|system|timezone)</regex>
+ </constraint>
+ </properties>
+ <defaultValue>timezone</defaultValue>
+ </leafNode>
<tagNode name="server">
<properties>
<help>Network Time Protocol (NTP) server</help>
@@ -56,10 +88,6 @@
</leafNode>
</children>
</tagNode>
- #include <include/allow-client.xml.i>
- #include <include/generic-interface.xml.i>
- #include <include/listen-address.xml.i>
- #include <include/interface/vrf.xml.i>
</children>
</node>
</children>
diff --git a/op-mode-definitions/generate-system-login-user.xml.in b/op-mode-definitions/generate-system-login-user.xml.in
index 6f65c12b3..6f65c12b3 100755..100644
--- a/op-mode-definitions/generate-system-login-user.xml.in
+++ b/op-mode-definitions/generate-system-login-user.xml.in
diff --git a/python/vyos/qos/base.py b/python/vyos/qos/base.py
index d8bbfe970..a22039e52 100644
--- a/python/vyos/qos/base.py
+++ b/python/vyos/qos/base.py
@@ -1,4 +1,4 @@
-# Copyright 2022-2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2022-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
@@ -14,6 +14,7 @@
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
import os
+import jmespath
from vyos.base import Warning
from vyos.utils.process import cmd
@@ -166,14 +167,17 @@ class QoSBase:
}
if rate == 'auto' or rate.endswith('%'):
- speed = 10
+ speed = 1000
+ default_speed = speed
# Not all interfaces have valid entries in the speed file. PPPoE
# interfaces have the appropriate speed file, but you can not read it:
# cat: /sys/class/net/pppoe7/speed: Invalid argument
try:
speed = read_file(f'/sys/class/net/{self._interface}/speed')
if not speed.isnumeric():
- Warning('Interface speed cannot be determined (assuming 10 Mbit/s)')
+ Warning('Interface speed cannot be determined (assuming 1000 Mbit/s)')
+ if int(speed) < 1:
+ speed = default_speed
if rate.endswith('%'):
percent = rate.rstrip('%')
speed = int(speed) * int(percent) // 100
@@ -223,6 +227,9 @@ class QoSBase:
if 'mark' in match_config:
mark = match_config['mark']
filter_cmd += f' handle {mark} fw'
+ if 'vif' in match_config:
+ vif = match_config['vif']
+ filter_cmd += f' basic match "meta(vlan mask 0xfff eq {vif})"'
for af in ['ip', 'ipv6']:
tc_af = af
@@ -298,23 +305,28 @@ class QoSBase:
filter_cmd += f' flowid {self._parent:x}:{cls:x}'
self._cmd(filter_cmd)
+ vlan_expression = "match.*.vif"
+ match_vlan = jmespath.search(vlan_expression, cls_config)
+
if any(tmp in ['exceed', 'bandwidth', 'burst'] for tmp in cls_config):
- filter_cmd += f' action police'
-
- if 'exceed' in cls_config:
- action = cls_config['exceed']
- filter_cmd += f' conform-exceed {action}'
- if 'not_exceed' in cls_config:
- action = cls_config['not_exceed']
- filter_cmd += f'/{action}'
-
- if 'bandwidth' in cls_config:
- rate = self._rate_convert(cls_config['bandwidth'])
- filter_cmd += f' rate {rate}'
-
- if 'burst' in cls_config:
- burst = cls_config['burst']
- filter_cmd += f' burst {burst}'
+ # For "vif" "basic match" is used instead of "action police" T5961
+ if not match_vlan:
+ filter_cmd += f' action police'
+
+ if 'exceed' in cls_config:
+ action = cls_config['exceed']
+ filter_cmd += f' conform-exceed {action}'
+ if 'not_exceed' in cls_config:
+ action = cls_config['not_exceed']
+ filter_cmd += f'/{action}'
+
+ if 'bandwidth' in cls_config:
+ rate = self._rate_convert(cls_config['bandwidth'])
+ filter_cmd += f' rate {rate}'
+
+ if 'burst' in cls_config:
+ burst = cls_config['burst']
+ filter_cmd += f' burst {burst}'
cls = int(cls)
filter_cmd += f' flowid {self._parent:x}:{cls:x}'
self._cmd(filter_cmd)
diff --git a/python/vyos/utils/network.py b/python/vyos/utils/network.py
index c3c419a61..b58e02d91 100644
--- a/python/vyos/utils/network.py
+++ b/python/vyos/utils/network.py
@@ -155,7 +155,9 @@ def is_wwan_connected(interface):
""" Determine if a given WWAN interface, e.g. wwan0 is connected to the
carrier network or not """
import json
+ from vyos.utils.dict import dict_search
from vyos.utils.process import cmd
+ from vyos.utils.process import is_systemd_service_active
if not interface.startswith('wwan'):
raise ValueError(f'Specified interface "{interface}" is not a WWAN interface')
diff --git a/smoketest/scripts/cli/test_service_dhcp-server.py b/smoketest/scripts/cli/test_service_dhcp-server.py
index 91ae901cd..9e8196d7a 100755
--- a/smoketest/scripts/cli/test_service_dhcp-server.py
+++ b/smoketest/scripts/cli/test_service_dhcp-server.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2021 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
@@ -203,12 +203,19 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase):
client_base += 1
# cannot have mappings with duplicate IP addresses
+ self.cli_set(pool + ['static-mapping', 'dupe1', 'mac-address', '00:50:00:00:fe:ff'])
+ self.cli_set(pool + ['static-mapping', 'dupe1', 'ip-address', inc_ip(subnet, 10)])
with self.assertRaises(ConfigSessionError):
- self.cli_set(pool + ['static-mapping', 'dupe1', 'mac', '00:50:00:00:00:01'])
- self.cli_set(pool + ['static-mapping', 'dupe1', 'ip-address', inc_ip(subnet, 10)])
self.cli_commit()
self.cli_delete(pool + ['static-mapping', 'dupe1'])
+ # cannot have mappings with duplicate MAC addresses
+ self.cli_set(pool + ['static-mapping', 'dupe2', 'mac-address', '00:50:00:00:00:10'])
+ self.cli_set(pool + ['static-mapping', 'dupe2', 'ip-address', inc_ip(subnet, 120)])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(pool + ['static-mapping', 'dupe2'])
+
# commit changes
self.cli_commit()
diff --git a/smoketest/scripts/cli/test_service_ntp.py b/smoketest/scripts/cli/test_service_ntp.py
index 5e385d5ad..ae45fe2f4 100755
--- a/smoketest/scripts/cli/test_service_ntp.py
+++ b/smoketest/scripts/cli/test_service_ntp.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
@@ -43,7 +43,7 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
self.assertFalse(process_named_running(PROCESS_NAME))
- def test_01_ntp_options(self):
+ def test_base_options(self):
# Test basic NTP support with multiple servers and their options
servers = ['192.0.2.1', '192.0.2.2']
options = ['nts', 'noselect', 'prefer']
@@ -77,7 +77,7 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
for pool in pools:
self.assertIn(f'pool {pool} iburst', config)
- def test_02_ntp_clients(self):
+ def test_clients(self):
# Test the allowed-networks statement
listen_address = ['127.0.0.1', '::1']
for listen in listen_address:
@@ -107,7 +107,7 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
for listen in listen_address:
self.assertIn(f'bindaddress {listen}', config)
- def test_03_ntp_interface(self):
+ def test_interface(self):
interfaces = ['eth0']
for interface in interfaces:
self.cli_set(base_path + ['interface', interface])
@@ -124,7 +124,7 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
for interface in interfaces:
self.assertIn(f'binddevice {interface}', config)
- def test_04_ntp_vrf(self):
+ def test_vrf(self):
vrf_name = 'vyos-mgmt'
self.cli_set(['vrf', 'name', vrf_name, 'table', '12345'])
@@ -142,5 +142,28 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
self.cli_delete(['vrf', 'name', vrf_name])
+ def test_leap_seconds(self):
+ servers = ['time1.vyos.net', 'time2.vyos.net']
+ for server in servers:
+ self.cli_set(base_path + ['server', server])
+
+ self.cli_commit()
+
+ # Check generated client address configuration
+ # this file must be read with higher permissions
+ config = cmd(f'sudo cat {NTP_CONF}')
+ self.assertIn('leapsectz right/UTC', config) # CLI default
+
+ for mode in ['ignore', 'system', 'smear']:
+ self.cli_set(base_path + ['leap-second', mode])
+ self.cli_commit()
+ config = cmd(f'sudo cat {NTP_CONF}')
+ if mode != 'smear':
+ self.assertIn(f'leapsecmode {mode}', config)
+ else:
+ self.assertIn(f'leapsecmode slew', config)
+ self.assertIn(f'maxslewrate 1000', config)
+ self.assertIn(f'smoothtime 400 0.001024 leaponly', config)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/service_dhcp-server.py b/src/conf_mode/service_dhcp-server.py
index 8d849b1e6..341b31dd7 100755
--- a/src/conf_mode/service_dhcp-server.py
+++ b/src/conf_mode/service_dhcp-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
@@ -22,6 +22,7 @@ from netaddr import IPAddress
from netaddr import IPRange
from sys import exit
+from vyos.base import DeprecationWarning
from vyos.config import Config
from vyos.template import render
from vyos.utils.dict import dict_search
@@ -149,9 +150,15 @@ def verify(dhcp):
shared_networks = len(dhcp['shared_network_name'])
disabled_shared_networks = 0
+ common_deprecation_msg = 'are subject of removal in VyOS 1.5! Please raise a feature request for proper CLI nodes!'
+ if 'global_parameters' in dhcp:
+ DeprecationWarning(f'Additional global parameters {common_deprecation_msg}')
# A shared-network requires a subnet definition
for network, network_config in dhcp['shared_network_name'].items():
+ if 'shared_network_parameters' in network_config:
+ DeprecationWarning(f'Additional shared network parameters in "{network}" {common_deprecation_msg}')
+
if 'disable' in network_config:
disabled_shared_networks += 1
@@ -160,6 +167,9 @@ def verify(dhcp):
'lease subnet must be configured.')
for subnet, subnet_config in network_config['subnet'].items():
+ if 'subnet_parameters' in subnet_config:
+ DeprecationWarning(f'Additional subnet parameters in "{subnet}" {common_deprecation_msg}')
+
# All delivered static routes require a next-hop to be set
if 'static_route' in subnet_config:
for route, route_option in subnet_config['static_route'].items():
@@ -215,6 +225,7 @@ def verify(dhcp):
if 'static_mapping' in subnet_config:
# Static mappings require just a MAC address (will use an IP from the dynamic pool if IP is not set)
used_ips = []
+ used_mac = []
for mapping, mapping_config in subnet_config['static_mapping'].items():
if 'ip_address' in mapping_config:
if ip_address(mapping_config['ip_address']) not in ip_network(subnet):
@@ -226,10 +237,14 @@ def verify(dhcp):
f'within shared-network "{network}, {subnet}"!')
if mapping_config['ip_address'] in used_ips:
- raise ConfigError(f'Configured IP address for static mapping "{mapping}" exists on another static mapping')
-
+ raise ConfigError(f'Configured IP address for static mapping "{mapping}" already exists on another static mapping')
used_ips.append(mapping_config['ip_address'])
+ if 'mac_address' in mapping_config:
+ if mapping_config['mac_address'] in used_mac:
+ raise ConfigError(f'Configured MAC address for static mapping "{mapping}" already exists on another static mapping')
+ used_mac.append(mapping_config['mac_address'])
+
# There must be one subnet connected to a listen interface.
# This only counts if the network itself is not disabled!
if 'disable' not in network_config:
diff --git a/src/conf_mode/service_ntp.py b/src/conf_mode/service_ntp.py
index 1cc23a7df..f11690ee6 100755
--- a/src/conf_mode/service_ntp.py
+++ b/src/conf_mode/service_ntp.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
@@ -42,7 +42,7 @@ def get_config(config=None):
if not conf.exists(base):
return None
- ntp = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
+ ntp = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True, with_defaults=True)
ntp['config_file'] = config_file
ntp['user'] = user_group