From f78cb9c55c827520b8fb94357c1908a1ca866f19 Mon Sep 17 00:00:00 2001 From: Yevhen Fastiuk Date: Thu, 21 Dec 2023 19:45:29 +0200 Subject: [PATCH] [202311][cherry-pick][NTP] Add NTP extended configuration (#17487) * Add NTP YANG model Signed-off-by: Yevhen Fastiuk * Extend NTP config generation mechanism Signed-off-by: Yevhen Fastiuk * Add NTP YANG nodel tests Signed-off-by: Yevhen Fastiuk * Add test for NTP Jinja templates Signed-off-by: Yevhen Fastiuk * Add ntpdate package Signed-off-by: Yevhen Fastiuk * Fix 'bad' when auth disabled Signed-off-by: Yevhen Fastiuk * [NTP] Changed owner for ntp keys config file to root and remove read access for other. Signed-off-by: Yevhen Fastiuk * Fix NTP warnings after restarting the service Signed-off-by: Yevhen Fastiuk * Add ability to encrypt/decrypt NTP keys Signed-off-by: Yevhen Fastiuk * Update Configuration reference Signed-off-by: Yevhen Fastiuk * Fix NTP configuration template * Align the description for setting interface * Fix the usage of scoped variable Signed-off-by: Yevhen Fastiuk * Fix YANG model description and tests Signed-off-by: Yevhen Fastiuk * Align NTP test according to fixed condition Signed-off-by: Yevhen Fastiuk * Allow eth0 to be as source ifc without defining it Signed-off-by: Yevhen Fastiuk * Update sample config with NTP config Signed-off-by: Yevhen Fastiuk --------- Signed-off-by: Yevhen Fastiuk --- files/build_templates/init_cfg.json.j2 | 10 + .../build_templates/sonic_debian_extension.j2 | 3 + files/image_config/ntp/ntp | 100 ------- files/image_config/ntp/ntp-config.sh | 4 + files/image_config/ntp/ntp-systemd-wrapper | 17 +- files/image_config/ntp/ntp.conf.j2 | 136 +++++---- files/image_config/ntp/ntp.keys.j2 | 18 ++ src/sonic-config-engine/sonic-cfggen | 27 ++ .../tests/data/ntp/ntp_interfaces.json | 44 ++- src/sonic-config-engine/tests/ntp.keys.j2 | 1 + .../tests/sample_output/py2/ntp.conf | 73 +---- .../tests/sample_output/py2/ntp.keys | 1 + .../tests/sample_output/py3/ntp.conf | 58 +--- .../tests/sample_output/py3/ntp.keys | 8 + src/sonic-config-engine/tests/test_j2files.py | 13 +- src/sonic-yang-models/doc/Configuration.md | 130 ++++++++- .../tests/files/sample_config_db.json | 28 +- .../tests/yang_model_tests/tests/ntp.json | 77 ++++++ .../yang_model_tests/tests_config/ntp.json | 260 +++++++++++++++++- .../yang-models/sonic-ntp.yang | 149 ++++++++++ .../yang-templates/sonic-types.yang.j2 | 16 ++ 21 files changed, 891 insertions(+), 282 deletions(-) delete mode 100755 files/image_config/ntp/ntp create mode 100644 files/image_config/ntp/ntp.keys.j2 create mode 120000 src/sonic-config-engine/tests/ntp.keys.j2 mode change 100644 => 120000 src/sonic-config-engine/tests/sample_output/py2/ntp.conf create mode 120000 src/sonic-config-engine/tests/sample_output/py2/ntp.keys create mode 100644 src/sonic-config-engine/tests/sample_output/py3/ntp.keys diff --git a/files/build_templates/init_cfg.json.j2 b/files/build_templates/init_cfg.json.j2 index 7ec71a3589..53091a4a24 100644 --- a/files/build_templates/init_cfg.json.j2 +++ b/files/build_templates/init_cfg.json.j2 @@ -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" + } } } diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index b4ecda9942..240ebfaa38 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -370,10 +370,13 @@ 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 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/lib/ntp/ sudo cp $IMAGE_CONFIGS/ntp/ntp.service $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_SYSTEM echo "ntp.service" | sudo tee -a $GENERATED_SERVICE_FILE diff --git a/files/image_config/ntp/ntp b/files/image_config/ntp/ntp deleted file mode 100755 index f0ca500fb8..0000000000 --- a/files/image_config/ntp/ntp +++ /dev/null @@ -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/ntp file that gets created during build process. - -### BEGIN INIT INFO -# Provides: ntp -# 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 -### END INIT INFO - -PATH=/sbin:/bin:/usr/sbin:/usr/bin - -. /lib/lsb/init-functions - -DAEMON=/usr/sbin/ntpd -PIDFILE=/var/run/ntpd.pid - -test -x $DAEMON || exit 5 - -if [ -r /etc/default/ntp ]; then - . /etc/default/ntp -fi - -if [ -e /run/ntp.conf.dhcp ]; then - NTPD_OPTS="$NTPD_OPTS -c /run/ntp.conf.dhcp" -fi - - -LOCKFILE=/run/lock/ntpdate - -RUNASUSER=ntp -UGID=$(getent passwd $RUNASUSER | cut -f 3,4 -d:) || true -if test "$(uname -s)" = "Linux"; then - NTPD_OPTS="$NTPD_OPTS -u $UGID" -fi - -case $1 in - start) - log_daemon_msg "Starting NTP server" "ntpd" - if [ -z "$UGID" ]; then - log_failure_msg "user \"$RUNASUSER\" does not exist" - exit 1 - fi - ( - 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 diff --git a/files/image_config/ntp/ntp-config.sh b/files/image_config/ntp/ntp-config.sh index ace9ad1c8a..3a2a667d80 100755 --- a/files/image_config/ntp/ntp-config.sh +++ b/files/image_config/ntp/ntp-config.sh @@ -24,6 +24,10 @@ function modify_ntp_default } sonic-cfggen -d -t /usr/share/sonic/templates/ntp.conf.j2 >/etc/ntp.conf +sonic-cfggen -d -t /usr/share/sonic/templates/ntp.keys.j2 >/etc/ntp.keys + +chown root:ntp /etc/ntp.keys +chmod o-r /etc/ntp.keys get_database_reboot_type echo "Disabling NTP long jump for reboot type ${reboot_type} ..." diff --git a/files/image_config/ntp/ntp-systemd-wrapper b/files/image_config/ntp/ntp-systemd-wrapper index 1e646f3936..b1e027b9cd 100644 --- a/files/image_config/ntp/ntp-systemd-wrapper +++ b/files/image_config/ntp/ntp-systemd-wrapper @@ -13,7 +13,8 @@ if [ -r /etc/default/ntp ]; then . /etc/default/ntp fi -if [ -e /run/ntp.conf.dhcp ]; then +dhcp=$(/usr/local/bin/sonic-cfggen -d -v 'NTP["global"]["dhcp"]' 2> /dev/null) +if [ -e /run/ntp.conf.dhcp ] && [ "$dhcp" = "enabled" ]; then NTPD_OPTS="$NTPD_OPTS -c /run/ntp.conf.dhcp" fi @@ -27,6 +28,14 @@ fi ( flock -w 180 9 + ntpEnabled=$(/usr/local/bin/sonic-cfggen -d -v 'NTP["global"]["admin_state"]' 2> /dev/null) + if [ "$ntpEnabled" = "disabled" ] + then + logger -p INFO -t "ntpd" "Stopping NTP daemon" + start-stop-daemon --stop --quiet --oknodo --pidfile $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) @@ -34,14 +43,14 @@ fi then if [ "$vrfConfigured" = "default" ] then - log_daemon_msg "Starting NTP server in default-vrf for default set as NTP vrf" "ntpd" + logger -p INFO -t "ntpd" "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" + logger -p INFO -t "ntpd" "Starting NTP server in mgmt-vrf" ip vrf exec 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" + logger -p INFO -t "ntpd" "Starting NTP server in default-vrf" start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --startas $DAEMON -- -p $PIDFILE $NTPD_OPTS fi ) 9>$LOCKFILE diff --git a/files/image_config/ntp/ntp.conf.j2 b/files/image_config/ntp/ntp.conf.j2 index 280b46a426..ff25367f1e 100644 --- a/files/image_config/ntp/ntp.conf.j2 +++ b/files/image_config/ntp/ntp.conf.j2 @@ -1,45 +1,95 @@ ############################################################################### -# 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/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/ntp/ntp.drift - -# Enable this if you want statistics to be logged. -#statsdir /var/log/ntpstats/ - 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 +{# Getting NTP global configuration -#} +{% set global = (NTP | d({})).get('global', {}) -%} -# You do need to talk to an NTP server or two (or three). -#server ntp.your-provider.example +{# 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 = '' -%} -# 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: -{% for ntp_server in NTP_SERVER %} -server {{ ntp_server }} iburst + {# Authentication key -#} + {% if global.authentication == 'enabled' -%} + {% if config.key -%} + {% set soptions = soptions ~ ' key ' ~ config.key -%} + {% endif -%} + {% endif -%} + + {# 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 %} -#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) +{% if global.authentication == 'enabled' %} +keys /etc/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) -#} interface ignore wildcard -# 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 +{# 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 %} @@ -54,8 +104,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' %} @@ -90,32 +140,24 @@ interface listen eth0 {% endif %} interface listen 127.0.0.1 -# Access control configuration; see /usr/share/doc/ntp-doc/html/accopt.html for -# details. The web page -# might also be helpful. -# -# 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 = '' -%} +{# Allow additional servers mobilization from the pool. Otherwise we don't need +that -#} +{% if ns.is_pools == false -%} + {% set options = options ~ ' nopeer' -%} +{% endif -%} +{# 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. -restrict -4 default kod notrap nomodify nopeer noquery -restrict -6 default kod notrap nomodify nopeer noquery +restrict -4 default kod limited notrap nomodify noquery{{ options }} +restrict -6 default kod limited notrap nomodify noquery{{ options }} # Local users may interrogate the ntp server more closely. restrict 127.0.0.1 restrict ::1 - -# Clients from this (example!) subnet have unlimited access, but only if -# cryptographically authenticated. -#restrict 192.168.123.0 mask 255.255.255.0 notrust - - -# If you want to provide time to your local subnet, change the next line. -# (Again, the address is an example only.) -#broadcast 192.168.123.255 - -# If you want to listen to time broadcasts on your local subnet, de-comment the -# next lines. Please do this only if you trust everybody on the network! -#disable auth -#broadcastclient diff --git a/files/image_config/ntp/ntp.keys.j2 b/files/image_config/ntp/ntp.keys.j2 new file mode 100644 index 0000000000..961fc75326 --- /dev/null +++ b/files/image_config/ntp/ntp.keys.j2 @@ -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 -%} diff --git a/src/sonic-config-engine/sonic-cfggen b/src/sonic-config-engine/sonic-cfggen index 243cc3ac2a..e7451a1e17 100755 --- a/src/sonic-config-engine/sonic-cfggen +++ b/src/sonic-config-engine/sonic-cfggen @@ -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 @@ -138,6 +139,28 @@ 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 "" @@ -273,6 +296,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(): diff --git a/src/sonic-config-engine/tests/data/ntp/ntp_interfaces.json b/src/sonic-config-engine/tests/data/ntp/ntp_interfaces.json index 2847583014..a8da7f1331 100644 --- a/src/sonic-config-engine/tests/data/ntp/ntp_interfaces.json +++ b/src/sonic-config-engine/tests/data/ntp/ntp_interfaces.json @@ -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": { diff --git a/src/sonic-config-engine/tests/ntp.keys.j2 b/src/sonic-config-engine/tests/ntp.keys.j2 new file mode 120000 index 0000000000..a95603db8b --- /dev/null +++ b/src/sonic-config-engine/tests/ntp.keys.j2 @@ -0,0 +1 @@ +../../../files/image_config/ntp/ntp.keys.j2 \ No newline at end of file diff --git a/src/sonic-config-engine/tests/sample_output/py2/ntp.conf b/src/sonic-config-engine/tests/sample_output/py2/ntp.conf deleted file mode 100644 index bc98019e88..0000000000 --- a/src/sonic-config-engine/tests/sample_output/py2/ntp.conf +++ /dev/null @@ -1,72 +0,0 @@ -############################################################################### -# Managed by Ansible -# file: ansible/roles/acs/templates/ntp.conf.j2 -############################################################################### - -# /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. -tinker panic 0 - -driftfile /var/lib/ntp/ntp.drift - - -# Enable this if you want statistics to be logged. -#statsdir /var/log/ntpstats/ - -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 - - -# You do need to talk to an NTP server or two (or three). -#server ntp.your-provider.example - -# 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: - -#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 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 - -interface listen Ethernet0 -interface listen 127.0.0.1 - -# Access control configuration; see /usr/share/doc/ntp-doc/html/accopt.html for -# details. The web page -# might also be helpful. -# -# 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. -restrict -4 default kod notrap nomodify nopeer noquery -restrict -6 default kod notrap nomodify nopeer noquery - -# Local users may interrogate the ntp server more closely. -restrict 127.0.0.1 -restrict ::1 - -# Clients from this (example!) subnet have unlimited access, but only if -# cryptographically authenticated. -#restrict 192.168.123.0 mask 255.255.255.0 notrust - - -# If you want to provide time to your local subnet, change the next line. -# (Again, the address is an example only.) -#broadcast 192.168.123.255 - -# If you want to listen to time broadcasts on your local subnet, de-comment the -# next lines. Please do this only if you trust everybody on the network! -#disable auth -#broadcastclient diff --git a/src/sonic-config-engine/tests/sample_output/py2/ntp.conf b/src/sonic-config-engine/tests/sample_output/py2/ntp.conf new file mode 120000 index 0000000000..5ebe399367 --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/py2/ntp.conf @@ -0,0 +1 @@ +../py3/ntp.conf \ No newline at end of file diff --git a/src/sonic-config-engine/tests/sample_output/py2/ntp.keys b/src/sonic-config-engine/tests/sample_output/py2/ntp.keys new file mode 120000 index 0000000000..5f1ab315e5 --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/py2/ntp.keys @@ -0,0 +1 @@ +../py3/ntp.keys \ No newline at end of file diff --git a/src/sonic-config-engine/tests/sample_output/py3/ntp.conf b/src/sonic-config-engine/tests/sample_output/py3/ntp.conf index bc98019e88..56f18e3ca1 100644 --- a/src/sonic-config-engine/tests/sample_output/py3/ntp.conf +++ b/src/sonic-config-engine/tests/sample_output/py3/ntp.conf @@ -1,72 +1,42 @@ ############################################################################### -# 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/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/ntp/ntp.drift - -# Enable this if you want statistics to be logged. -#statsdir /var/log/ntpstats/ - 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 +server 10.20.30.50 key 42 iburst version 3 +restrict 10.20.30.50 kod limited nomodify notrap noquery nopeer -# You do need to talk to an NTP server or two (or three). -#server ntp.your-provider.example +pool pool.ntp.org iburst version 3 +restrict pool.ntp.org kod limited nomodify notrap noquery -# 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: -#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) +keys /etc/ntp.keys +trustedkey 42 + interface ignore wildcard -# 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 + -interface listen Ethernet0 +interface listen eth0 interface listen 127.0.0.1 -# Access control configuration; see /usr/share/doc/ntp-doc/html/accopt.html for -# details. The web page -# might also be helpful. -# -# 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. -restrict -4 default kod notrap nomodify nopeer noquery -restrict -6 default kod notrap nomodify nopeer noquery +restrict -4 default kod limited notrap nomodify noquery +restrict -6 default kod limited notrap nomodify noquery # Local users may interrogate the ntp server more closely. restrict 127.0.0.1 restrict ::1 - -# Clients from this (example!) subnet have unlimited access, but only if -# cryptographically authenticated. -#restrict 192.168.123.0 mask 255.255.255.0 notrust - - -# If you want to provide time to your local subnet, change the next line. -# (Again, the address is an example only.) -#broadcast 192.168.123.255 - -# If you want to listen to time broadcasts on your local subnet, de-comment the -# next lines. Please do this only if you trust everybody on the network! -#disable auth -#broadcastclient diff --git a/src/sonic-config-engine/tests/sample_output/py3/ntp.keys b/src/sonic-config-engine/tests/sample_output/py3/ntp.keys new file mode 100644 index 0000000000..4a1a37b693 --- /dev/null +++ b/src/sonic-config-engine/tests/sample_output/py3/ntp.keys @@ -0,0 +1,8 @@ +############################################################################### +# This file was AUTOMATICALLY GENERATED. DO NOT MODIFY. +# Controlled by ntp-config.service +############################################################################### + +1 md5 blabla +42 sha1 the_answer + diff --git a/src/sonic-config-engine/tests/test_j2files.py b/src/sonic-config-engine/tests/test_j2files.py index 125668f24a..5f31785507 100644 --- a/src/sonic-config-engine/tests/test_j2files.py +++ b/src/sonic-config-engine/tests/test_j2files.py @@ -663,10 +663,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) diff --git a/src/sonic-yang-models/doc/Configuration.md b/src/sonic-yang-models/doc/Configuration.md index a28ffa5c57..5ee894f7aa 100644 --- a/src/sonic-yang-models/doc/Configuration.md +++ b/src/sonic-yang-models/doc/Configuration.md @@ -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 diff --git a/src/sonic-yang-models/tests/files/sample_config_db.json b/src/sonic-yang-models/tests/files/sample_config_db.json index 4eba94e72f..b0e3f5f589 100644 --- a/src/sonic-yang-models/tests/files/sample_config_db.json +++ b/src/sonic-yang-models/tests/files/sample_config_db.json @@ -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": { diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/ntp.json b/src/sonic-yang-models/tests/yang_model_tests/tests/ntp.json index c798de7d83..f380162b83 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/ntp.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/ntp.json @@ -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" } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests_config/ntp.json b/src/sonic-yang-models/tests/yang_model_tests/tests_config/ntp.json index 5b9ab1495a..c886bec3d2 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests_config/ntp.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests_config/ntp.json @@ -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": "" + } + ] + } + } } } diff --git a/src/sonic-yang-models/yang-models/sonic-ntp.yang b/src/sonic-yang-models/yang-models/sonic-ntp.yang index f28e105209..2591f8c7a5 100644 --- a/src/sonic-yang-models/yang-models/sonic-ntp.yang +++ b/src/sonic-yang-models/yang-models/sonic-ntp.yang @@ -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 */ diff --git a/src/sonic-yang-models/yang-templates/sonic-types.yang.j2 b/src/sonic-yang-models/yang-templates/sonic-types.yang.j2 index 4007a386b3..909a883a0e 100644 --- a/src/sonic-yang-models/yang-templates/sonic-types.yang.j2 +++ b/src/sonic-yang-models/yang-templates/sonic-types.yang.j2 @@ -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 {