diff --git a/chrony.texi.in b/chrony.texi.in index d44399a..50cccfc 100644 --- a/chrony.texi.in +++ b/chrony.texi.in @@ -1152,6 +1152,7 @@ the configuration file is ignored. * manual directive:: Allow manual entry using chronyc's settime cmd * maxchange directive:: Set maximum allowed offset * maxclockerror directive:: Set maximum frequency error of local clock +* maxdistance directive:: Set maximum allowed distance of sources * maxsamples directive:: Set maximum number of samples per source * maxslewrate directive:: Set maximum slew rate * maxupdateskew directive:: Stop bad estimates upsetting machine clock @@ -2441,6 +2442,23 @@ Typical values for might be 10 for a low quality clock to 0.1 for a high quality clock using a temperature compensated crystal oscillator. @c }}} +@c {{{ maxdistance +@node maxdistance directive +@subsection maxdistance +The @code{maxdistance} directive sets the maximum allowed root distance of the +sources to not be rejected by the source selection algorithm. The distance +includes the accumulated dispersion, which may be large when the source is no +longer synchronised, and half of the total round-trip delay to the primary +source. + +By default, the maximum distance is 3 seconds. + +The syntax is + +@example +maxdistance +@end example +@c }}} @c {{{ maxsamples @node maxsamples directive @subsection maxsamples diff --git a/conf.c b/conf.c index 0d58b0e..25a5705 100644 --- a/conf.c +++ b/conf.c @@ -90,6 +90,7 @@ static double correction_time_ratio = 3.0; static double max_clock_error = 1.0; /* in ppm */ static double max_slew_rate = 1e6 / 12.0; /* in ppm */ +static double max_distance = 3.0; static double reselect_distance = 1e-4; static double stratum_weight = 1e-3; static double combine_limit = 3.0; @@ -477,6 +478,8 @@ CNF_ParseLine(const char *filename, int number, char *line) parse_maxchange(p); } else if (!strcasecmp(command, "maxclockerror")) { parse_double(p, &max_clock_error); + } else if (!strcasecmp(command, "maxdistance")) { + parse_double(p, &max_distance); } else if (!strcasecmp(command, "maxsamples")) { parse_int(p, &max_samples); } else if (!strcasecmp(command, "maxslewrate")) { @@ -1524,6 +1527,14 @@ CNF_GetMaxSlewRate(void) /* ================================================== */ +double +CNF_GetMaxDistance(void) +{ + return max_distance; +} + +/* ================================================== */ + double CNF_GetReselectDistance(void) { diff --git a/conf.h b/conf.h index d8e7cca..75f2764 100644 --- a/conf.h +++ b/conf.h @@ -86,6 +86,7 @@ extern double CNF_GetMaxClockError(void); extern double CNF_GetCorrectionTimeRatio(void); extern double CNF_GetMaxSlewRate(void); +extern double CNF_GetMaxDistance(void); extern double CNF_GetReselectDistance(void); extern double CNF_GetStratumWeight(void); extern double CNF_GetCombineLimit(void); diff --git a/sources.c b/sources.c index 4ddee25..017f3bc 100644 --- a/sources.c +++ b/sources.c @@ -70,6 +70,7 @@ typedef enum { SRC_OK, /* OK so far, not a final status! */ SRC_UNSELECTABLE, /* Has noselect option set */ SRC_BAD_STATS, /* Doesn't have valid stats data */ + SRC_BAD_DISTANCE, /* Has root distance longer than allowed maximum */ SRC_WAITS_STATS, /* Others have bad stats, selection postponed */ SRC_STALE, /* Has older samples than others */ SRC_FALSETICKER, /* Doesn't agree with others */ @@ -155,6 +156,7 @@ static int selected_source_index; /* Which source index is currently /* Number of updates needed to reset the distant status */ #define DISTANT_PENALTY 32 +static double max_distance; static double reselect_distance; static double stratum_weight; static double combine_limit; @@ -179,6 +181,7 @@ void SRC_Initialise(void) { n_sources = 0; max_n_sources = 0; selected_source_index = INVALID_SOURCE; + max_distance = CNF_GetMaxDistance(); reselect_distance = CNF_GetReselectDistance(); stratum_weight = CNF_GetStratumWeight(); combine_limit = CNF_GetCombineLimit(); @@ -653,6 +656,12 @@ SRC_SelectSource(SRC_Instance updated_inst) continue; } + /* Require the root distance to be below the allowed maximum */ + if (si->root_distance > max_distance) { + sources[i]->status = SRC_BAD_DISTANCE; + continue; + } + sources[i]->status = SRC_OK; /* For now */ if (sources[i]->reachability && max_reach_sample_ago < first_sample_ago) @@ -1216,6 +1225,7 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now) switch (src->status) { case SRC_UNSELECTABLE: case SRC_BAD_STATS: + case SRC_BAD_DISTANCE: case SRC_STALE: case SRC_WAITS_STATS: report->state = RPT_UNREACH; diff --git a/test/simulation/114-presend b/test/simulation/114-presend index e9fe66e..8872525 100755 --- a/test/simulation/114-presend +++ b/test/simulation/114-presend @@ -6,6 +6,7 @@ test_start "presend option" min_sync_time=140 max_sync_time=260 client_server_options="presend 6 maxdelay 16" +client_conf="maxdistance 10" run_test || test_fail check_chronyd_exit || test_fail