smooth: add option to smooth out only leap seconds
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.
This commit is contained in:
parent
31669f343a
commit
0abdc2a350
6 changed files with 61 additions and 20 deletions
16
conf.c
16
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
|
2
conf.h
2
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);
|
||||
|
|
3
local.c
3
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);
|
||||
}
|
||||
|
|
28
smooth.c
28
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)
|
||||
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);
|
||||
}
|
||||
|
|
2
smooth.h
2
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
|
||||
|
|
|
@ -27,10 +27,11 @@ for leapmode in system step slew; do
|
|||
check_sync || test_fail
|
||||
done
|
||||
|
||||
for smoothmode in "" "leaponly"; do
|
||||
server_conf="refclock SHM 0 dpoll 10 poll 10
|
||||
leapsectz right/UTC
|
||||
leapsecmode slew
|
||||
smoothtime 400 0.001"
|
||||
smoothtime 400 0.001 $smoothmode"
|
||||
client_conf="leapsecmode system"
|
||||
min_sync_time=230000
|
||||
max_sync_time=240000
|
||||
|
@ -40,5 +41,6 @@ check_chronyd_exit || test_fail
|
|||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
done
|
||||
|
||||
test_pass
|
||||
|
|
Loading…
Reference in a new issue