]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
smooth: add option to smooth out only leap seconds
authorMiroslav Lichvar <mlichvar@redhat.com>
Tue, 2 Jun 2015 11:24:04 +0000 (13:24 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Tue, 2 Jun 2015 13:24:01 +0000 (15:24 +0200)
The leaponly option can be used to enable a mode where only leap seconds
are smoothed out and normal offset/frequency changes are ignored. This
is useful to make the interval in which a leap second is smoothed out
constant and allow an NTP client to use multiple leap smearing servers
safely.

conf.c
conf.h
local.c
smooth.c
smooth.h
test/simulation/113-leapsecond

diff --git a/conf.c b/conf.c
index 513633f75edc7a6392e7046255e3f832ade5a949..a83d937ca0272708c540ad38fabc495a55370a10 100644 (file)
--- a/conf.c
+++ b/conf.c
@@ -189,6 +189,7 @@ static char *pidfile;
 /* Smoothing constants */
 static double smooth_max_freq = 0.0; /* in ppm */
 static double smooth_max_wander = 0.0; /* in ppm/s */
+static int smooth_leap_only = 0;
 
 /* Temperature sensor, update interval and compensation coefficients */
 static char *tempcomp_sensor_file = NULL;
@@ -1174,11 +1175,23 @@ parse_broadcast(char *line)
 static void
 parse_smoothtime(char *line)
 {
-  check_number_of_args(line, 2);
+  if (get_number_of_args(line) != 3)
+    check_number_of_args(line, 2);
+
   if (sscanf(line, "%lf %lf", &smooth_max_freq, &smooth_max_wander) != 2) {
     smooth_max_freq = 0.0;
     command_parse_error();
   }
+
+  line = CPS_SplitWord(CPS_SplitWord(line));
+  smooth_leap_only = 0;
+
+  if (*line) {
+    if (!strcasecmp(line, "leaponly"))
+      smooth_leap_only = 1;
+    else
+      command_parse_error();
+  }
 }
 
 /* ================================================== */
@@ -1738,10 +1751,11 @@ CNF_GetLockMemory(void)
 /* ================================================== */
 
 void
-CNF_GetSmooth(double *max_freq, double *max_wander)
+CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only)
 {
   *max_freq = smooth_max_freq;
   *max_wander = smooth_max_wander;
+  *leap_only = smooth_leap_only;
 }
 
 /* ================================================== */
diff --git a/conf.h b/conf.h
index 4d51d2422113a37a3dd189eae166f652086d2c82..ec08ded6e63e269e23e76ecad40d6eb62ec44f5e 100644 (file)
--- a/conf.h
+++ b/conf.h
@@ -96,7 +96,7 @@ extern void CNF_SetupAccessRestrictions(void);
 extern int CNF_GetSchedPriority(void);
 extern int CNF_GetLockMemory(void);
 
-extern void CNF_GetSmooth(double *max_freq, double *max_wander);
+extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only);
 extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
 
 extern char *CNF_GetUser(void);
diff --git a/local.c b/local.c
index 53abf99a05945a1fd0c0d02a3c1459688f679af9..848cc3edf1e8feeb822e57780c14dadba386683f 100644 (file)
--- a/local.c
+++ b/local.c
@@ -564,6 +564,9 @@ LCL_NotifyLeap(int leap)
   LCL_ReadRawTime(&raw);
   LCL_CookTime(&raw, &cooked, NULL);
 
+  /* Smooth the leap second out */
+  SMT_Leap(&cooked, leap);
+
   /* Dispatch to all handlers as if the clock was stepped */
   invoke_parameter_change_handlers(&raw, &cooked, 0.0, -leap, LCL_ChangeStep);
 }
index dc145da1af1a1c4e12a0232e154b849e6cd38711..e5c60f4e1eadd3ff8c00454780c5d8626c817a33 100644 (file)
--- a/smooth.c
+++ b/smooth.c
@@ -77,6 +77,10 @@ static struct stage stages[NUM_STAGES];
 /* Enabled/disabled smoothing */
 static int enabled;
 
