reference: activate local reference with large root distance

Since the update to NTPv4, when the clock is in the synchronised state
and the clock updates stop (e.g. sources become unreachable), it doesn't
switch to the unsynchronised state and the local reference is never
activate. This can be a problem for clients that rely on the server to
always have root distance below some value (e.g. chronyd's maxdistance).

Add a timer that will activate the local reference when the root
distance reaches a specified threshold. It can be configured with the
distance option in the local directive (by default 1.0 second).
This commit is contained in:
Miroslav Lichvar 2016-03-30 17:12:12 +02:00
parent 981f897c96
commit 81f440a882
5 changed files with 55 additions and 6 deletions

View file

@ -224,12 +224,13 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
/* ================================================== */
int
CPS_ParseLocal(char *line, int *stratum)
CPS_ParseLocal(char *line, int *stratum, double *distance)
{
int n;
char *cmd;
*stratum = 10;
*distance = 1.0;
while (*line) {
cmd = line;
@ -238,6 +239,9 @@ CPS_ParseLocal(char *line, int *stratum)
if (!strcasecmp(cmd, "stratum")) {
if (sscanf(line, "%d%n", stratum, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "distance")) {
if (sscanf(line, "%lf%n", distance, &n) != 1)
return 0;
} else {
return 0;
}

View file

@ -60,7 +60,7 @@ typedef struct {
extern CPS_Status CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
/* Parse a command to enable local reference */
extern int CPS_ParseLocal(char *line, int *stratum);
extern int CPS_ParseLocal(char *line, int *stratum, double *distance);
/* Get a string describing error status */
extern void CPS_StatusToString(CPS_Status status, char *dest, int len);

6
conf.c
View file

@ -108,6 +108,7 @@ static char *dumpdir;
static int enable_local=0;
static int local_stratum;
static double local_distance;
/* Threshold (in seconds) - if absolute value of initial error is less
than this, slew instead of stepping */
@ -817,7 +818,7 @@ parse_log(char *line)
static void
parse_local(char *line)
{
if (!CPS_ParseLocal(line, &local_stratum))
if (!CPS_ParseLocal(line, &local_stratum, &local_distance))
command_parse_error();
enable_local = 1;
}
@ -1565,10 +1566,11 @@ CNF_GetCommandPort(void) {
/* ================================================== */
int
CNF_AllowLocalReference(int *stratum)
CNF_AllowLocalReference(int *stratum, double *distance)
{
if (enable_local) {
*stratum = local_stratum;
*distance = local_distance;
return 1;
} else {
return 0;

2
conf.h
View file

@ -92,7 +92,7 @@ extern double CNF_GetReselectDistance(void);
extern double CNF_GetStratumWeight(void);
extern double CNF_GetCombineLimit(void);
extern int CNF_AllowLocalReference(int *stratum);
extern int CNF_AllowLocalReference(int *stratum, double *distance);
extern void CNF_SetupAccessRestrictions(void);

View file

@ -45,6 +45,7 @@
static int are_we_synchronised;
static int enable_local_stratum;
static int local_stratum;
static double local_distance;
static NTP_Leap our_leap_status;
static int our_leap_sec;
static int our_stratum;
@ -112,6 +113,11 @@ static char *leap_tzname;
static time_t last_tz_leap_check;
static NTP_Leap tz_leap;
#define MAX_LOCAL_TIMEOUT (30 * 24 * 3600.0)
/* Timer for local reference */
static SCH_TimeoutID local_timeout_id;
/* ================================================== */
static LOG_FileID logfileid;
@ -230,7 +236,8 @@ REF_Initialise(void)
correction_time_ratio = CNF_GetCorrectionTimeRatio();
enable_local_stratum = CNF_AllowLocalReference(&local_stratum);
enable_local_stratum = CNF_AllowLocalReference(&local_stratum, &local_distance);
local_timeout_id = 0;
leap_timeout_id = 0;
leap_in_progress = 0;
@ -801,6 +808,38 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
/* ================================================== */
static void
local_timeout(void *arg)
{
local_timeout_id = 0;
REF_SetUnsynchronised();
}
/* ================================================== */
static void
update_local_timeout(void)
{
double delay;
SCH_RemoveTimeout(local_timeout_id);
local_timeout_id = 0;
if (!enable_local_stratum || !are_we_synchronised)
return;
/* Add a timer that will activate the local reference approximately at the
point when our root distance reaches the configured root distance */
delay = (local_distance - (our_root_delay / 2.0 + our_root_dispersion)) /
(our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError());
delay = CLAMP(0.0, delay, MAX_LOCAL_TIMEOUT);
local_timeout_id = SCH_AddTimeoutByDelay(delay, local_timeout, NULL);
DEBUG_LOG(LOGF_Reference, "Local reference timeout %f", delay);
}
/* ================================================== */
static void
write_log(struct timeval *ref_time, char *ref, int stratum, NTP_Leap leap,
double freq, double skew, double offset, int combined_sources,
@ -1063,6 +1102,9 @@ REF_SetReference(int stratum,
}
}
/* Update timer that activates the local reference */
update_local_timeout();
/* Update fallback drifts */
if (fb_drifts) {
update_fb_drifts(abs_freq_ppm, update_interval);
@ -1127,6 +1169,7 @@ REF_SetUnsynchronised(void)
update_leap_status(LEAP_Unsynchronised, 0, 0);
are_we_synchronised = 0;
update_local_timeout();
LCL_SetSyncStatus(0, 0.0, 0.0);