From 5a92dbe7840802d307f28bdce43b940c9c02be4f Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Wed, 30 Mar 2016 17:39:49 +0200 Subject: [PATCH] sources: add support for orphan sources When the local reference is configured with the orphan option, NTP sources that have stratum equal to the configured local stratum are considered to be orphans (i.e. serving local time while not being synchronised with real time) and are excluded from the normal source selection. Sources with stratum larger than the local stratum are considered to be directly on indirectly synchronised to an orphan and are always ignored. If no selectable source is available and all orphan sources have reference IDs larger than the local ID, no source will be selected and the local reference mode will be activated at some point, i.e. this host will become an orphan. Otherwise, the orphan source with the smallest reference ID will be selected. This ensures a group of servers polling each other (with the same orphan configuration) which have no external source can settle down to a state where only one server is serving its local unsychronised time and others are synchronised to it. --- sources.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/sources.c b/sources.c index 28fc16b..df3f7a0 100644 --- a/sources.c +++ b/sources.c @@ -73,6 +73,7 @@ typedef enum { 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_ORPHAN, /* Has stratum equal or larger than orphan stratum */ SRC_FALSETICKER, /* Doesn't agree with others */ SRC_JITTERY, /* Scatter worse than other's dispersion (not used) */ SRC_WAITS_SOURCES, /* Not enough sources, selection postponed */ @@ -607,6 +608,7 @@ SRC_SelectSource(SRC_Instance updated_inst) int n_badstats_sources, max_sel_reach, max_badstat_reach, sel_req_source; int depth, best_depth, trust_depth, best_trust_depth; int combined, stratum, min_stratum, max_score_index; + int orphan_stratum, orphan_source; double src_offset, src_offset_sd, src_frequency, src_skew; double src_root_delay, src_root_dispersion; double best_lo, best_hi, distance, sel_src_distance, max_score; @@ -680,6 +682,9 @@ SRC_SelectSource(SRC_Instance updated_inst) max_sel_reach = sources[i]->reachability; } + orphan_stratum = REF_GetOrphanStratum(); + orphan_source = INVALID_SOURCE; + for (i = 0; i < n_sources; i++) { if (sources[i]->status != SRC_OK) continue; @@ -694,7 +699,52 @@ SRC_SelectSource(SRC_Instance updated_inst) continue; } + /* When the local reference is configured with the orphan option, NTP + sources that have stratum equal to the configured local stratum are + considered to be orphans (i.e. serving local time while not being + synchronised with real time) and are excluded from the normal source + selection. Sources with stratum larger than the local stratum are + considered to be directly on indirectly synchronised to an orphan and + are always ignored. + + If no selectable source is available and all orphan sources have + reference IDs larger than the local ID, no source will be selected and + the local reference mode will be activated at some point, i.e. this host + will become an orphan. Otherwise, the orphan source with the smallest + reference ID will be selected. This ensures a group of servers polling + each other (with the same orphan configuration) which have no external + source can settle down to a state where only one server is serving its + local unsychronised time and others are synchronised to it. */ + + if (si->stratum >= orphan_stratum && sources[i]->type == SRC_NTP) { + sources[i]->status = SRC_ORPHAN; + + if (si->stratum == orphan_stratum && + (orphan_source == INVALID_SOURCE || + sources[i]->ref_id < sources[orphan_source]->ref_id)) + orphan_source = i; + + continue; + } + ++n_sel_sources; + } + + /* If no selectable source is available, consider the orphan source */ + if (!n_sel_sources && orphan_source != INVALID_SOURCE && + sources[orphan_source]->ref_id < + NSR_GetLocalRefid(sources[orphan_source]->ip_addr)) { + sources[orphan_source]->status = SRC_OK; + n_sel_sources = 1; + DEBUG_LOG(LOGF_Sources, "selecting orphan refid=%"PRIx32, + sources[orphan_source]->ref_id); + } + + for (i = 0; i < n_sources; i++) { + if (sources[i]->status != SRC_OK) + continue; + + si = &sources[i]->sel_info; j1 = n_endpoints; j2 = j1 + 1; @@ -1254,6 +1304,7 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now) case SRC_BAD_STATS: case SRC_BAD_DISTANCE: case SRC_STALE: + case SRC_ORPHAN: case SRC_WAITS_STATS: report->state = RPT_UNREACH; break;