From af2bce4f0faa27f83b85a3849aa532d5c85518f5 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Thu, 4 Dec 2025 11:26:17 +0000 Subject: [PATCH] Import from AlmaLinux stable repository --- .chrony.metadata | 4 +- .gitignore | 4 +- SOURCES/chrony-4.5-tar-gz-asc.txt | 16 - SOURCES/chrony-4.6.1-tar-gz-asc.txt | 16 + SOURCES/chrony-defconfig.patch | 15 + SOURCES/chrony-docrefresh.patch | 55 +++ SOURCES/chrony-logselect.patch | 612 ++++++++++++++++++++++++++++ SOURCES/chrony-refclkreach.patch | 226 ++++++++++ SOURCES/chrony-serverstats.patch | 39 -- SOURCES/chrony-sourcedir.patch | 279 +++++++++++++ SOURCES/clknetsim-revert-phc.patch | 64 +++ SPECS/chrony.spec | 58 ++- 12 files changed, 1320 insertions(+), 68 deletions(-) delete mode 100644 SOURCES/chrony-4.5-tar-gz-asc.txt create mode 100644 SOURCES/chrony-4.6.1-tar-gz-asc.txt create mode 100644 SOURCES/chrony-defconfig.patch create mode 100644 SOURCES/chrony-docrefresh.patch create mode 100644 SOURCES/chrony-logselect.patch create mode 100644 SOURCES/chrony-refclkreach.patch delete mode 100644 SOURCES/chrony-serverstats.patch create mode 100644 SOURCES/chrony-sourcedir.patch create mode 100644 SOURCES/clknetsim-revert-phc.patch diff --git a/.chrony.metadata b/.chrony.metadata index 59f2c95..d541db2 100644 --- a/.chrony.metadata +++ b/.chrony.metadata @@ -1,2 +1,2 @@ -4661e5df181a9761b73caeaef2f2ab755bbe086a SOURCES/chrony-4.5.tar.gz -e021461c23fe4e5c46fd53c449587d8f6cc217ae SOURCES/clknetsim-5d1dc0.tar.gz +35b070fdd446080232844ac9f70f84ca1823206f SOURCES/chrony-4.6.1.tar.gz +c29c27ef95a3c80737a97ae6e3ee386e1af625de SOURCES/clknetsim-cdd694.tar.gz diff --git a/.gitignore b/.gitignore index a1b6ce7..0b1e042 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -SOURCES/chrony-4.5.tar.gz -SOURCES/clknetsim-5d1dc0.tar.gz +SOURCES/chrony-4.6.1.tar.gz +SOURCES/clknetsim-cdd694.tar.gz diff --git a/SOURCES/chrony-4.5-tar-gz-asc.txt b/SOURCES/chrony-4.5-tar-gz-asc.txt deleted file mode 100644 index 16dae25..0000000 --- a/SOURCES/chrony-4.5-tar-gz-asc.txt +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQIzBAABCAAdFiEEjzdcfo0O4SWj071RU34rdvdoDawFAmVvJPkACgkQU34rdvdo -DawQjw//Zkq4UTPZDpU/gifjUtE/jpIa6+tyhSFpRI5abNScOPaEa8nZz6Q33/s4 -qiS9RJh1AA13xnal7bIHsixadON01x91ysW1sbNhFx942SwTpk00wDdLmySqW+u5 -klrTfGlGRejp7ahasbXx/dXqk3Sz+J19YIvdz2X1o2HaUZwp1SIwq5Y8BYS8iE0a -G5ov/ail2965hwSoYWNbR7/UuOTEO3YgRk2YSpKKKGJgL27pAzwGlOVwgP9JLAD0 -WsGDEpn+EY+4BOkwMyFeACOHyJ+QCcpKXF9B6CGJELyPqTp2uQy+OkaF4VtkGvpp -wRs6IhMoHFt5NjvCiBhOMvocKd6JrxDxN84gGhSG6OtSFp8GZoFhTxIp//mnZDoz -WPl/Z+n3yABdaG7IWavl6tn2wvipMsgcTJHxRYg6A4d2+mKKy0pRyfLUtGTM9EA/ -NEhTIHVZZLORNK7zPaB8CkFmmsmDQVhowBjXjFcq2HDNzQawbU5gjWUBEH+4R4bq -rb4P9Eg3Kus0fvBxj4z72XkzYGNn951YFhwW26x4w09+J35/1eoshNkBaPfOdsRf -Xgb37MmEe5yfU32k27aYtERnH9w/+rOk1RISrVcK0c87uz0RnzPN5HBzc4PnEpx6 -KQFkFxVaaMeJNc0Ca5/u9aE9nli1DIS8Afo/Z4zQtjVMqLsvecQ= -=4/yB ------END PGP SIGNATURE----- diff --git a/SOURCES/chrony-4.6.1-tar-gz-asc.txt b/SOURCES/chrony-4.6.1-tar-gz-asc.txt new file mode 100644 index 0000000..e33cef1 --- /dev/null +++ b/SOURCES/chrony-4.6.1-tar-gz-asc.txt @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCAAdFiEEjzdcfo0O4SWj071RU34rdvdoDawFAmcFKp4ACgkQU34rdvdo +DazMmxAAlSONiDmb/EpwVBigLlVdtyelr6G/9ISMQv/f3CzNlliZOWBQBYiK8UfL ++ohx4uh3R10kWMMJEpeJ7VQMkh3Jn6BKWE3QKQQDKI/Cd39ceeTO57ZZreI3dTRh +8w9xxdwYwEobHhabXQ7wCXDIvssyC6w5LXw4dLmo3N1dC7ZNxJhYgmXVScw6RK5m +bc5Ch/H9bxD1xZiWflXC2dW57nJumJDnMlRVdYot9P2zD0DrGy3cFmh6w89gip67 +T2PrhQ9vQUt8zWKEt9CQi0EtDJ8q1B7HKTLSmM6iEGRjphij+2Z8i0EiQRYA+V++ +ZQVGg+O6MJYuNbPGdwVBZZMVS4wF3mnNkmBk0/tlxNnNH9dqQ1RquRxQCUPDsGwF +dZUmptZWctNaM7TfICdnjEWz/7flR52+BMi5VRYvAK9MCqhTCkg5bw53r02wNSTK +M2PXMRbGuYUGsPDkXaKHf478uhiZF+3ka6tiomK0RT9ip304qhNxdzhsW942ryH2 +yUaFFRGpNk+KJI7e7GfmWmRrBhpi4tqsaFQ4dvUXhlSmk4zVbHIzkgj6Ej6pgJrW +w3lUOlQ49DfNkUnZIVAFHJ6LAmeejTvMNlq9IKHfuFA18X7yhHQI49SXiOUOhKD2 +/z6nMP0cjxQ6eij5UupKx/6/IHTIt9uUpTU1taxAsVXKcBemkN8= +=/5W0 +-----END PGP SIGNATURE----- diff --git a/SOURCES/chrony-defconfig.patch b/SOURCES/chrony-defconfig.patch new file mode 100644 index 0000000..92d5669 --- /dev/null +++ b/SOURCES/chrony-defconfig.patch @@ -0,0 +1,15 @@ +diff --git a/examples/chrony.conf.example2 b/examples/chrony.conf.example2 +index 03e7d47b..bf2bbdda 100644 +--- a/examples/chrony.conf.example2 ++++ b/examples/chrony.conf.example2 +@@ -37,8 +37,8 @@ ntsdumpdir /var/lib/chrony + # Insert/delete leap seconds by slewing instead of stepping. + #leapsecmode slew + +-# Set the TAI-UTC offset of the system clock. +-#leapseclist /usr/share/zoneinfo/leap-seconds.list ++# Get TAI-UTC offset and leap seconds from the system tz database. ++#leapsectz right/UTC + + # Specify directory for log files. + logdir /var/log/chrony diff --git a/SOURCES/chrony-docrefresh.patch b/SOURCES/chrony-docrefresh.patch new file mode 100644 index 0000000..bfd98e0 --- /dev/null +++ b/SOURCES/chrony-docrefresh.patch @@ -0,0 +1,55 @@ +commit b889627998ba584528d1c1145a212fb2b97e5289 +Author: Miroslav Lichvar +Date: Thu Feb 27 10:04:41 2025 +0100 + + doc: improve description of refresh directive + +diff --git a/doc/chrony.conf.adoc b/doc/chrony.conf.adoc +index 7ccdd20c..eb00e029 100644 +--- a/doc/chrony.conf.adoc ++++ b/doc/chrony.conf.adoc +@@ -941,14 +941,15 @@ time, assuming the first update corrects the clock and later checks can work + with correct time. + + [[refresh]]*refresh* _interval_:: +-This directive specifies the interval (in seconds) between refreshing IP +-addresses of NTP sources specified by hostname. If the hostname no longer ++This directive specifies the minimum interval (in seconds) between refreshing ++IP addresses of NTP sources specified by hostname. If the hostname no longer + resolves to the currently used address, it will be replaced with one of the new + addresses to avoid using a server which is no longer intended for service, even + if it is still responding correctly and would not be replaced as unreachable. +-Only one source is refreshed at a time. The default value is 1209600 (2 weeks) +-and the maximum value is 2^31-1 (68 years). A value of 0 disables the periodic +-refreshment. ++Only one source is refreshed at a time and only when a valid response is ++received (unreachable sources are replaced independently). The default value is ++1209600 (2 weeks) and the maximum value is 2^31-1 (68 years). A value of 0 ++disables the periodic refreshment. + + + The <> command can be used to refresh all + sources immediately. +diff -up chrony-4.6.1/doc/chrony.conf.man.in.docrefresh chrony-4.6.1/doc/chrony.conf.man.in +--- chrony-4.6.1/doc/chrony.conf.man.in.docrefresh 2025-05-15 17:04:33.824077026 +0200 ++++ chrony-4.6.1/doc/chrony.conf.man.in 2025-05-15 17:04:53.308070453 +0200 +@@ -1270,14 +1270,15 @@ with correct time. + .sp + \fBrefresh\fP \fIinterval\fP + .RS 4 +-This directive specifies the interval (in seconds) between refreshing IP +-addresses of NTP sources specified by hostname. If the hostname no longer ++This directive specifies the minimum interval (in seconds) between refreshing ++IP addresses of NTP sources specified by hostname. If the hostname no longer + resolves to the currently used address, it will be replaced with one of the new + addresses to avoid using a server which is no longer intended for service, even + if it is still responding correctly and would not be replaced as unreachable. +-Only one source is refreshed at a time. The default value is 1209600 (2 weeks) +-and the maximum value is 2^31\-1 (68 years). A value of 0 disables the periodic +-refreshment. ++Only one source is refreshed at a time and only when a valid response is ++received (unreachable sources are replaced independently). The default value is ++1209600 (2 weeks) and the maximum value is 2^31\-1 (68 years). A value of 0 ++disables the periodic refreshment. + .sp + The \fBrefresh\fP command can be used to refresh all + sources immediately. diff --git a/SOURCES/chrony-logselect.patch b/SOURCES/chrony-logselect.patch new file mode 100644 index 0000000..f3c22a6 --- /dev/null +++ b/SOURCES/chrony-logselect.patch @@ -0,0 +1,612 @@ +commit 620210218c4d2e9634035b3c3d01b0a329708111 +Author: Miroslav Lichvar +Date: Mon Mar 3 15:48:37 2025 +0100 + + sources: refactor logging of source-specific selection status + + Move logging of falsetickers and system peers to the mark_source() + function. Use an array to flag already logged messages in preparation + for logging of other status. Support variable number of arguments in the + logging functions. + +diff --git a/sources.c b/sources.c +index e292e4d6..bfb1c45b 100644 +--- a/sources.c ++++ b/sources.c +@@ -66,7 +66,7 @@ struct SelectInfo { + /* This enum contains the flag values that are used to label + each source */ + typedef enum { +- SRC_OK, /* OK so far, not a final status! */ ++ SRC_OK = 0, /* OK so far, not a final status! */ + SRC_UNSELECTABLE, /* Has noselect option set */ + SRC_BAD_STATS, /* Doesn't have valid stats data */ + SRC_UNSYNCHRONISED, /* Provides samples, but not synchronised */ +@@ -144,9 +144,9 @@ struct SRC_Instance_Record { + /* Flag indicating the source has a leap second vote */ + int leap_vote; + +- /* Flag indicating the source was already reported as +- a falseticker since the last selection change */ +- int reported_falseticker; ++ /* Flags indicating which status was already reported for ++ the source since the last change of the system peer */ ++ char reported_status[SRC_SELECTED + 1]; + }; + + /* ================================================== */ +@@ -360,8 +360,8 @@ SRC_ResetInstance(SRC_Instance instance) + instance->stratum = 0; + instance->leap = LEAP_Unsynchronised; + instance->leap_vote = 0; +- instance->reported_falseticker = 0; + ++ memset(instance->reported_status, 0, sizeof (instance->reported_status)); + memset(&instance->sel_info, 0, sizeof (instance->sel_info)); + + SST_ResetInstance(instance->stats); +@@ -620,20 +620,45 @@ update_sel_options(void) + + /* ================================================== */ + ++FORMAT_ATTRIBUTE_PRINTF(2, 3) + static void +-log_selection_message(LOG_Severity severity, const char *format, const char *arg) ++log_selection_message(LOG_Severity severity, const char *format, ...) + { ++ char buf[256]; ++ va_list ap; ++ + if (REF_GetMode() != REF_ModeNormal) + return; +- LOG(severity, format, arg); ++ ++ va_start(ap, format); ++ vsnprintf(buf, sizeof (buf), format, ap); ++ va_end(ap); ++ ++ LOG(severity, "%s", buf); + } + + /* ================================================== */ + ++FORMAT_ATTRIBUTE_PRINTF(3, 4) + static void +-log_selection_source(LOG_Severity severity, const char *format, SRC_Instance inst) ++log_selection_source(LOG_Severity severity, SRC_Instance inst, const char *format, ...) + { +- char buf[320], *name, *ntp_name; ++ char buf[320], buf2[256], *name, *ntp_name, *s; ++ va_list ap; ++ ++ if (REF_GetMode() != REF_ModeNormal) ++ return; ++ ++ va_start(ap, format); ++ vsnprintf(buf2, sizeof (buf2), format, ap); ++ va_end(ap); ++ ++ /* Replace ## with %s in the formatted string to be the source name */ ++ s = strstr(buf2, "##"); ++ if (!s || strchr(buf2, '%')) ++ return; ++ s[0] = '%'; ++ s[1] = 's'; + + name = source_to_string(inst); + ntp_name = inst->type == SRC_NTP ? NSR_GetName(inst->ip_addr) : NULL; +@@ -643,7 +668,9 @@ log_selection_source(LOG_Severity severity, const char *format, SRC_Instance ins + else + snprintf(buf, sizeof (buf), "%s", name); + +- log_selection_message(severity, format, buf); ++ LOG(severity, buf2, buf); ++ ++ inst->reported_status[inst->status] = 1; + } + + /* ================================================== */ +@@ -686,7 +713,7 @@ source_to_string(SRC_Instance inst) + /* ================================================== */ + + static void +-mark_source(SRC_Instance inst, SRC_Status status) ++set_source_status(SRC_Instance inst, SRC_Status status) + { + struct timespec now; + +@@ -731,6 +758,30 @@ mark_source(SRC_Instance inst, SRC_Status status) + + /* ================================================== */ + ++static void ++mark_source(SRC_Instance inst, SRC_Status status) ++{ ++ set_source_status(inst, status); ++ ++ if (status < SRC_OK || status >= sizeof (inst->reported_status)) ++ assert(0); ++ ++ if (!inst->reported_status[status]) { ++ switch (status) { ++ case SRC_FALSETICKER: ++ log_selection_source(LOGS_WARN, inst, "Detected falseticker ##"); ++ break; ++ case SRC_SELECTED: ++ log_selection_source(LOGS_INFO, inst, "Selected source ##"); ++ break; ++ default: ++ break; ++ } ++ } ++} ++ ++/* ================================================== */ ++ + static void + mark_ok_sources(SRC_Status status) + { +@@ -739,7 +790,8 @@ mark_ok_sources(SRC_Status status) + for (i = 0; i < n_sources; i++) { + if (sources[i]->status != SRC_OK) + continue; +- mark_source(sources[i], status); ++ /* Don't log the status in this case (multiple sources at once) */ ++ set_source_status(sources[i], status); + } + } + +@@ -1161,7 +1213,7 @@ SRC_SelectSource(SRC_Instance updated_inst) + /* Could not even get half the reachable (trusted) sources to agree */ + + if (!reported_no_majority) { +- log_selection_message(LOGS_WARN, "Can't synchronise: no majority", NULL); ++ log_selection_message(LOGS_WARN, "Can't synchronise: no majority"); + reported_no_majority = 1; + report_selection_loss = 0; + } +@@ -1212,10 +1264,6 @@ SRC_SelectSource(SRC_Instance updated_inst) + sel_req_source = 0; + } else { + mark_source(sources[i], SRC_FALSETICKER); +- if (!sources[i]->reported_falseticker) { +- log_selection_source(LOGS_WARN, "Detected falseticker %s", sources[i]); +- sources[i]->reported_falseticker = 1; +- } + } + } + +@@ -1335,13 +1383,12 @@ SRC_SelectSource(SRC_Instance updated_inst) + } + + selected_source_index = max_score_index; +- log_selection_source(LOGS_INFO, "Selected source %s", sources[selected_source_index]); + + /* New source has been selected, reset all scores */ + for (i = 0; i < n_sources; i++) { + sources[i]->sel_score = 1.0; + sources[i]->distant = 0; +- sources[i]->reported_falseticker = 0; ++ memset(sources[i]->reported_status, 0, sizeof (sources[i]->reported_status)); + } + + reported_no_majority = 0; + +commit 52237b7d0da75fcd750c5d5ee80e87b97474f7fd +Author: Miroslav Lichvar +Date: Wed Mar 5 10:45:20 2025 +0100 + + sources: warn about sources exceeding maxdistance or maxjitter + + Log a warning message if a source is rejected in the source selecting + due to exceeding the maxdistance or maxjitter limit to make it more + obvious when synchronization is failing for this reason. Delay the + message until the reachability register is full (8 updates), or a + replacement of the source is attempted. + +diff --git a/sources.c b/sources.c +index bfb1c45b..2ba595b5 100644 +--- a/sources.c ++++ b/sources.c +@@ -768,6 +768,20 @@ mark_source(SRC_Instance inst, SRC_Status status) + + if (!inst->reported_status[status]) { + switch (status) { ++ case SRC_BAD_DISTANCE: ++ if (inst->reachability_size < SOURCE_REACH_BITS && inst->bad < BAD_HANDLE_THRESHOLD) ++ break; ++ log_selection_source(LOGS_WARN, inst, ++ "Root distance of ## exceeds maxdistance of %.3f seconds", ++ max_distance); ++ break; ++ case SRC_JITTERY: ++ if (inst->reachability_size < SOURCE_REACH_BITS && inst->bad < BAD_HANDLE_THRESHOLD) ++ break; ++ log_selection_source(LOGS_WARN, inst, ++ "Jitter of ## exceeds maxjitter of %.3f seconds", ++ max_jitter); ++ break; + case SRC_FALSETICKER: + log_selection_source(LOGS_WARN, inst, "Detected falseticker ##"); + break; + +commit 1c06925d439d8699cc52df71a7a4e809b5b7348f +Author: Miroslav Lichvar +Date: Thu Mar 6 12:46:09 2025 +0100 + + sources: improve no majority log message + + Add the number of sources that form an agreement (overlapping + intervals), if at least two agree with each other, and number of + reachable sources to the "Can't synchronize: no majority" log message to + better explain why synchronization is failing and hint that adding more + sources might help. + +diff --git a/sources.c b/sources.c +index 2ba595b5..3b1766be 100644 +--- a/sources.c ++++ b/sources.c +@@ -1222,12 +1222,23 @@ SRC_SelectSource(SRC_Instance updated_inst) + assert(depth == 0 && trust_depth == 0); + assert(2 * n_sel_sources == n_endpoints); + +- if ((best_trust_depth == 0 && best_depth <= n_sel_sources / 2) || +- (best_trust_depth > 0 && best_trust_depth <= n_sel_trust_sources / 2)) { ++ if (best_trust_depth > 0) { ++ best_depth = best_trust_depth; ++ n_sel_sources = n_sel_trust_sources; ++ } ++ ++ if (best_depth <= n_sel_sources / 2) { + /* Could not even get half the reachable (trusted) sources to agree */ + + if (!reported_no_majority) { +- log_selection_message(LOGS_WARN, "Can't synchronise: no majority"); ++ if (best_depth < 2) ++ log_selection_message(LOGS_WARN, "%s (no agreement among %d %ssources)", ++ "Can't synchronise: no majority", n_sel_sources, ++ best_trust_depth > 0 ? "trusted " : ""); ++ else ++ log_selection_message(LOGS_WARN, "%s (only %d of %d %ssources agree)", ++ "Can't synchronise: no majority", best_depth, ++ n_sel_sources, best_trust_depth > 0 ? "trusted " : ""); + reported_no_majority = 1; + report_selection_loss = 0; + } +diff --git a/test/simulation/009-sourceselection b/test/simulation/009-sourceselection +index 547c376c..139b6aa2 100755 +--- a/test/simulation/009-sourceselection ++++ b/test/simulation/009-sourceselection +@@ -24,6 +24,12 @@ for falsetickers in 3 4; do + # These check are expected to fail + check_source_selection && test_fail + check_sync && test_fail ++ ++ if [ $falsetickers = 3 ]; then ++ check_log_messages "Can't synchronise: no majority (only 2 of 5 sources agree)" 1 1 || test_fail ++ else ++ check_log_messages "Can't synchronise: no majority (no agreement among 5 sources)" 1 1 || test_fail ++ fi + done + + # Sources with large asymmetric delay should be excluded +diff --git a/test/simulation/148-replacement b/test/simulation/148-replacement +index d09fba6e..ee8b2e23 100755 +--- a/test/simulation/148-replacement ++++ b/test/simulation/148-replacement +@@ -68,7 +68,7 @@ check_source_selection && test_fail + check_packet_interval || test_fail + check_sync || test_fail + +-check_log_messages "Can't synchronise: no majority" 1 1 || test_fail ++check_log_messages "Can't synchronise: no majority (no agreement among 2 sources)" 1 1 || test_fail + check_log_messages "Detected falseticker" 0 2 || test_fail + check_log_messages "Source 192.168.123.. replaced with" 3 60 || test_fail + check_log_messages "Source 192.168.123.1 replaced with" 1 25 || test_fail + +commit 2fc7fc2e227f85dcde0953d47e1815432a4a2bf7 +Author: Miroslav Lichvar +Date: Wed Mar 12 15:21:18 2025 +0100 + + sources: delay maxjitter/maxdistance warning messages + + Avoid logging the new warning messages about exceeded maxjitter or + maxdistance when only a small number of samples is collected after the + source becomes reachable and the values are unstable. Log the messages + only when a replacement attempt is made. + +diff --git a/sources.c b/sources.c +index 3b1766be..c8d96af4 100644 +--- a/sources.c ++++ b/sources.c +@@ -769,14 +769,14 @@ mark_source(SRC_Instance inst, SRC_Status status) + if (!inst->reported_status[status]) { + switch (status) { + case SRC_BAD_DISTANCE: +- if (inst->reachability_size < SOURCE_REACH_BITS && inst->bad < BAD_HANDLE_THRESHOLD) ++ if (inst->bad < BAD_HANDLE_THRESHOLD) + break; + log_selection_source(LOGS_WARN, inst, + "Root distance of ## exceeds maxdistance of %.3f seconds", + max_distance); + break; + case SRC_JITTERY: +- if (inst->reachability_size < SOURCE_REACH_BITS && inst->bad < BAD_HANDLE_THRESHOLD) ++ if (inst->bad < BAD_HANDLE_THRESHOLD) + break; + log_selection_source(LOGS_WARN, inst, + "Jitter of ## exceeds maxjitter of %.3f seconds", + +commit 0c7e72304aac05020cbaeb4ccab73ce0c441e1ca +Author: Miroslav Lichvar +Date: Thu Mar 13 15:40:47 2025 +0100 + + sources: switch unselect_selected_source() to variable arguments + + Switch the function to the full printf style, which will be needed to + log an integer. + +diff --git a/sources.c b/sources.c +index c8d96af4..b43ef8dc 100644 +--- a/sources.c ++++ b/sources.c +@@ -206,8 +206,7 @@ static LOG_FileID logfileid; + /* Forward prototype */ + + static void update_sel_options(void); +-static void unselect_selected_source(LOG_Severity severity, const char *format, +- const char *arg); ++static void unselect_selected_source(LOG_Severity severity, const char *format, ...); + static void slew_sources(struct timespec *raw, struct timespec *cooked, double dfreq, + double doffset, LCL_ChangeType change_type, void *anything); + static void add_dispersion(double dispersion, void *anything); +@@ -340,7 +339,7 @@ void SRC_DestroyInstance(SRC_Instance instance) + if (selected_source_index > dead_index) + --selected_source_index; + else if (selected_source_index == dead_index) +- unselect_selected_source(LOGS_INFO, NULL, NULL); ++ unselect_selected_source(LOGS_INFO, NULL); + + SRC_SelectSource(NULL); + } +@@ -815,16 +814,24 @@ mark_ok_sources(SRC_Status status) + call providing a message or selection of another source, which resets the + report_selection_loss flag. */ + ++FORMAT_ATTRIBUTE_PRINTF(2, 3) + static void +-unselect_selected_source(LOG_Severity severity, const char *format, const char *arg) ++unselect_selected_source(LOG_Severity severity, const char *format, ...) + { ++ char buf[256]; ++ va_list ap; ++ + if (selected_source_index != INVALID_SOURCE) { + selected_source_index = INVALID_SOURCE; + report_selection_loss = 1; + } + + if (report_selection_loss && format) { +- log_selection_message(severity, format, arg); ++ va_start(ap, format); ++ vsnprintf(buf, sizeof (buf), format, ap); ++ va_end(ap); ++ ++ log_selection_message(severity, "%s", buf); + report_selection_loss = 0; + } + } +@@ -947,7 +954,7 @@ SRC_SelectSource(SRC_Instance updated_inst) + } + + if (n_sources == 0) { +- unselect_selected_source(LOGS_INFO, "Can't synchronise: no sources", NULL); ++ unselect_selected_source(LOGS_INFO, "Can't synchronise: no sources"); + return; + } + +@@ -1134,7 +1141,7 @@ SRC_SelectSource(SRC_Instance updated_inst) + if (n_badstats_sources && n_sel_sources && selected_source_index == INVALID_SOURCE && + max_sel_reach_size < SOURCE_REACH_BITS && max_sel_reach >> 1 == max_badstat_reach) { + mark_ok_sources(SRC_WAITS_STATS); +- unselect_selected_source(LOGS_INFO, NULL, NULL); ++ unselect_selected_source(LOGS_INFO, NULL); + return; + } + +@@ -1148,7 +1155,7 @@ SRC_SelectSource(SRC_Instance updated_inst) + + if (n_endpoints == 0) { + /* No sources provided valid endpoints */ +- unselect_selected_source(LOGS_INFO, "Can't synchronise: no selectable sources", NULL); ++ unselect_selected_source(LOGS_INFO, "Can't synchronise: no selectable sources"); + return; + } + +@@ -1402,7 +1409,7 @@ SRC_SelectSource(SRC_Instance updated_inst) + /* Before selecting the new synchronisation source wait until the reference + can be updated */ + if (sources[max_score_index]->updates == 0) { +- unselect_selected_source(LOGS_INFO, NULL, NULL); ++ unselect_selected_source(LOGS_INFO, NULL); + mark_ok_sources(SRC_WAITS_UPDATE); + return; + } + +commit a8094716b0c21a037e3f21d2f3c2e45f14060b07 +Author: Miroslav Lichvar +Date: Thu Nov 14 13:41:41 2024 +0100 + + test: add 014-intermittent test + +diff --git a/test/simulation/014-intermittent b/test/simulation/014-intermittent +new file mode 100755 +index 00000000..2f018ed0 +--- /dev/null ++++ b/test/simulation/014-intermittent +@@ -0,0 +1,49 @@ ++#!/usr/bin/env bash ++ ++. ./test.common ++ ++test_start "intermittent connection" ++ ++# Pass packets only for 1200 seconds every 10000 seconds ++base_delay=$(cat <<-EOF | tr -d '\n' ++ (+ 1e-4 ++ (* -1 ++ (equal 0.1 (min (% time 10000) 1200) 1200))) ++EOF ++) ++ ++time_max_limit=1e-1 ++freq_max_limit=1e-2 ++time_rms_limit=2e-3 ++freq_rms_limit=2e-5 ++limit=100000 ++ ++run_test || test_fail ++check_chronyd_exit || test_fail ++check_sync || test_fail ++ ++check_log_messages "Can't.*no selectable sources" 9 10 || test_fail ++check_log_messages "Selected source 192.168.123.1" 9 10 || test_fail ++ ++# Pass every 20th request ++base_delay=$(cat <<-EOF | tr -d '\n' ++ (+ 1e-4 ++ (* -1 ++ (equal 0.1 from 2) ++ (equal 0.1 (min (% (sum 1) 20) 1) 1))) ++EOF ++) ++ ++time_max_limit=1e-2 ++freq_max_limit=1e-4 ++time_rms_limit=5e-3 ++max_sync_time=22000 ++ ++run_test || test_fail ++check_chronyd_exit || test_fail ++check_sync || test_fail ++ ++check_log_messages "Can't.*no selectable sources" 5 15 || test_fail ++check_log_messages "Selected source 192.168.123.1" 5 15 || test_fail ++ ++test_pass + +commit aa3660256a83768aa3fb640f6032780000c7a4fb +Author: Miroslav Lichvar +Date: Thu Mar 13 15:55:32 2025 +0100 + + sources: improve no-selectable-sources log message + + Include the number of unreachable sources in the "Can't synchronise: no + selectable sources" log message to provide a hint whether it might be a + networking issue. + +diff --git a/sources.c b/sources.c +index b43ef8dc..406c2f86 100644 +--- a/sources.c ++++ b/sources.c +@@ -937,7 +937,7 @@ SRC_SelectSource(SRC_Instance updated_inst) + struct timespec now, ref_time; + int i, j, j1, j2, index, sel_prefer, n_endpoints, n_sel_sources, sel_req_source; + int max_badstat_reach, max_badstat_reach_size, n_badstats_sources; +- int max_sel_reach, max_sel_reach_size; ++ int max_sel_reach, max_sel_reach_size, n_unreach_sources; + int depth, best_depth, trust_depth, best_trust_depth, n_sel_trust_sources; + int combined, stratum, min_stratum, max_score_index; + int orphan_stratum, orphan_source; +@@ -966,6 +966,7 @@ SRC_SelectSource(SRC_Instance updated_inst) + n_endpoints = 0; + n_sel_sources = n_sel_trust_sources = 0; + n_badstats_sources = 0; ++ n_unreach_sources = 0; + sel_req_source = 0; + max_sel_reach = max_badstat_reach = 0; + max_sel_reach_size = max_badstat_reach_size = 0; +@@ -988,6 +989,10 @@ SRC_SelectSource(SRC_Instance updated_inst) + continue; + } + ++ /* Count unreachable sources for a warning message */ ++ if (sources[i]->reachability == 0) ++ n_unreach_sources++; ++ + si = &sources[i]->sel_info; + SST_GetSelectionData(sources[i]->stats, &now, + &si->lo_limit, &si->hi_limit, &si->root_distance, +@@ -1155,7 +1160,8 @@ SRC_SelectSource(SRC_Instance updated_inst) + + if (n_endpoints == 0) { + /* No sources provided valid endpoints */ +- unselect_selected_source(LOGS_INFO, "Can't synchronise: no selectable sources"); ++ unselect_selected_source(LOGS_INFO, "Can't synchronise: no selectable sources" ++ " (%d unreachable sources)", n_unreach_sources); + return; + } + +diff --git a/test/simulation/014-intermittent b/test/simulation/014-intermittent +index 2f018ed0..4af574b7 100755 +--- a/test/simulation/014-intermittent ++++ b/test/simulation/014-intermittent +@@ -22,7 +22,7 @@ run_test || test_fail + check_chronyd_exit || test_fail + check_sync || test_fail + +-check_log_messages "Can't.*no selectable sources" 9 10 || test_fail ++check_log_messages "Can't.*no selectable sources (1 unreachable" 9 10 || test_fail + check_log_messages "Selected source 192.168.123.1" 9 10 || test_fail + + # Pass every 20th request +@@ -43,7 +43,7 @@ run_test || test_fail + check_chronyd_exit || test_fail + check_sync || test_fail + +-check_log_messages "Can't.*no selectable sources" 5 15 || test_fail ++check_log_messages "Can't.*no selectable sources (1 unreachable" 5 15 || test_fail + check_log_messages "Selected source 192.168.123.1" 5 15 || test_fail + + test_pass + +commit 402d5d9eb5767797e3af150119b63a08adf43813 +Author: Miroslav Lichvar +Date: Thu Mar 13 16:03:59 2025 +0100 + + sources: increase severity of can't-synchronise log messages + + Switch the info-level "Can't synchronise" selection messages to + warnings. + +diff --git a/sources.c b/sources.c +index 406c2f86..cfe7f260 100644 +--- a/sources.c ++++ b/sources.c +@@ -954,7 +954,7 @@ SRC_SelectSource(SRC_Instance updated_inst) + } + + if (n_sources == 0) { +- unselect_selected_source(LOGS_INFO, "Can't synchronise: no sources"); ++ unselect_selected_source(LOGS_WARN, "Can't synchronise: no sources"); + return; + } + +@@ -1160,7 +1160,7 @@ SRC_SelectSource(SRC_Instance updated_inst) + + if (n_endpoints == 0) { + /* No sources provided valid endpoints */ +- unselect_selected_source(LOGS_INFO, "Can't synchronise: no selectable sources" ++ unselect_selected_source(LOGS_WARN, "Can't synchronise: no selectable sources" + " (%d unreachable sources)", n_unreach_sources); + return; + } +@@ -1306,7 +1306,7 @@ SRC_SelectSource(SRC_Instance updated_inst) + } + + if (!n_sel_sources || sel_req_source || n_sel_sources < CNF_GetMinSources()) { +- unselect_selected_source(LOGS_INFO, "Can't synchronise: %s selectable sources", ++ unselect_selected_source(LOGS_WARN, "Can't synchronise: %s selectable sources", + !n_sel_sources ? "no" : + sel_req_source ? "no required source in" : "not enough"); + mark_ok_sources(SRC_WAITS_SOURCES); diff --git a/SOURCES/chrony-refclkreach.patch b/SOURCES/chrony-refclkreach.patch new file mode 100644 index 0000000..9731d53 --- /dev/null +++ b/SOURCES/chrony-refclkreach.patch @@ -0,0 +1,226 @@ +commit b9b338a8df23927d8104f41ecb21baa3558de0cd +Author: Miroslav Lichvar +Date: Thu Oct 31 14:41:19 2024 +0100 + + refclock: rework update of reachability + + Update the reachability register of a refclock source by 1 if a valid + measurement is received by the drivers between source polls, and not + only when it is accumulated to sourcestats, similarly to how + reachability works with NTP sources. + + This avoids drops in the reported reachability when a PHC refclock is + dropping samples due to significant changes in the measured delay (e.g. + due to high PCIe load), or a PPS refclock dropping samples due to failed + lock. + +diff --git a/doc/chronyc.adoc b/doc/chronyc.adoc +index 935f1da9..dea93c9f 100644 +--- a/doc/chronyc.adoc ++++ b/doc/chronyc.adoc +@@ -364,9 +364,12 @@ a measurement is being made every 64 seconds. *chronyd* automatically varies + the polling rate in response to prevailing conditions. + *Reach*::: + This shows the source's reachability register printed as an octal number. The +-register has 8 bits and is updated on every received or missed packet from +-the source. A value of 377 indicates that a valid reply was received for all +-from the last eight transmissions. ++register has 8 bits. It is shifted to left by one bit with each poll and it is ++updated by 1 when a valid NTP response, or just a sample in case of a reference ++clock, is received from the source. A value of 377 indicates that a valid ++response or sample was received for all of the last 8 polls. Note that samples ++can be dropped if they are not considered good enough for synchronisation, but ++the reachability register will still have 1s for their polls. + *LastRx*::: + This column shows how long ago the last good sample (which is shown in the next + column) was received from the source. Measurements that failed some tests are +diff --git a/refclock.c b/refclock.c +index 22d775a5..d14560fa 100644 +--- a/refclock.c ++++ b/refclock.c +@@ -63,6 +63,7 @@ struct RCL_Instance_Record { + int driver_poll; + int driver_polled; + int poll; ++ int reached; + int leap_status; + int local; + int pps_forced; +@@ -175,6 +176,7 @@ RCL_AddRefclock(RefclockParameters *params) + inst->driver_poll = params->driver_poll; + inst->poll = params->poll; + inst->driver_polled = 0; ++ inst->reached = 0; + inst->leap_status = LEAP_Normal; + inst->local = params->local; + inst->pps_forced = params->pps_forced; +@@ -665,6 +667,12 @@ RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time, + return 1; + } + ++void ++RCL_UpdateReachability(RCL_Instance instance) ++{ ++ instance->reached++; ++} ++ + double + RCL_GetPrecision(RCL_Instance instance) + { +@@ -792,6 +800,9 @@ poll_timeout(void *arg) + if (!(inst->driver->poll && inst->driver_polled < (1 << (inst->poll - inst->driver_poll)))) { + inst->driver_polled = 0; + ++ SRC_UpdateReachability(inst->source, inst->reached > 0); ++ inst->reached = 0; ++ + if (SPF_GetFilteredSample(inst->filter, &sample)) { + double local_freq, local_offset; + struct timespec local_ref_time; +@@ -807,7 +818,6 @@ poll_timeout(void *arg) + inst->leap_status = LEAP_Unsynchronised; + } + +- SRC_UpdateReachability(inst->source, 1); + SRC_UpdateStatus(inst->source, stratum, inst->leap_status); + SRC_AccumulateSample(inst->source, &sample); + SRC_SelectSource(inst->source); +@@ -816,8 +826,6 @@ poll_timeout(void *arg) + follow_local(inst, &local_ref_time, local_freq, local_offset); + + log_sample(inst, &sample.time, 1, 0, 0.0, sample.offset, sample.peer_dispersion); +- } else { +- SRC_UpdateReachability(inst->source, 0); + } + } + +diff --git a/refclock.h b/refclock.h +index 40c852de..5fdbf9c7 100644 +--- a/refclock.h ++++ b/refclock.h +@@ -81,6 +81,7 @@ extern int RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, + extern int RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second); + extern int RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time, + double second, double dispersion, double raw_correction); ++extern void RCL_UpdateReachability(RCL_Instance instance); + extern double RCL_GetPrecision(RCL_Instance instance); + extern int RCL_GetDriverPoll(RCL_Instance instance); + +diff --git a/refclock_phc.c b/refclock_phc.c +index e12f2258..6c0914f6 100644 +--- a/refclock_phc.c ++++ b/refclock_phc.c +@@ -154,6 +154,8 @@ static void process_ext_pulse(RCL_Instance instance, struct timespec *phc_ts) + } + phc->last_extts = *phc_ts; + ++ RCL_UpdateReachability(instance); ++ + if (!HCL_CookTime(phc->clock, phc_ts, &local_ts, &local_err)) + return; + +@@ -204,6 +206,9 @@ static int phc_poll(RCL_Instance instance) + if (n_readings < 1) + return 0; + ++ if (!phc->extpps) ++ RCL_UpdateReachability(instance); ++ + if (!HCL_ProcessReadings(phc->clock, n_readings, readings, &phc_ts, &sys_ts, &phc_err)) + return 0; + +diff --git a/refclock_pps.c b/refclock_pps.c +index 880c13fc..f00b7ccb 100644 +--- a/refclock_pps.c ++++ b/refclock_pps.c +@@ -143,6 +143,8 @@ static int pps_poll(RCL_Instance instance) + + pps->last_seq = seq; + ++ RCL_UpdateReachability(instance); ++ + return RCL_AddPulse(instance, &ts, 1.0e-9 * ts.tv_nsec); + } + +diff --git a/refclock_shm.c b/refclock_shm.c +index ee13e871..22e51820 100644 +--- a/refclock_shm.c ++++ b/refclock_shm.c +@@ -109,6 +109,8 @@ static int shm_poll(RCL_Instance instance) + + shm->valid = 0; + ++ RCL_UpdateReachability(instance); ++ + receive_ts.tv_sec = t.receiveTimeStampSec; + clock_ts.tv_sec = t.clockTimeStampSec; + +diff --git a/refclock_sock.c b/refclock_sock.c +index 2da57ef5..49cf3559 100644 +--- a/refclock_sock.c ++++ b/refclock_sock.c +@@ -129,6 +129,8 @@ static void read_sample(int sockfd, int event, void *anything) + UTI_TimevalToTimespec(&sample.tv, &sys_ts); + UTI_NormaliseTimespec(&sys_ts); + ++ RCL_UpdateReachability(instance); ++ + if (!UTI_IsTimeOffsetSane(&sys_ts, sample.offset)) + return; + +diff --git a/test/simulation/106-refclock b/test/simulation/106-refclock +index dedab9b8..3793bd86 100755 +--- a/test/simulation/106-refclock ++++ b/test/simulation/106-refclock +@@ -114,6 +114,32 @@ Root delay : 0\.000000001 seconds + rm -f tmp/refclocks.log + fi + ++export CLKNETSIM_PHC_JITTER_OFF=$[2 * 25 * 492] ++export CLKNETSIM_PHC_JITTER_ON=$[2 * 25 * 8] ++export CLKNETSIM_PHC_JITTER=1e-6 ++refclock_offset=0.0 ++refclock_jitter=1e-9 ++min_sync_time=5 ++max_sync_time=7 ++time_max_limit=1e-7 ++time_rms_limit=1e-8 ++client_conf="refclock PHC /dev/ptp0:nocrossts poll 0 ++logdir tmp ++log refclocks" ++chronyc_start=500 ++chronyc_conf="sources" ++ ++run_test || test_fail ++check_chronyd_exit || test_fail ++check_source_selection || test_fail ++check_sync || test_fail ++check_chronyc_output "^MS.* ++=* ++#\* PHC0 0 0 377 8 .*$" || test_fail ++ ++unset CLKNETSIM_PHC_JITTER_OFF ++unset CLKNETSIM_PHC_JITTER_ON ++export CLKNETSIM_PHC_JITTER=1e-7 + refclock_offset="(+ 0.399 (sum 1e-3))" + refclock_jitter=1e-6 + servers=1 +diff -up chrony/doc/chronyc.man.orig chrony/doc/chronyc.man +--- chrony/doc/chronyc.man.in.orig 2024-11-06 12:07:50.555216174 +0100 ++++ chrony/doc/chronyc.man.in 2024-11-06 12:07:58.131217759 +0100 +@@ -535,9 +535,12 @@ the polling rate in response to prevaili + \fBReach\fP + .RS 4 + This shows the source\(cqs reachability register printed as an octal number. The +-register has 8 bits and is updated on every received or missed packet from +-the source. A value of 377 indicates that a valid reply was received for all +-from the last eight transmissions. ++register has 8 bits. It is shifted to left by one bit with each poll and it is ++updated by 1 when a valid NTP response, or just a sample in case of a reference ++clock, is received from the source. A value of 377 indicates that a valid ++response or sample was received for all of the last 8 polls. Note that samples ++can be dropped if they are not considered good enough for synchronisation, but ++the reachability register will still have 1s for their polls. + .RE + .sp + \fBLastRx\fP diff --git a/SOURCES/chrony-serverstats.patch b/SOURCES/chrony-serverstats.patch deleted file mode 100644 index a5131fe..0000000 --- a/SOURCES/chrony-serverstats.patch +++ /dev/null @@ -1,39 +0,0 @@ -commit e11b518a1ffa704986fb1f1835c425844ba248ef -Author: Miroslav Lichvar -Date: Mon Jan 8 11:35:56 2024 +0100 - - ntp: fix authenticated requests in serverstats - - Fix the CLG_UpdateNtpStats() call to count requests passing the - authentication check instead of requests triggering a KoD response - (i.e. NTS NAK). - -diff --git a/ntp_core.c b/ntp_core.c -index 023e60b2..35801744 100644 ---- a/ntp_core.c -+++ b/ntp_core.c -@@ -2736,7 +2736,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a - CLG_DisableNtpTimestamps(&ntp_rx); - } - -- CLG_UpdateNtpStats(kod != 0 && info.auth.mode != NTP_AUTH_NONE && -+ CLG_UpdateNtpStats(kod == 0 && info.auth.mode != NTP_AUTH_NONE && - info.auth.mode != NTP_AUTH_MSSNTP, - rx_ts->source, interleaved ? tx_ts->source : NTP_TS_DAEMON); - -diff --git a/test/system/010-nts b/test/system/010-nts -index 8d92bbc8..b215efa3 100755 ---- a/test/system/010-nts -+++ b/test/system/010-nts -@@ -45,6 +45,11 @@ check_chronyc_output "^Name/IP address Mode KeyID Type KLen Last Atm - ========================================================================= - 127\.0\.0\.1 NTS 1 (30|15) (128|256) [0-9] 0 0 [78] ( 64|100)$" || test_fail - -+run_chronyc "serverstats" || test_fail -+check_chronyc_output "NTS-KE connections accepted: 1 -+NTS-KE connections dropped : 0 -+Authenticated NTP packets : [1-9][0-9]*" || test_fail -+ - stop_chronyd || test_fail - check_chronyd_messages || test_fail - check_chronyd_files || test_fail diff --git a/SOURCES/chrony-sourcedir.patch b/SOURCES/chrony-sourcedir.patch new file mode 100644 index 0000000..8ccd708 --- /dev/null +++ b/SOURCES/chrony-sourcedir.patch @@ -0,0 +1,279 @@ +commit d6aab8da1533b169385c749f8d1320c2b568a149 +Author: Miroslav Lichvar +Date: Mon Jun 2 10:53:47 2025 +0200 + + conf: fix sourcedir reloading to not multiply sources + + The sourcedir reload triggered by the chronyc "reload sources" + command incorrectly assumed that NSR_AddSourceByName() can return + only the NSR_Success status when a source is added. It ignored the + NSR_UnresolvedName status returned for a source whose name needs to + be resolved after the call (i.e. not specified with an IP address) + and added the source again, effectively multiplying it if the name + can be resolved to a different IP address. + + Fix the code to check for the NSR_UnresolvedName status to correctly + determine whether the source was already added before and should not be + added again. + + Reported-by: MichaelR + Fixes: 916ed70c4a81 ("conf: save source status in sourcedir reload") + +diff --git a/conf.c b/conf.c +index cbb11304..59a2e5c9 100644 +--- a/conf.c ++++ b/conf.c +@@ -1742,8 +1742,8 @@ reload_source_dirs(void) + NTP_Source *prev_sources, *new_sources, *source; + unsigned int i, j, prev_size, new_size, unresolved; + char buf[MAX_LINE_LENGTH]; ++ int d, pass, was_added; + NSR_Status s; +- int d, pass; + + /* Ignore reload command before adding configured sources */ + if (!conf_ntp_sources_added) +@@ -1782,13 +1782,16 @@ reload_source_dirs(void) + else + d = i < prev_size ? -1 : 1; + ++ was_added = d <= 0 && (prev_sources[i].status == NSR_Success || ++ prev_sources[i].status == NSR_UnresolvedName); ++ + /* Remove missing sources before adding others to avoid conflicts */ +- if (pass == 0 && d < 0 && prev_sources[i].status == NSR_Success) { ++ if (pass == 0 && d < 0 && was_added) { + NSR_RemoveSourcesById(prev_sources[i].conf_id); + } + + /* Add new sources and sources that could not be added before */ +- if (pass == 1 && (d > 0 || (d == 0 && prev_sources[i].status != NSR_Success))) { ++ if (pass == 1 && (d > 0 || (d == 0 && !was_added))) { + source = &new_sources[j]; + s = NSR_AddSourceByName(source->params.name, source->params.family, source->params.port, + source->pool, source->type, &source->params.params, + +commit 778331092436c2f2077a7d0b6253ca1771fb8e27 +Author: Miroslav Lichvar +Date: Tue Jun 3 10:58:00 2025 +0200 + + test: add 149-sourcedir test + +diff --git a/test/simulation/149-sourcedir b/test/simulation/149-sourcedir +new file mode 100755 +index 00000000..77b8499f +--- /dev/null ++++ b/test/simulation/149-sourcedir +@@ -0,0 +1,189 @@ ++#!/usr/bin/env bash ++ ++. ./test.common ++ ++test_start "sourcedir directive" ++ ++check_config_h 'FEAT_CMDMON 1' || test_skip ++ ++servers=4 ++limit=191 ++update_executable="tmp/update-sourcedir" ++client_server_conf="sourcedir tmp" ++base_delay="(+ 1e-4 (* 5 (equal 0.1 from $[servers + 2])))" ++chronyc_start=1 ++chronyc_conf="timeout 6000 ++activity ++$(for i in $(seq 1 18); do echo "reload sources"; echo activity; done)" ++ ++cat > tmp/sources.sources < tmp/update-sourcedir < tmp/sources.sources ++EOF ++chmod 755 tmp/update-sourcedir ++ ++run_test || test_fail ++check_chronyd_exit || test_fail ++ ++check_log_messages "T00:0.:[135].Z \(Added\|Removed\)" 0 0 || test_fail ++check_log_messages "T00:0.:..Z Added pool nodes-1-2-3-4\." 3 3 || test_fail ++check_log_messages "T00:0.:..Z Removed pool nodes-1-2-3-4\." 3 3 || test_fail ++check_log_messages "T00:0.:..Z Added pool nodes-1-2-3\." 1 1 || test_fail ++check_log_messages "T00:0.:..Z Removed pool nodes-1-2-3\." 1 1 || test_fail ++check_log_messages "T00:0.:..Z Added source ID#" 2 2 || test_fail ++check_log_messages "T00:0.:..Z Added source 192.168.123.[1234]" 2 2 || test_fail ++check_log_messages "T00:0.:..Z Removed source 192.168.123.[1234]" 4 4 || test_fail ++ ++check_chronyc_output "^200 OK ++0 sources online ++0 sources offline ++4 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++4 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++4 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++4 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++3 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++3 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++3 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++5 sources with unknown address ++200 OK ++200 OK ++3 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++5 sources with unknown address ++200 OK ++200 OK ++4 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++5 sources with unknown address ++200 OK ++200 OK ++4 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++5 sources with unknown address ++200 OK ++200 OK ++1 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++1 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++1 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++1 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++1 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++1 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++1 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++1 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address ++200 OK ++200 OK ++0 sources online ++0 sources offline ++0 sources doing burst \(return to online\) ++0 sources doing burst \(return to offline\) ++0 sources with unknown address$" || test_fail ++ ++check_packet_interval || test_fail ++ ++test_pass +diff --git a/test/simulation/test.common b/test/simulation/test.common +index 42a2917b..7eb348e3 100644 +--- a/test/simulation/test.common ++++ b/test/simulation/test.common +@@ -39,6 +39,7 @@ default_refclock_jitter="" + default_refclock_offset=0.0 + + default_update_interval=0 ++default_update_executable="" + default_shift_pll=2 + + default_server_strata=1 +@@ -442,7 +443,9 @@ run_simulation() { + -o tmp/log.offset -f tmp/log.freq -p tmp/log.packets \ + -R $(awk "BEGIN {print $update_interval < 0 ? 2^-($update_interval) : 1}") \ + -r $(awk "BEGIN {print $max_sync_time * 2^$update_interval}") \ +- -l $(awk "BEGIN {print $limit * 2^$update_interval}") && test_ok || test_error ++ -l $(awk "BEGIN {print $limit * 2^$update_interval}") \ ++ $([ "$update_executable" != "" ] && printf "%s" "-e $update_executable") && \ ++ test_ok || test_error + } + + run_test() { diff --git a/SOURCES/clknetsim-revert-phc.patch b/SOURCES/clknetsim-revert-phc.patch new file mode 100644 index 0000000..65c2ae3 --- /dev/null +++ b/SOURCES/clknetsim-revert-phc.patch @@ -0,0 +1,64 @@ +commit 1205197f2e15166a47fa1817feaf3587738fb37a +Author: Miroslav Lichvar +Date: Wed Nov 27 16:03:19 2024 +0100 + + avoid timestamps from future in PTP_SYS_OFFSET_EXTENDED + +diff --git a/client.c b/client.c +index 065eddf..32796e0 100644 +--- a/client.c ++++ b/client.c +@@ -2065,24 +2065,24 @@ int ioctl(int fd, unsigned long request, ...) { + } else if (request == PTP_SYS_OFFSET_EXTENDED && fd == REFCLK_FD) { + struct ptp_sys_offset_extended *sys_off = va_arg(ap, struct ptp_sys_offset_extended *); + struct timespec ts, ts1, ts2; ++ double delay; + int i; + + if (sys_off->n_samples > PTP_MAX_SAMPLES) + sys_off->n_samples = PTP_MAX_SAMPLES; + + for (i = 0; i < sys_off->n_samples; i++) { ++ clock_gettime(CLOCK_REALTIME, &ts2); + clock_gettime(REFCLK_ID, &ts); +- sys_off->ts[i][1].sec = ts.tv_sec; +- sys_off->ts[i][1].nsec = ts.tv_nsec; +- } +- +- clock_gettime(CLOCK_REALTIME, &ts); +- for (i = 0; i < sys_off->n_samples; i++) { +- ts1 = ts, ts2 = ts; +- add_to_timespec(&ts1, -get_phc_delay(-1)); +- add_to_timespec(&ts2, get_phc_delay(1)); ++ delay = get_phc_delay(1); ++ add_to_timespec(&ts, -delay); ++ delay += get_phc_delay(-1); ++ ts1 = ts2; ++ add_to_timespec(&ts1, -delay); + sys_off->ts[i][0].sec = ts1.tv_sec; + sys_off->ts[i][0].nsec = ts1.tv_nsec; ++ sys_off->ts[i][1].sec = ts.tv_sec; ++ sys_off->ts[i][1].nsec = ts.tv_nsec; + sys_off->ts[i][2].sec = ts2.tv_sec; + sys_off->ts[i][2].nsec = ts2.tv_nsec; + } + +commit 8b8831d98df1fca21288a9bc18c6a8fbfe6874a6 +Author: Miroslav Lichvar +Date: Wed Nov 27 16:06:40 2024 +0100 + + round nanoseconds in PTP_SYS_OFFSET* delay adjustments + +diff --git a/client.c b/client.c +index 32796e0..0e235a6 100644 +--- a/client.c ++++ b/client.c +@@ -794,7 +794,7 @@ static void normalize_timespec(struct timespec *tp) { + + static void add_to_timespec(struct timespec *tp, double offset) { + tp->tv_sec += floor(offset); +- tp->tv_nsec += (offset - floor(offset)) * 1e9; ++ tp->tv_nsec += round((offset - floor(offset)) * 1e9); + normalize_timespec(tp); + } + diff --git a/SPECS/chrony.spec b/SPECS/chrony.spec index 64204c7..058db35 100644 --- a/SPECS/chrony.spec +++ b/SPECS/chrony.spec @@ -1,5 +1,5 @@ %global _hardened_build 1 -%global clknetsim_ver 5d1dc0 +%global clknetsim_ver cdd694 %bcond_without debug %bcond_without nts @@ -8,8 +8,8 @@ %endif Name: chrony -Version: 4.5 -Release: 1%{?dist} +Version: 4.6.1 +Release: 2%{?dist} Summary: An NTP client/server License: GPLv2 @@ -29,8 +29,19 @@ Patch1: chrony-nm-dispatcher-dhcp.patch Patch2: chrony-keys.patch # revert some hardening options in service files Patch3: chrony-services.patch -# fix serverstats to correctly count authenticated packets -Patch4: chrony-serverstats.patch +# revert upstream changes in packaged configuration examples +Patch4: chrony-defconfig.patch +# keep PHC refclock reachable when dropping samples due to high delay +Patch5: chrony-refclkreach.patch +# improve description of refresh directive +Patch6: chrony-docrefresh.patch +# improve logging of selection failures +Patch7: chrony-logselect.patch +# fix sourcedir reloading to not multiply sources +Patch8: chrony-sourcedir.patch + +# revert clknetsim changes in PHC breaking old refclock tests +Patch20: clknetsim-revert-phc.patch BuildRequires: gnutls-devel libcap-devel libedit-devel pps-tools-devel BuildRequires: gcc gcc-c++ make bison systemd gnupg2 @@ -61,10 +72,18 @@ service to other computers in the network. %{gpgverify} --keyring=%{SOURCE2} --signature=%{SOURCE1} --data=%{SOURCE0} %setup -q -n %{name}-%{version}%{?prerelease} -a 10 %{?gitpatch:%patch0 -p1} -%patch1 -p1 -b .nm-dispatcher-dhcp -%patch2 -p1 -b .keys -%patch3 -p1 -b .services -%patch4 -p1 -b .serverstats +%patch -P 1 -p1 -b .nm-dispatcher-dhcp +%patch -P 2 -p1 -b .keys +%patch -P 3 -p1 -b .services +%patch -P 4 -p1 -b .defconfig +%patch -P 5 -p1 +%patch -P 6 -p1 -b .docrefresh +%patch -P 7 -p1 +%patch -P 8 -p1 + +pushd clknetsim-*-%{clknetsim_ver}* +%patch -P 20 -R -p1 +popd %{?gitpatch: echo %{version}-%{gitpatch} > version.txt} @@ -217,6 +236,27 @@ fi %dir %attr(750,chrony,chrony) %{_localstatedir}/log/chrony %changelog +* Wed Jun 04 2025 Miroslav Lichvar 4.6.1-2 +- improve description of refresh directive (RHEL-82096) +- improve logging of selection failures (RHEL-80388 RHEL-80413 RHEL-80415) +- fix sourcedir reloading to not multiply sources (RHEL-95016) +- switch from patchX to patch -P X + +* Wed Nov 06 2024 Miroslav Lichvar 4.6.1-1 +- update to 4.6.1 (RHEL-61877) +- keep PHC refclock reachable when dropping samples due to high delay + (RHEL-65421) + +* Thu Sep 05 2024 Miroslav Lichvar 4.6-1 +- update to 4.6 (RHEL-56964) + +* Thu Aug 08 2024 Miroslav Lichvar 4.5-3 +- don't repeat error log messages when reloading sourcedir (RHEL-51786) +- add support for leap-seconds.list file (RHEL-53484) + +* Thu Jun 13 2024 Miroslav Lichvar 4.5-2 +- fix crash on reload command during start (RHEL-28945) + * Tue Jan 09 2024 Miroslav Lichvar 4.5-1 - update to 4.5 (RHEL-6522 RHEL-6520 RHEL-9969 RHEL-9971 RHEL-9973 RHEL-9975 RHEL-12411)