+/* Enabled/disabled mode where only leap seconds are smoothed out and normal
+   offset/frequency changes are ignored */
+static int leap_only_mode;
+
 /* Maximum skew/max_wander ratio to start updating offset and frequency */
 #define UNLOCK_SKEW_WANDER_RATIO 10000
 
@@ -185,8 +189,9 @@ update_smoothing(struct timeval *now, double offset, double freq)
 {
   /* Don't accept offset/frequency until the clock has stabilized */
   if (locked) {
-    if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO) {
-      LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated");
+    if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO || leap_only_mode) {
+      LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated%s", leap_only_mode ?
+          " (leap seconds only)" : "");
       locked = 0;
     }
     return;
@@ -208,15 +213,19 @@ handle_slew(struct timeval *raw, struct timeval *cooked, double dfreq,
 {
   double delta;
 
-  if (change_type == LCL_ChangeAdjust)
-    update_smoothing(cooked, doffset, dfreq);
+  if (change_type == LCL_ChangeAdjust) {
+    if (leap_only_mode)
+      update_smoothing(cooked, 0.0, 0.0);
+    else
+      update_smoothing(cooked, doffset, dfreq);
+  }
 
   UTI_AdjustTimeval(&last_update, cooked, &last_update, &delta, dfreq, doffset);
 }
 
 void SMT_Initialise(void)
 {
-  CNF_GetSmooth(&max_freq, &max_wander);
+  CNF_GetSmooth(&max_freq, &max_wander, &leap_only_mode);
   if (max_freq <= 0.0 || max_wander <= 0.0) {
       enabled = 0;
       return;
@@ -265,3 +274,14 @@ SMT_Reset(struct timeval *now)
   smooth_freq = 0.0;
   last_update = *now;
 }
+
+void
+SMT_Leap(struct timeval *now, int leap)
+{
+  /* When the leap-only mode is disabled, the leap second will be accumulated
+     in handle_slew() as a normal offset */
+  if (!enabled || !leap_only_mode)
+    return;
+
+  update_smoothing(now, leap, 0.0);
+}
index c2877d676aedaad55d6ec2970ca481d23215f92c..4cb72d7b506626bb886df0c9adf32b1c5800aa08 100644 (file)
--- a/smooth.h
+++ b/smooth.h
@@ -37,4 +37,6 @@ extern double SMT_GetOffset(struct timeval *now);
 
 extern void SMT_Reset(struct timeval *now);
 
+extern void SMT_Leap(struct timeval *now, int leap);
+
 #endif
index af4b547b88a0c846c6c3575ee8e71188950d21b9..7d6700715077e1879df8dabb0ad56dc5bbac2bde 100755 (executable)
@@ -27,18 +27,20 @@ for leapmode in system step slew; do
        check_sync || test_fail
 done
 
-server_conf="refclock SHM 0 dpoll 10 poll 10
-leapsectz right/UTC
-leapsecmode slew
-smoothtime 400 0.001"
-client_conf="leapsecmode system"
-min_sync_time=230000
-max_sync_time=240000
-
-run_test || test_fail
-check_chronyd_exit || test_fail
-check_source_selection || test_fail
-check_packet_interval || test_fail
-check_sync || test_fail
+for smoothmode in "" "leaponly"; do
+       server_conf="refclock SHM 0 dpoll 10 poll 10
+       leapsectz right/UTC
+       leapsecmode slew
+       smoothtime 400 0.001 $smoothmode"
+       client_conf="leapsecmode system"
+       min_sync_time=230000
+       max_sync_time=240000
+
+       run_test || test_fail
+       check_chronyd_exit || test_fail
+       check_source_selection || test_fail
+       check_packet_interval || test_fail
+       check_sync || test_fail
+done
 
 test_pass