#define REQ_ADDSRC_PREFER 0x8
#define REQ_ADDSRC_NOSELECT 0x10
#define REQ_ADDSRC_TRUST 0x20
+#define REQ_ADDSRC_REQUIRE 0x40
typedef struct {
IPAddr ip_addr;
#define RPY_SD_FLAG_NOSELECT 0x1
#define RPY_SD_FLAG_PREFER 0x2
#define RPY_SD_FLAG_TRUST 0x4
+#define RPY_SD_FLAG_REQUIRE 0x8
typedef struct {
IPAddr ip_addr;
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 require
+Require that at least one of the sources specified with this option is
+selectable (i.e. recently reachable and not a falseticker) before updating the
+clock. Together with the @code{trust} option this may be useful to allow a
+trusted, but not very precise, reference clock to be safely combined with
+unauthenticated NTP sources in order to improve the accuracy of the clock.
+They can be selected and used for synchronisation only if they agree with
+the trusted and required source.
@item minsamples
Set the minimum number of samples kept for this source. This overrides the
@code{minsamples} directive (@pxref{minsamples directive}).
falseticker in the source selection if sources that are specified without this
option don't agree with it.
+@item require
+Require that at least one of the sources specified with this option is
+selectable (i.e. recently reachable and not a falseticker) before updating the
+clock. Together with the @code{trust} option this may be useful to allow a
+trusted authenticated source to be safely combined with unauthenticated sources
+in order to improve the accuracy of the clock. They can be selected and used
+for synchronisation only if they agree with the trusted and required source.
+
@item minsamples
Set the minimum number of samples kept for this source. This overrides the
@code{minsamples} directive (@pxref{minsamples directive}).
(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_TRUST ? REQ_ADDSRC_TRUST : 0));
+ (data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) |
+ (data.params.sel_options & SRC_SELECT_REQUIRE ? REQ_ADDSRC_REQUIRE : 0));
result = 1;
break;
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_TRUST ? RPY_SD_FLAG_TRUST : 0));
+ (report.sel_options & SRC_SELECT_TRUST ? RPY_SD_FLAG_TRUST : 0) |
+ (report.sel_options & SRC_SELECT_REQUIRE ? RPY_SD_FLAG_REQUIRE : 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);
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_TRUST ? SRC_SELECT_TRUST : 0);
+ (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_TRUST ? SRC_SELECT_TRUST : 0) |
+ (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_REQUIRE ? SRC_SELECT_REQUIRE : 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);
} else if (!strcasecmp(cmd, "trust")) {
src->params.sel_options |= SRC_SELECT_TRUST;
+ } else if (!strcasecmp(cmd, "require")) {
+ src->params.sel_options |= SRC_SELECT_REQUIRE;
+
} else if (!strcasecmp(cmd, "version")) {
if (sscanf(line, "%d%n", &src->params.version, &n) != 1) {
result = CPS_BadVersion;
} else if (!strcasecmp(cmd, "trust")) {
n = 0;
sel_options |= SRC_SELECT_TRUST;
+ } else if (!strcasecmp(cmd, "require")) {
+ n = 0;
+ sel_options |= SRC_SELECT_REQUIRE;
} else {
other_parse_error("Invalid refclock option");
return;
struct SelectInfo *si;
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 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;
double src_offset, src_offset_sd, src_frequency, src_skew;
n_endpoints = 0;
n_sel_sources = 0;
n_badstats_sources = 0;
+ sel_req_source = 0;
max_sel_reach = max_badstat_reach = 0;
max_reach_sample_ago = 0.0;
for (i = 0; i < n_sources; i++) {
assert(sources[i]->status != SRC_OK);
+ /* If some sources are specified with the require option, at least one
+ of them will have to be selectable in order to update the clock */
+ if (sources[i]->sel_options & SRC_SELECT_REQUIRE)
+ sel_req_source = 1;
+
/* Ignore sources which were added with the noselect option */
if (sources[i]->sel_options & SRC_SELECT_NOSELECT) {
sources[i]->status = SRC_UNSELECTABLE;
sources[i]->sel_info.hi_limit <= best_hi)) {
sel_sources[n_sel_sources++] = i;
+
+ if (sources[i]->sel_options & SRC_SELECT_REQUIRE)
+ sel_req_source = 0;
} else {
sources[i]->status = SRC_FALSETICKER;
}
}
- if (n_sel_sources == 0 || n_sel_sources < CNF_GetMinSources()) {
+ if (!n_sel_sources || sel_req_source || n_sel_sources < CNF_GetMinSources()) {
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: %s selectable sources",
- n_sel_sources ? "not enough" : "no");
+ !n_sel_sources ? "no" :
+ sel_req_source ? "no required source in" : "not enough");
selected_source_index = INVALID_SOURCE;
}
mark_ok_sources(SRC_WAITS_SOURCES);
#define SRC_SELECT_NOSELECT 0x1
#define SRC_SELECT_PREFER 0x2
#define SRC_SELECT_TRUST 0x4
+#define SRC_SELECT_REQUIRE 0x8
#endif /* GOT_SRCPARAMS_H */