From 5039f959e0624a8e40269f71341a336dbe538bec Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Tue, 25 Aug 2015 16:27:36 +0200 Subject: [PATCH] sources: add option to limit selection by root distance Add maxdistance directive to set the maximum root distance the sources are allowed to have to be selected. This is useful to reject NTPv4 sources that are no longer synchronized and report large dispersion. The default value is 3 seconds. --- chrony.texi.in | 18 ++++++++++++++++++ conf.c | 11 +++++++++++ conf.h | 1 + sources.c | 10 ++++++++++ test/simulation/114-presend | 1 + 5 files changed, 41 insertions(+) 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