Skip to content

Commit

Permalink
[202311][cherry-pick][NTP] Add NTP extended configuration (#17487)
Browse files Browse the repository at this point in the history
* Add NTP YANG model

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Extend NTP config generation mechanism

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Add NTP YANG nodel tests

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Add test for NTP Jinja templates

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Add ntpdate package

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Fix 'bad' when auth disabled

Signed-off-by: Yevhen Fastiuk <[email protected]>

* [NTP] Changed owner for ntp keys config file to root and remove read access for other.

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Fix NTP warnings after restarting the service

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Add ability to encrypt/decrypt NTP keys

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Update Configuration reference

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Fix NTP configuration template

* Align the description for setting interface
* Fix the usage of scoped variable

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Fix YANG model description and tests

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Align NTP test according to fixed condition

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Allow eth0 to be as source ifc without defining it

Signed-off-by: Yevhen Fastiuk <[email protected]>

* Update sample config with NTP config

Signed-off-by: Yevhen Fastiuk <[email protected]>

---------

Signed-off-by: Yevhen Fastiuk <[email protected]>
  • Loading branch information
fastiuk authored Dec 21, 2023
1 parent bd8ed6b commit f78cb9c
Show file tree
Hide file tree
Showing 21 changed files with 891 additions and 282 deletions.
10 changes: 10 additions & 0 deletions files/build_templates/init_cfg.json.j2
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
}
3 changes: 3 additions & 0 deletions files/build_templates/sonic_debian_extension.j2
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
100 changes: 0 additions & 100 deletions files/image_config/ntp/ntp

This file was deleted.

4 changes: 4 additions & 0 deletions files/image_config/ntp/ntp-config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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} ..."
Expand Down
17 changes: 13 additions & 4 deletions files/image_config/ntp/ntp-systemd-wrapper
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -27,21 +28,29 @@ 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)
if [ "$vrfEnabled" = "true" ]
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
Expand Down
136 changes: 89 additions & 47 deletions files/image_config/ntp/ntp.conf.j2
Original file line number Diff line number Diff line change
@@ -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', {}) -%}

{# 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 = '' -%}

{# 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 %}

# You do need to talk to an NTP server or two (or three).
#server ntp.your-provider.example
{% 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: <http://www.pool.ntp.org/join.html>
{% for ntp_server in NTP_SERVER %}
server {{ ntp_server }} iburst
{% 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 %}
Expand All @@ -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' %}
Expand Down Expand Up @@ -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 <http://support.ntp.org/bin/view/Support/AccessRestrictions>
# 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
18 changes: 18 additions & 0 deletions files/image_config/ntp/ntp.keys.j2
Original file line number Diff line number Diff line change
@@ -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 -%}
Loading

0 comments on commit f78cb9c

Please sign in to comment.