[NTP] Add NTP extended configuration (#15058)

hld [#1296](https://github.com/sonic-net/SONiC/pull/1296)
closes [#1254](https://github.com/sonic-net/SONiC/issues/1254)
depends-on [#60](https://github.com/sonic-net/sonic-host-services/pull/60), [#781](https://github.com/sonic-net/sonic-swss-common/pull/781), [#2835](https://github.com/sonic-net/sonic-utilities/pull/2835), [#10749](https://github.com/sonic-net/sonic-mgmt/pull/10749)

#### Why I did it
To cover the next AIs:
* Configure NTP global parameters
* Add/remove new NTP servers
* Change the configuration for NTP servers
* Show NTP status
* Show NTP configuration

### How I did it
* Add YANG model for a new configuration
* Extend configuration templates to support new knobs

### Description for the changelog
* Add ability to configure NTP global parameters such as authentication, dhcp, admin state
* Change the configuration for NTP servers
* Add an ability to show NTP configuration

#### Link to config_db schema for YANG module changes
[NTP configuration](https://github.com/sonic-net/sonic-buildimage/blob/master/src/sonic-yang-models/doc/Configuration.md#ntp-and-syslog-servers)
This commit is contained in:
Yevhen Fastiuk 2023-12-11 23:31:35 +02:00 committed by GitHub
parent b0bb3d40d3
commit 5efb123ede
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 885 additions and 241 deletions

View File

@ -157,5 +157,15 @@
"memory": "0M-2G:256M,2G-4G:320M,4G-8G:384M,8G-:448M",
"num_dumps": "3"
}
},
"NTP": {
"global": {
"authentication": "disabled",
"dhcp": "enabled",
"server_role": "disabled",
"src_intf": "eth0",
"admin_state": "enabled",
"vrf": "default"
}
}
}

View File

@ -373,10 +373,14 @@ sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/flashrom_*.deb
sudo cp -f $IMAGE_CONFIGS/cron.d/* $FILESYSTEM_ROOT/etc/cron.d/
# Copy NTP configuration files and templates
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT \
apt-get -y install ntpdate
sudo rm -f $FILESYSTEM_ROOT/etc/network/if-up.d/ntpsec-ntpdate
sudo cp $IMAGE_CONFIGS/ntp/ntp-config.service $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_SYSTEM
echo "ntp-config.service" | sudo tee -a $GENERATED_SERVICE_FILE
sudo cp $IMAGE_CONFIGS/ntp/ntp-config.sh $FILESYSTEM_ROOT/usr/bin/
sudo cp $IMAGE_CONFIGS/ntp/ntp.conf.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/
sudo cp $IMAGE_CONFIGS/ntp/ntp.keys.j2 $FILESYSTEM_ROOT_USR_SHARE_SONIC_TEMPLATES/
sudo cp $IMAGE_CONFIGS/ntp/ntp-systemd-wrapper $FILESYSTEM_ROOT/usr/libexec/ntpsec/
sudo mkdir $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_SYSTEM/ntpsec.service.d
sudo cp $IMAGE_CONFIGS/ntp/sonic-target.conf $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_SYSTEM/ntpsec.service.d/

View File

@ -24,6 +24,8 @@ function modify_ntp_default
}
sonic-cfggen -d -t /usr/share/sonic/templates/ntp.conf.j2 >/etc/ntpsec/ntp.conf
sonic-cfggen -d -t /usr/share/sonic/templates/ntp.keys.j2 >/etc/ntpsec/ntp.keys
chmod o-r /etc/ntp.keys
get_database_reboot_type
echo "Disabling NTP long jump for reboot type ${reboot_type} ..."

View File

@ -13,7 +13,8 @@ if [ -r /etc/default/ntpsec ]; then
. /etc/default/ntpsec
fi
if [ "$IGNORE_DHCP" != "yes" ] && [ -e /run/ntpsec/ntp.conf.dhcp ]; then
dhcp=$(/usr/local/bin/sonic-cfggen -d -v 'NTP["global"]["dhcp"]' 2> /dev/null)
if [ "$IGNORE_DHCP" != "yes" ] && [ -e /run/ntpsec/ntp.conf.dhcp ] && [ "$dhcp" = "enabled" ]; then
NTPD_OPTS="$NTPD_OPTS -c /run/ntpsec/ntp.conf.dhcp"
else
# List the default -c first, so if the admin has specified -c in
@ -26,6 +27,14 @@ NTPD_OPTS="$NTPD_OPTS -u ntpsec:ntpsec"
# Protect the service startup against concurrent ntpdate ifup hooks
(
if flock -w 180 9; then
ntpEnabled=$(/usr/local/bin/sonic-cfggen -d -v 'NTP["global"]["admin_state"]' 2> /dev/null)
if [ "$ntpEnabled" = "disabled" ]
then
echo "Stopping NTP daemon"
kill -9 $(cat $PIDFILE)
exit 0
fi
# when mgmt vrf is configured, ntp starts in mgmt vrf by default unless user configures otherwise
vrfEnabled=$(/usr/local/bin/sonic-cfggen -d -v 'MGMT_VRF_CONFIG["vrf_global"]["mgmtVrfEnabled"]' 2> /dev/null)
vrfConfigured=$(/usr/local/bin/sonic-cfggen -d -v 'NTP["global"]["vrf"]' 2> /dev/null)

View File

@ -1,9 +1,9 @@
###############################################################################
# Managed by Ansible
# file: ansible/roles/acs/templates/ntp.conf.j2
# This file was AUTOMATICALLY GENERATED. DO NOT MODIFY.
# Controlled by ntp-config.service
###############################################################################
# /etc/ntpsec/ntp.conf, configuration for ntpd; see ntp.conf(5) for help
# /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help
# To avoid ntpd from panic and exit if the drift between new time and
# current system time is large.
@ -12,35 +12,82 @@ tinker panic 0
driftfile /var/lib/ntpsec/ntp.drift
leapfile /usr/share/zoneinfo/leap-seconds.list
# To enable Network Time Security support as a server, obtain a certificate
# (e.g. with Let's Encrypt), configure the paths below, and uncomment:
# nts cert CERT_FILE
# nts key KEY_FILE
# nts enable
{# Getting NTP global configuration -#}
{% set global = (NTP | d({})).get('global', {}) -%}
# You must create /var/log/ntpsec (owned by ntpsec:ntpsec) to enable logging.
#statsdir /var/log/ntpsec/
#statistics loopstats peerstats clockstats
#filegen loopstats file loopstats type day enable
#filegen peerstats file peerstats type day enable
#filegen clockstats file clockstats type day enable
{# Adding NTP servers. We need to know if we have some pools, to set proper
config -#}
{% set ns = namespace(is_pools=false) %}
{% for server in NTP_SERVER if NTP_SERVER[server].admin_state != 'disabled' and
NTP_SERVER[server].resolve_as and
NTP_SERVER[server].association_type -%}
{% set config = NTP_SERVER[server] -%}
{# Server options -#}
{% set soptions = '' -%}
{# Server access control options -#}
{% set aoptions = '' -%}
# Specify one or more NTP servers.
{# Authentication key -#}
{% if global.authentication == 'enabled' -%}
{% if config.key -%}
{% set soptions = soptions ~ ' key ' ~ config.key -%}
{% endif -%}
{% endif -%}
# Public NTP servers supporting Network Time Security:
# server time.cloudflare.com nts
{% for ntp_server in NTP_SERVER %}
server {{ ntp_server }} iburst
{# Aggressive polling -#}
{% if config.iburst -%}
{% set soptions = soptions ~ ' iburst' -%}
{% endif -%}
{# Protocol version -#}
{% if config.version -%}
{% set soptions = soptions ~ ' version ' ~ config.version -%}
{% endif -%}
{# Check if there are any pool configured. BTW it doesn't matter what was
configured as "resolve_as" for pools. If they were configured with FQDN they
must remain like that -#}
{% set config_as = config.resolve_as -%}
{% if config.association_type == 'pool' -%}
{% set ns.is_pools = true -%}
{% set config_as = server -%}
{% else -%}
{% set aoptions = aoptions ~ ' nopeer' -%}
{% endif -%}
{{ config.association_type }} {{ config_as }}{{ soptions }}
{% if global.server_role == 'disabled' %}
restrict {{ config_as }} kod limited nomodify notrap noquery{{ aoptions }}
{% endif %}
{% endfor -%}
{% set trusted_keys_arr = [] -%}
{% for key in NTP_KEY -%}
{% set keydata = NTP_KEY[key] -%}
{% if keydata.trusted == 'yes' -%}
{% set trusted_keys_arr = trusted_keys_arr.append(key) -%}
{% endif -%}
{% endfor %}
# pool.ntp.org maps to about 1000 low-stratum NTP servers. Your server will
# pick a different set every time it starts up. Please consider joining the
# pool: <https://www.pool.ntp.org/join.html>
{% if global.authentication == 'enabled' %}
keys /etc/ntpsec/ntp.keys
{% if trusted_keys_arr != [] %}
trustedkey {{ trusted_keys_arr|join(' ') }}
{% endif %}
{% endif %}
#listen on source interface if configured, else
#only listen on MGMT_INTERFACE, LOOPBACK_INTERFACE ip when MGMT_INTERFACE is not defined, or eth0
# if we don't have both of them (default is to listen on all ip addresses)
{# listen on source interface if configured, else only listen on MGMT_INTERFACE,
LOOPBACK_INTERFACE ip when MGMT_INTERFACE is not defined, or eth0 if we don't
have both of them (default is to listen on all ip addresses) -#}
interface ignore wildcard
{# Set interface to listen on:
* Set global variable for configured source interface name.
* Set global boolean to indicate if the ip of the configured source
interface is configured.
* If the source interface is configured but no ip on that
interface, then listen on another interface based on existing logic. -#}
{%- macro check_ip_on_interface(interface_name, table_name) %}
{%- set ns = namespace(valid_intf = 'false') %}
{%- if table_name %}
@ -55,8 +102,8 @@ interface ignore wildcard
{% set ns = namespace(source_intf = "") %}
{%- set ns = namespace(source_intf_ip = 'false') %}
{%- if (NTP) and (NTP['global']['src_intf']) %}
{%- set ns.source_intf = (NTP['global']['src_intf']) %}
{%- if global.src_intf %}
{%- set ns.source_intf = global.src_intf %}
{%- if ns.source_intf != "" %}
{%- if ns.source_intf == "eth0" %}
{%- set ns.source_intf_ip = 'true' %}
@ -91,16 +138,19 @@ interface listen eth0
{% endif %}
interface listen 127.0.0.1
# Access control configuration; see /usr/share/doc/ntpsec-doc/html/accopt.html
# for details.
#
# Note that "restrict" applies to both servers and clients, so a configuration
# that might be intended to block requests from certain clients could also end
# up blocking replies from your own upstream servers.
{# Access control options -#}
{% set options = '' -%}
{# Disable NTP server functionality. Should stay on when dhcp is enabled -#}
{# {% if global.server_role == 'disabled' and global.dhcp == 'disabled' -%}
{% set options = options ~ ' ignore' -%}
{% endif -%} #}
# Access control configuration
# By default, exchange time with everybody, but don't allow configuration.
# NTPsec doesn't establish peer associations, and so nopeer has no effect, and has been removed from here
restrict default kod nomodify noquery limited
# NTPsec doesn't establish peer associations, and so nopeer has no effect, and
# has been removed from here
restrict default kod nomodify noquery limited{{ options }}
# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1

View File

@ -0,0 +1,18 @@
###############################################################################
# This file was AUTOMATICALLY GENERATED. DO NOT MODIFY.
# Controlled by ntp-config.service
###############################################################################
{# We can connect only to the servers we trust. Determine those servers -#}
{% set trusted_arr = [] -%}
{% for server in NTP_SERVER if NTP_SERVER[server].trusted == 'yes' and
NTP_SERVER[server].resolve_as -%}
{% set _ = trusted_arr.append(NTP_SERVER[server].resolve_as) -%}
{% endfor -%}
{# Define authentication keys inventory -#}
{% set trusted_str = ' ' ~ trusted_arr|join(',') -%}
{% for keyid in NTP_KEY if NTP_KEY[keyid].type and NTP_KEY[keyid].value %}
{% set keyval = NTP_KEY[keyid].value | b64decode %}
{{ keyid }} {{ NTP_KEY[keyid].type }} {{ keyval }}{{trusted_str}}
{% endfor -%}

View File

@ -1,100 +0,0 @@
#!/bin/sh
# This file was originally created automatically as part of default NTP application installation from debian package.
# This is now manually modified for supporting NTP in management VRF.
# When management VRF is enabled, the NTP application should be started using "cgexec -g l3mdev:mgmt".
# Check has been added to verify the management VRF enabled status and use cgexec when it is enabled.
# This file will be copied on top of the etc/init.d/ntpsec file that gets created during build process.
### BEGIN INIT INFO
# Provides: ntpsec
# Required-Start: $network $remote_fs $syslog
# Required-Stop: $network $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop:
# Short-Description: Start NTP daemon
# Description: NTP, the Network Time Protocol, is used to keep computer
# clocks accurate by synchronizing them over the Internet or
# a local network, or by following an accurate hardware
# receiver that interprets GPS, DCF-77, or similar time
# signals.
### END INIT INFO
PATH=/sbin:/bin:/usr/sbin:/usr/bin
. /lib/lsb/init-functions
DAEMON=/usr/sbin/ntpd
PIDFILE=/run/ntpd.pid
test -x $DAEMON || exit 5
if [ -r /etc/default/ntpsec ]; then
. /etc/default/ntpsec
fi
if [ "$IGNORE_DHCP" != "yes" ] && [ -e /run/ntpsec/ntp.conf.dhcp ]; then
NTPD_OPTS="$NTPD_OPTS -c /run/ntpsec/ntp.conf.dhcp"
else
# List the default -c first, so if the admin has specified -c in
# NTPD_OPTS, it is honored.
NTPD_OPTS="-c /etc/ntpsec/ntp.conf $NTPD_OPTS"
fi
NTPD_OPTS="$NTPD_OPTS -u ntpsec:ntpsec"
LOCKFILE=/run/lock/ntpsec-ntpdate
case $1 in
start)
log_daemon_msg "Starting NTP server" "ntpd"
(
flock -w 180 9
# when mgmt vrf is configured, ntp starts in mgmt vrf by default unless user configures otherwise
vrfEnabled=$(/usr/local/bin/sonic-cfggen -d -v 'MGMT_VRF_CONFIG["vrf_global"]["mgmtVrfEnabled"]' 2> /dev/null)
vrfConfigured=$(/usr/local/bin/sonic-cfggen -d -v 'NTP["global"]["vrf"]' 2> /dev/null)
if [ "$vrfEnabled" = "true" ]
then
if [ "$vrfConfigured" = "default" ]
then
log_daemon_msg "Starting NTP server in default-vrf for default set as NTP vrf" "ntpd"
start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --startas $DAEMON -- -p $PIDFILE $NTPD_OPTS
else
log_daemon_msg "Starting NTP server in mgmt-vrf" "ntpd"
cgexec -g l3mdev:mgmt start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --startas $DAEMON -- -p $PIDFILE $NTPD_OPTS
fi
else
log_daemon_msg "Starting NTP server in default-vrf" "ntpd"
start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --startas $DAEMON -- -p $PIDFILE $NTPD_OPTS
fi
) 9>$LOCKFILE
log_end_msg $?
;;
stop)
log_daemon_msg "Stopping NTP server" "ntpd"
start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE --retry=TERM/30/KILL/5 --exec $DAEMON
log_end_msg $?
rm -f $PIDFILE
;;
restart|force-reload)
$0 stop && sleep 2 && $0 start
;;
try-restart)
if $0 status >/dev/null; then
$0 restart
else
exit 0
fi
;;
reload)
exit 3
;;
status)
status_of_proc $DAEMON "NTP server"
;;
*)
echo "Usage: $0 {start|stop|restart|try-restart|force-reload|status}"
exit 2
;;
esac

View File

@ -26,6 +26,7 @@ import os
import sys
import yaml
import ipaddress
import base64
from collections import OrderedDict
from config_samples import generate_sample_config, get_available_config
@ -139,6 +140,29 @@ def ip_network(value):
return "Invalid ip address %s" % value
return r_v.network
def b64encode(value):
"""Base64 encoder
Return:
encoded string or the same value in case of error
"""
try:
ret = base64.b64encode(value.encode()).decode()
except:
return value
return ret
def b64decode(value):
"""Base64 decoder
Return:
decoded string or the same value in case of error
"""
try:
ret = base64.b64decode(value.encode()).decode()
except:
return value
return ret
def get_primary_addr(value):
if not value:
return ""
@ -274,6 +298,10 @@ def _get_jinja2_env(paths):
for attr in ['ip', 'network', 'prefixlen', 'netmask', 'broadcast']:
env.filters[attr] = partial(prefix_attr, attr)
# Base64 encoder/decoder
env.filters['b64encode'] = b64encode
env.filters['b64decode'] = b64decode
return env
def main():

View File

@ -1,7 +1,49 @@
{
"NTP": {
"global": {
"src_intf": "Ethernet0"
"src_intf": "eth0",
"vrf": "default",
"authentication": "enabled",
"dhcp": "disabled",
"server_role": "disabled",
"admin_state": "enabled"
}
},
"NTP_SERVER": {
"my_ntp_server": {
"association_type": "server",
"iburst": "off",
"admin_state": "disabled",
"version": 3,
"resolve_as": "10.20.30.40"
},
"server2": {
"association_type": "server",
"iburst": "off",
"admin_state": "enabled",
"version": 3,
"resolve_as": "10.20.30.50",
"key": 42,
"trusted": "no"
},
"pool.ntp.org": {
"association_type": "pool",
"iburst": "on",
"admin_state": "enabled",
"version": 3,
"resolve_as": "pool.ntp.org"
}
},
"NTP_KEY": {
"1": {
"type": "md5",
"trusted": "no",
"value": "blabla"
},
"42": {
"type": "sha1",
"trusted": "yes",
"value": "the_answer"
}
},
"INTERFACE": {

View File

@ -0,0 +1 @@
../../../files/image_config/ntp/ntp.keys.j2

View File

@ -1,58 +0,0 @@
###############################################################################
# Managed by Ansible
# file: ansible/roles/acs/templates/ntp.conf.j2
###############################################################################
# /etc/ntpsec/ntp.conf, configuration for ntpd; see ntp.conf(5) for help
# To avoid ntpd from panic and exit if the drift between new time and
# current system time is large.
tinker panic 0
driftfile /var/lib/ntpsec/ntp.drift
leapfile /usr/share/zoneinfo/leap-seconds.list
# To enable Network Time Security support as a server, obtain a certificate
# (e.g. with Let's Encrypt), configure the paths below, and uncomment:
# nts cert CERT_FILE
# nts key KEY_FILE
# nts enable
# You must create /var/log/ntpsec (owned by ntpsec:ntpsec) to enable logging.
#statsdir /var/log/ntpsec/
#statistics loopstats peerstats clockstats
#filegen loopstats file loopstats type day enable
#filegen peerstats file peerstats type day enable
#filegen clockstats file clockstats type day enable
# Specify one or more NTP servers.
# Public NTP servers supporting Network Time Security:
# server time.cloudflare.com nts
# pool.ntp.org maps to about 1000 low-stratum NTP servers. Your server will
# pick a different set every time it starts up. Please consider joining the
# pool: <https://www.pool.ntp.org/join.html>
#listen on source interface if configured, else
#only listen on MGMT_INTERFACE, LOOPBACK_INTERFACE ip when MGMT_INTERFACE is not defined, or eth0
# if we don't have both of them (default is to listen on all ip addresses)
interface ignore wildcard
interface listen Ethernet0
interface listen 127.0.0.1
# Access control configuration; see /usr/share/doc/ntpsec-doc/html/accopt.html
# for details.
#
# Note that "restrict" applies to both servers and clients, so a configuration
# that might be intended to block requests from certain clients could also end
# up blocking replies from your own upstream servers.
# By default, exchange time with everybody, but don't allow configuration.
# NTPsec doesn't establish peer associations, and so nopeer has no effect, and has been removed from here
restrict default kod nomodify noquery limited
# Local users may interrogate the ntp server more closely.
restrict 127.0.0.1
restrict ::1

View File

@ -0,0 +1 @@
../py3/ntp.conf

View File

@ -0,0 +1 @@
../py3/ntp.keys

View File

@ -1,9 +1,9 @@
###############################################################################
# Managed by Ansible
# file: ansible/roles/acs/templates/ntp.conf.j2
# This file was AUTOMATICALLY GENERATED. DO NOT MODIFY.
# Controlled by ntp-config.service
###############################################################################
# /etc/ntpsec/ntp.conf, configuration for ntpd; see ntp.conf(5) for help
# /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help
# To avoid ntpd from panic and exit if the drift between new time and
# current system time is large.
@ -12,45 +12,28 @@ tinker panic 0
driftfile /var/lib/ntpsec/ntp.drift
leapfile /usr/share/zoneinfo/leap-seconds.list
# To enable Network Time Security support as a server, obtain a certificate
# (e.g. with Let's Encrypt), configure the paths below, and uncomment:
# nts cert CERT_FILE
# nts key KEY_FILE
# nts enable
server 10.20.30.50 key 42 iburst version 3
restrict 10.20.30.50 kod limited nomodify notrap noquery nopeer
# You must create /var/log/ntpsec (owned by ntpsec:ntpsec) to enable logging.
#statsdir /var/log/ntpsec/
#statistics loopstats peerstats clockstats
#filegen loopstats file loopstats type day enable
#filegen peerstats file peerstats type day enable
#filegen clockstats file clockstats type day enable
pool pool.ntp.org iburst version 3
restrict pool.ntp.org kod limited nomodify notrap noquery
# Specify one or more NTP servers.
# Public NTP servers supporting Network Time Security:
# server time.cloudflare.com nts
keys /etc/ntpsec/ntp.keys
trustedkey 42
# pool.ntp.org maps to about 1000 low-stratum NTP servers. Your server will
# pick a different set every time it starts up. Please consider joining the
# pool: <https://www.pool.ntp.org/join.html>
#listen on source interface if configured, else
#only listen on MGMT_INTERFACE, LOOPBACK_INTERFACE ip when MGMT_INTERFACE is not defined, or eth0
# if we don't have both of them (default is to listen on all ip addresses)
interface ignore wildcard
interface listen Ethernet0
interface listen eth0
interface listen 127.0.0.1
# Access control configuration; see /usr/share/doc/ntpsec-doc/html/accopt.html
# for details.
#
# Note that "restrict" applies to both servers and clients, so a configuration
# that might be intended to block requests from certain clients could also end
# up blocking replies from your own upstream servers.
# Access control configuration
# By default, exchange time with everybody, but don't allow configuration.
# NTPsec doesn't establish peer associations, and so nopeer has no effect, and has been removed from here
# NTPsec doesn't establish peer associations, and so nopeer has no effect, and
# has been removed from here
restrict default kod nomodify noquery limited
# Local users may interrogate the ntp server more closely.

View File

@ -0,0 +1,8 @@
###############################################################################
# This file was AUTOMATICALLY GENERATED. DO NOT MODIFY.
# Controlled by ntp-config.service
###############################################################################
1 md5 blabla
42 sha1 the_answer

View File

@ -675,10 +675,19 @@ class TestJ2Files(TestCase):
def test_ntp_conf(self):
conf_template = os.path.join(self.test_dir, "ntp.conf.j2")
ntp_interfaces_json = os.path.join(self.test_dir, "data", "ntp", "ntp_interfaces.json")
config_db_ntp_json = os.path.join(self.test_dir, "data", "ntp", "ntp_interfaces.json")
expected = os.path.join(self.test_dir, "sample_output", utils.PYvX_DIR, "ntp.conf")
argument = ['-j', ntp_interfaces_json, '-t', conf_template]
argument = ['-j', config_db_ntp_json, '-t', conf_template]
self.run_script(argument, output_file=self.output_file)
assert utils.cmp(expected, self.output_file), self.run_diff(expected, self.output_file)
def test_ntp_keys(self):
conf_template = os.path.join(self.test_dir, "ntp.keys.j2")
config_db_ntp_json = os.path.join(self.test_dir, "data", "ntp", "ntp_interfaces.json")
expected = os.path.join(self.test_dir, "sample_output", utils.PYvX_DIR, "ntp.keys")
argument = ['-j', config_db_ntp_json, '-t', conf_template]
self.run_script(argument, output_file=self.output_file)
assert utils.cmp(expected, self.output_file), self.run_diff(expected, self.output_file)

View File

@ -1538,6 +1538,35 @@ These configuration options are used to modify the way that
ntp binds to the ports on the switch and which port it uses to
make ntp update requests from.
***NTP Admin state***
If this option is set to `enabled` then ntp client will try to sync system time with configured NTP servers.
Otherwise, NTP client feature will be disabled.
```
{
"NTP": {
"global": {
"admin_state": "enabled"
}
}
}
```
***NTP Server role***
This option is used to control NTP server state on the switch.
If this option is set to `enabled` switch will act as NTP server.
By default `server_role` is `disabled`.
```
{
"NTP": {
"global": {
"server_role": "enabled"
}
}
}
```
***NTP VRF***
If this option is set to `default` then ntp will run within the default vrf
@ -1575,6 +1604,36 @@ for that address.
}
```
***NTP Authentication***
If this option is set to `enabled` then ntp will try to verify NTP servers it connects to.
This option **has no effect** if key is not set for NTP server.
By default it is `disabled`
```
{
"NTP": {
"global": {
"authentication": "enabled"
}
}
}
```
***NTP DHCP leases***
If this option is set to `enabled` then ntp client will try to use NTP servers provided by DHCP server.
If this option is set to `disabled` you will be able to use the user-configured NTP servers.
By default it is `enabled`
```
{
"NTP": {
"global": {
"dhcp": "enabled"
}
}
}
```
### NTP servers
These information are configured in individual tables. Domain name or IP
@ -1585,18 +1644,77 @@ attributes in those objects.
```
{
"NTP_SERVER": {
"2.debian.pool.ntp.org": {},
"1.debian.pool.ntp.org": {},
"3.debian.pool.ntp.org": {},
"0.debian.pool.ntp.org": {}
"2.debian.pool.ntp.org": {
"association_type": "pool",
"iburst": "on",
"admin_state": "enabled",
"version": 4
},
"1.debian.pool.ntp.org": {
"association_type": "pool",
"iburst": "off",
"admin_state": "enabled",
"version": 3
},
"3.debian.pool.ntp.org": {
"association_type": "pool",
"iburst": "on",
"admin_state": "disabled",
"version": 4
},
"0.debian.pool.ntp.org": {
"association_type": "pool",
"iburst": "off",
"admin_state": "disabled",
"version": 3
}
},
"NTP_SERVER": {
"23.92.29.245": {},
"204.2.134.164": {}
"23.92.29.245": {
"association_type": "server",
"iburst": "on",
"admin_state": "enabled",
"version": 4,
"key": 3,
"trusted": "yes"
},
"204.2.134.164": {
"association_type": "server",
"iburst": "on",
"admin_state": "enabled",
"version": 3
}
}
}
```
* `association_type` - is used to control the type of the server. It can be `server` or `pool`.
* `iburst` - agressive server polling `{on, off}`.
* `version` - NTP protool version to use `[3..4]`.
* `key` - authentication key id `[1..65535]` to use to auth the server.
* `admin_state` - enable or disable specific server.
* `trusted` - trust this server when auth is enabled.
***NTP keys***
```
{
"NTP_KEY": {
"1": {
"type": "md5",
"value": "bXlwYXNzd29yZA==",
"trusted": "yes"
},
"42": {
"type": "sha1",
"value": "dGhlYW5zd2Vy",
"trusted": "no"
}
}
}
```
* `type` - key type to use `{md5, sha1, sha256, sha384, sha512}`.
* `value` - base64 encoded key value.
* `trusted` - trust this NTP key `{yes, no}`.
### Peer Switch

View File

@ -477,14 +477,36 @@
},
"NTP": {
"global": {
"authentication": "disabled",
"dhcp": "enabled",
"server_role": "disabled",
"admin_state": "enabled",
"vrf": "mgmt",
"src_intf": "eth0;Loopback0"
}
},
"NTP_SERVER": {
"0.debian.pool.ntp.org": {},
"23.92.29.245": {},
"2001:aa:aa::aa": {}
"0.debian.pool.ntp.org": {
"association_type": "pool",
"resolve_as": "0.debian.pool.ntp.org"
},
"time.google.com": {
"association_type": "server",
"resolve_as": "216.239.35.4"
},
"23.92.29.245": {
"admin_state": "enabled",
"association_type": "server",
"resolve_as": "23.92.29.245",
"iburst": "off",
"trusted": "yes"
},
"2001:aa:aa::aa": {
"admin_state": "disabled",
"iburst": "on",
"association_type": "server",
"resolve_as": "2001:aa:aa::aa"
}
},
"SYSLOG_SERVER" : {
"10.13.14.17": {

View File

@ -58,5 +58,82 @@
"desc": "CONFIGURE NON-EXISTING MGMT INTERFACE AS NTP SOURCE INTERFACE.",
"eStrKey": "InvalidValue",
"eStr": ["src"]
},
"NTP_GLOB_VALID1": {
"desc": "NTP global params valid config 1"
},
"NTP_GLOB_VALID2": {
"desc": "NTP global params valid config 2"
},
"NTP_AUTH_INVALID1": {
"desc": "NTP authentication state invalid 1",
"eStrKey": "InvalidValue"
},
"NTP_AUTH_INVALID2": {
"desc": "NTP authentication state invalid 2",
"eStrKey": "InvalidValue"
},
"NTP_DHCP_INVALID1": {
"desc": "NTP DHCP state invalid 1",
"eStrKey": "InvalidValue"
},
"NTP_DHCP_INVALID2": {
"desc": "NTP DHCP state invalid 2",
"eStrKey": "InvalidValue"
},
"NTP_SERVER_ROLE_INVALID1": {
"desc": "NTP server role state invalid 1",
"eStrKey": "InvalidValue"
},
"NTP_SERVER_ROLE_INVALID2": {
"desc": "NTP server role state invalid 2",
"eStrKey": "InvalidValue"
},
"NTP_STATE_INVALID1": {
"desc": "NTP daemon state invalid 1",
"eStrKey": "InvalidValue"
},
"NTP_STATE_INVALID2": {
"desc": "NTP daemon state invalid 2",
"eStrKey": "InvalidValue"
},
"NTP_SERVER_ASSOCIATION_INVALID": {
"desc": "NTP server type invalid",
"eStrKey": "InvalidValue"
},
"NTP_SERVER_IBURST_INVALID": {
"desc": "NTP server aggressive mode invalid",
"eStrKey": "InvalidValue"
},
"NTP_SERVER_KEY_INVALID": {
"desc": "NTP server authentication key invalid",
"eStrKey": "InvalidValue"
},
"NTP_SERVER_STATE_INVALID": {
"desc": "NTP server state invalid",
"eStrKey": "InvalidValue"
},
"NTP_SERVER_TRUSTED_INVALID": {
"desc": "NTP server trusted mode invalid",
"eStrKey": "InvalidValue"
},
"NTP_KEY_VALID": {
"desc": "NTP authentication keys inventory"
},
"NTP_KEY_ID_INVALID": {
"desc": "NTP authentication keys invalid key id",
"eStrKey": "InvalidValue"
},
"NTP_KEY_TRUSTED_INVALID": {
"desc": "NTP authentication keys invalid trustiness",
"eStrKey": "InvalidValue"
},
"NTP_KEY_TYPE_INVALID": {
"desc": "NTP authentication keys invalid key type",
"eStrKey": "InvalidValue"
},
"NTP_KEY_VALUE_INVALID": {
"desc": "NTP authentication keys bad key value",
"eStrKey": "Range"
}
}

View File

@ -4,13 +4,38 @@
"sonic-ntp:NTP_SERVER": {
"NTP_SERVER_LIST": [
{
"server_address": "10.11.12.13"
"server_address": "10.11.12.13",
"association_type": "server",
"iburst": "on",
"key": 10,
"admin_state": "enabled",
"trusted": "no"
},
{
"server_address": "2001:aa:aa::aa"
"server_address": "2001:aa:aa::aa",
"association_type": "server",
"iburst": "off",
"key": 15,
"admin_state": "disabled",
"trusted": "yes"
},
{
"server_address": "pool.ntp.org"
"server_address": "pool.ntp.org",
"association_type": "pool",
"iburst": "on",
"admin_state": "enabled"
}
]
},
"sonic-ntp:NTP_KEY": {
"NTP_KEYS_LIST": [
{
"id": 10,
"value": "bHVtb3M="
},
{
"id": 15,
"value": "Ym9tYmFyZGE="
}
]
}
@ -237,5 +262,234 @@
]
}
}
},
"NTP_GLOB_VALID1": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP": {
"sonic-ntp:global": {
"authentication": "enabled",
"dhcp": "enabled",
"server_role": "enabled",
"admin_state": "enabled"
}
}
}
},
"NTP_GLOB_VALID2": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP": {
"sonic-ntp:global": {
"authentication": "disabled",
"dhcp": "disabled",
"server_role": "disabled",
"admin_state": "disabled"
}
}
}
},
"NTP_AUTH_INVALID1": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP": {
"sonic-ntp:global": {
"authentication": ""
}
}
}
},
"NTP_AUTH_INVALID2": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP": {
"sonic-ntp:global": {
"authentication": "blahblah"
}
}
}
},
"NTP_DHCP_INVALID1": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP": {
"sonic-ntp:global": {
"dhcp": ""
}
}
}
},
"NTP_DHCP_INVALID2": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP": {
"sonic-ntp:global": {
"dhcp": "abracadabra"
}
}
}
},
"NTP_SERVER_ROLE_INVALID1": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP": {
"sonic-ntp:global": {
"server_role": ""
}
}
}
},
"NTP_SERVER_ROLE_INVALID2": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP": {
"sonic-ntp:global": {
"server_role": "olololo"
}
}
}
},
"NTP_STATE_INVALID1": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP": {
"sonic-ntp:global": {
"admin_state": ""
}
}
}
},
"NTP_STATE_INVALID2": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP": {
"sonic-ntp:global": {
"admin_state": "azazaza"
}
}
}
},
"NTP_SERVER_ASSOCIATION_INVALID": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP_SERVER": {
"NTP_SERVER_LIST": [
{
"server_address": "2001:aa:aa:aa",
"association_type": "puul"
}
]
}
}
},
"NTP_SERVER_IBURST_INVALID": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP_SERVER": {
"NTP_SERVER_LIST": [
{
"server_address": "2001:aa:aa:aa",
"iburst": "of"
}
]
}
}
},
"NTP_SERVER_KEY_INVALID": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP_SERVER": {
"NTP_SERVER_LIST": [
{
"server_address": "2001:aa:aa:aa",
"key": 0
}
]
}
}
},
"NTP_SERVER_STATE_INVALID": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP_SERVER": {
"NTP_SERVER_LIST": [
{
"server_address": "2001:aa:aa:aa",
"admin_state": "enable"
}
]
}
}
},
"NTP_SERVER_TRUSTED_INVALID": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP_SERVER": {
"NTP_SERVER_LIST": [
{
"server_address": "2001:aa:aa:aa",
"trusted": "not"
}
]
}
}
},
"NTP_KEY_VALID": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP_KEY": {
"NTP_KEYS_LIST": [
{
"id": 20,
"type": "md5",
"value": "anNkZjg4MzIwZnNkMkBANDQ1",
"trusted": "no"
},
{
"id": 30,
"type": "sha1",
"value": "YWFiYmNjZGRlZWZm",
"trusted": "yes"
},
{
"id": 42,
"type": "md5",
"value": "dGhlYW5zd2Vy",
"trusted": "yes"
}
]
}
}
},
"NTP_KEY_ID_INVALID": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP_KEY": {
"NTP_KEYS_LIST": [
{
"id": 100000
}
]
}
}
},
"NTP_KEY_TRUSTED_INVALID": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP_KEY": {
"NTP_KEYS_LIST": [
{
"id": 20,
"trusted": "nope"
}
]
}
}
},
"NTP_KEY_TYPE_INVALID": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP_KEY": {
"NTP_KEYS_LIST": [
{
"id": 20,
"type": "md6"
}
]
}
}
},
"NTP_KEY_VALUE_INVALID": {
"sonic-ntp:sonic-ntp": {
"sonic-ntp:NTP_KEY": {
"NTP_KEYS_LIST": [
{
"id": 20,
"value": ""
}
]
}
}
}
}

View File

@ -33,6 +33,10 @@ module sonic-ntp {
prefix mprt;
}
import sonic-types {
prefix stypes;
}
description
"NTP yang Module for SONiC OS";
@ -41,6 +45,39 @@ module sonic-ntp {
"First revision";
}
revision 2023-03-20 {
description
"Add extended configuration options";
}
typedef association-type {
description "NTP server association type";
type enumeration {
enum server;
enum pool;
}
}
typedef key-type {
description "NTP key encryption type";
type enumeration {
enum md5;
enum sha1;
enum sha256;
enum sha384;
enum sha512;
}
}
typedef key-id {
description "NTP key ID";
type uint16 {
range 1..65535 {
error-message "Failed NTP key ID";
}
}
}
container sonic-ntp {
container NTP {
@ -68,6 +105,9 @@ module sonic-ntp {
type leafref {
path /mprt:sonic-mgmt_port/mprt:MGMT_PORT/mprt:MGMT_PORT_LIST/mprt:name;
}
type string {
pattern 'eth0';
}
}
description
@ -92,6 +132,30 @@ module sonic-ntp {
default VRF or Management VRF.";
}
leaf authentication {
type stypes:admin_mode;
default disabled;
description "NTP authentication state";
}
leaf dhcp {
type stypes:admin_mode;
default enabled;
description "Use NTP servers distributed by DHCP";
}
leaf server_role {
type stypes:admin_mode;
default enabled;
description "NTP server functionality state";
}
leaf admin_state {
type stypes:admin_mode;
default enabled;
description "NTP feature state";
}
} /* end of container global */
} /* end of container NTP */
@ -112,10 +176,95 @@ module sonic-ntp {
leaf server_address {
type inet:host;
}
leaf association_type {
type association-type;
default server;
description "NTP remote association type: server or pool.";
}
leaf iburst {
type stypes:on-off;
default on;
description "NTP aggressive polling";
}
leaf key {
description "NTP server key ID";
type leafref {
path /ntp:sonic-ntp/ntp:NTP_KEY/ntp:NTP_KEYS_LIST/ntp:id;
}
}
leaf resolve_as {
type inet:host;
description "Server resolved IP address";
}
leaf admin_state {
type stypes:admin_mode;
default enabled;
description "NTP server state";
}
leaf trusted {
type stypes:yes-no;
default no;
description "Trust this server. It will force time
synchronization only to this server when
authentication is enabled";
}
leaf version {
type uint8 {
range "3..4" {
error-message "Failed NTP version";
}
}
default 4;
description "NTP proto version to communicate with NTP
server";
}
} /* end of list NTP_SERVER_LIST */
} /* end of container NTP_SERVER */
container NTP_KEY {
description "NTP authentication keys inventory";
list NTP_KEYS_LIST {
description "NTP authentication keys inventory";
key "id";
leaf id {
type key-id;
description "NTP key ID";
}
leaf trusted {
type stypes:yes-no;
default no;
description "Trust this NTP key";
}
leaf value {
type string {
length 1..64;
}
description "NTP encrypted authentication key";
}
leaf type {
type key-type;
default md5;
description "NTP authentication key type";
}
} /* end of list NTP_KEYS_LIST */
} /* end of container NTP_KEY */
} /* end of container sonic-ntp */
} /* end of module sonic-ntp */

View File

@ -360,6 +360,22 @@ module sonic-types {
"BCP 175: Procedures for Maintaining the Time Zone Database";
}
typedef yes-no {
description "Yes/No configuration";
type enumeration {
enum yes;
enum no;
}
}
typedef on-off {
description "On/Off configuration";
type enumeration {
enum on;
enum off;
}
}
{% if yang_model_type == "cvl" %}
/* Required for CVL */
container operation {