diff --git a/candm.h b/candm.h index a740aa2..5b7c8d2 100644 --- a/candm.h +++ b/candm.h @@ -243,6 +243,7 @@ typedef struct { #define REQ_ADDSRC_IBURST 0x4 #define REQ_ADDSRC_PREFER 0x8 #define REQ_ADDSRC_NOSELECT 0x10 +#define REQ_ADDSRC_TRUST 0x20 typedef struct { IPAddr ip_addr; @@ -478,6 +479,7 @@ typedef struct { #define RPY_SD_FLAG_NOSELECT 0x1 #define RPY_SD_FLAG_PREFER 0x2 +#define RPY_SD_FLAG_TRUST 0x4 typedef struct { IPAddr ip_addr; diff --git a/chrony.texi.in b/chrony.texi.in index 59caf74..73f9023 100644 --- a/chrony.texi.in +++ b/chrony.texi.in @@ -2720,6 +2720,10 @@ Prefer this source over sources without prefer option. @item noselect Never select this source. This is useful for monitoring or with sources which are not very accurate, but are locked with a PPS refclock. +@item trust +Assume time from this source is always true. It can't be rejected as a +falseticker in the source selection if sources that are specified without this +option don't agree with it. @item minsamples Set the minimum number of samples kept for this source. This overrides the @code{minsamples} directive (@pxref{minsamples directive}). @@ -3024,6 +3028,11 @@ Prefer this source over sources without prefer option. @item noselect Never select this source. This is particularly useful for monitoring. +@item trust +Assume time from this source is always true. It can't be rejected as a +falseticker in the source selection if sources that are specified without this +option don't agree with it. + @item minsamples Set the minimum number of samples kept for this source. This overrides the @code{minsamples} directive (@pxref{minsamples directive}). diff --git a/client.c b/client.c index d19ec84..aa7271a 100644 --- a/client.c +++ b/client.c @@ -1118,7 +1118,8 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line) (data.params.auto_offline ? REQ_ADDSRC_AUTOOFFLINE : 0) | (data.params.iburst ? REQ_ADDSRC_IBURST : 0) | (data.params.sel_options & SRC_SELECT_PREFER ? REQ_ADDSRC_PREFER : 0) | - (data.params.sel_options & SRC_SELECT_NOSELECT ? REQ_ADDSRC_NOSELECT : 0)); + (data.params.sel_options & SRC_SELECT_NOSELECT ? REQ_ADDSRC_NOSELECT : 0) | + (data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0)); result = 1; break; diff --git a/cmdmon.c b/cmdmon.c index bf22de9..ae2a10c 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -663,7 +663,8 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message) } tx_message->data.source_data.flags = htons((report.sel_options & SRC_SELECT_PREFER ? RPY_SD_FLAG_PREFER : 0) | - (report.sel_options & SRC_SELECT_NOSELECT ? RPY_SD_FLAG_NOSELECT : 0)); + (report.sel_options & SRC_SELECT_NOSELECT ? RPY_SD_FLAG_NOSELECT : 0) | + (report.sel_options & SRC_SELECT_TRUST ? RPY_SD_FLAG_TRUST : 0)); tx_message->data.source_data.reachability = htons(report.reachability); tx_message->data.source_data.since_sample = htonl(report.latest_meas_ago); tx_message->data.source_data.orig_latest_meas = UTI_FloatHostToNetwork(report.orig_latest_meas); @@ -758,7 +759,8 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m params.iburst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_IBURST ? 1 : 0; params.sel_options = (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_PREFER ? SRC_SELECT_PREFER : 0) | - (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NOSELECT ? SRC_SELECT_NOSELECT : 0); + (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NOSELECT ? SRC_SELECT_NOSELECT : 0) | + (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_TRUST ? SRC_SELECT_TRUST : 0); params.max_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay); params.max_delay_ratio = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio); diff --git a/cmdparse.c b/cmdparse.c index 51a9364..976e696 100644 --- a/cmdparse.c +++ b/cmdparse.c @@ -170,6 +170,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src) } else if (!strcasecmp(cmd, "prefer")) { src->params.sel_options |= SRC_SELECT_PREFER; + } else if (!strcasecmp(cmd, "trust")) { + src->params.sel_options |= SRC_SELECT_TRUST; + } else if (!strcasecmp(cmd, "version")) { if (sscanf(line, "%d%n", &src->params.version, &n) != 1) { result = CPS_BadVersion; diff --git a/conf.c b/conf.c index c556476..8260de6 100644 --- a/conf.c +++ b/conf.c @@ -743,6 +743,9 @@ parse_refclock(char *line) } else if (!strcasecmp(cmd, "prefer")) { n = 0; sel_options |= SRC_SELECT_PREFER; + } else if (!strcasecmp(cmd, "trust")) { + n = 0; + sel_options |= SRC_SELECT_TRUST; } else { other_parse_error("Invalid refclock option"); return; diff --git a/sources.c b/sources.c index c67cf51..2e48c5f 100644 --- a/sources.c +++ b/sources.c @@ -603,7 +603,8 @@ SRC_SelectSource(SRC_Instance updated_inst) struct timeval now, ref_time; int i, j, j1, j2, index, sel_prefer, n_endpoints, n_sel_sources; int n_badstats_sources, max_sel_reach, max_badstat_reach; - int depth, best_depth, combined, stratum, min_stratum, max_score_index; + int depth, best_depth, trust_depth, best_trust_depth; + int combined, stratum, min_stratum, max_score_index; 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; @@ -751,8 +752,12 @@ SRC_SelectSource(SRC_Instance updated_inst) The first case is just bad luck - we need extra sources to detect the falseticker, so just make an arbitrary choice based on stratum & stability etc. + + Intervals from sources specified with the trust option have higher + priority in the search. */ + trust_depth = best_trust_depth = 0; depth = best_depth = 0; best_lo = best_hi = 0.0; @@ -760,14 +765,20 @@ SRC_SelectSource(SRC_Instance updated_inst) switch (sort_list[i].tag) { case LOW: depth++; - if (depth > best_depth) { + if (sources[sort_list[i].index]->sel_options & SRC_SELECT_TRUST) + trust_depth++; + if (trust_depth > best_trust_depth || + (trust_depth == best_trust_depth && depth > best_depth)) { + best_trust_depth = trust_depth; best_depth = depth; best_lo = sort_list[i].offset; } break; case HIGH: - if (depth == best_depth) + if (trust_depth == best_trust_depth && depth == best_depth) best_hi = sort_list[i].offset; + if (sources[sort_list[i].index]->sel_options & SRC_SELECT_TRUST) + trust_depth--; depth--; break; default: @@ -775,9 +786,9 @@ SRC_SelectSource(SRC_Instance updated_inst) } } - if (best_depth <= n_sel_sources / 2) { - /* Could not even get half the reachable sources to agree - - clearly we can't synchronise. */ + if (best_depth <= n_sel_sources / 2 && !best_trust_depth) { + /* Could not even get half the reachable sources to agree and there + are no trusted sources - clearly we can't synchronise */ if (selected_source_index != INVALID_SOURCE) { log_selection_message("Can't synchronise: no majority", NULL); @@ -798,14 +809,17 @@ SRC_SelectSource(SRC_Instance updated_inst) n_sel_sources = 0; for (i = 0; i < n_sources; i++) { + /* This should be the same condition to get into the endpoint + list */ if (sources[i]->status != SRC_OK) continue; - /* This should be the same condition to get into the endpoint - list */ - /* Check if source's interval contains the best interval, or - is wholly contained within it */ - if ((sources[i]->sel_info.lo_limit <= best_lo && + /* Check if source's interval contains the best interval, or is wholly + contained within it. If there are any trusted sources the first + condition is applied only to them to not allow non-trusted sources to + move the final offset outside the interval. */ + if (((!best_trust_depth || sources[i]->sel_options & SRC_SELECT_TRUST) && + sources[i]->sel_info.lo_limit <= best_lo && sources[i]->sel_info.hi_limit >= best_hi) || (sources[i]->sel_info.lo_limit >= best_lo && sources[i]->sel_info.hi_limit <= best_hi)) { diff --git a/srcparams.h b/srcparams.h index 1e15af6..15fb6f2 100644 --- a/srcparams.h +++ b/srcparams.h @@ -66,5 +66,6 @@ typedef struct { /* Flags for source selection */ #define SRC_SELECT_NOSELECT 0x1 #define SRC_SELECT_PREFER 0x2 +#define SRC_SELECT_TRUST 0x4 #endif /* GOT_SRCPARAMS_H */