int32_t filter_length;
uint32_t cert_set;
Float max_delay_quant;
- uint32_t reserved[1];
+ int32_t max_unreach;
int32_t EOR;
} REQ_NTP_Source;
msg->data.ntp_source.cert_set = htonl(data.params.cert_set);
msg->data.ntp_source.max_delay_quant =
UTI_FloatHostToNetwork(data.params.max_delay_quant);
- memset(msg->data.ntp_source.reserved, 0, sizeof (msg->data.ntp_source.reserved));
+ msg->data.ntp_source.max_unreach = htonl(data.params.max_unreach);
result = 1;
params.max_sources = ntohl(rx_message->data.ntp_source.max_sources);
params.min_samples = ntohl(rx_message->data.ntp_source.min_samples);
params.max_samples = ntohl(rx_message->data.ntp_source.max_samples);
+ params.max_unreach = ntohl(rx_message->data.ntp_source.max_unreach);
params.filter_length = ntohl(rx_message->data.ntp_source.filter_length);
params.authkey = ntohl(rx_message->data.ntp_source.authkey);
params.nts_port = ntohl(rx_message->data.ntp_source.nts_port);
src->params.max_sources = SRC_DEFAULT_MAXSOURCES;
src->params.min_samples = SRC_DEFAULT_MINSAMPLES;
src->params.max_samples = SRC_DEFAULT_MAXSAMPLES;
+ src->params.max_unreach = SRC_DEFAULT_MAXUNREACH;
src->params.filter_length = 0;
src->params.interleaved = 0;
src->params.sel_options = 0;
} else if (!strcasecmp(cmd, "maxsources")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.max_sources, &n, 1, INT_MAX))
return CPS_InvalidValue;
+ } else if (!strcasecmp(cmd, "maxunreach")) {
+ if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.max_unreach, &n, 0, INT_MAX))
+ return CPS_InvalidValue;
} else if (!strcasecmp(cmd, "mindelay")) {
if (sscanf(line, "%lf%n", &src->params.min_delay, &n) != 1)
return CPS_InvalidValue;
parse_refclock(char *line)
{
int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples, sel_options;
- int local, max_lock_age, pps_forced, sel_option, stratum, tai;
+ int local, max_lock_age, max_unreach, pps_forced, sel_option, stratum, tai;
uint32_t ref_id, lock_ref_id;
double offset, delay, precision, max_dispersion, pulse_width;
char *p, *cmd, *name, *param;
pps_rate = 0;
min_samples = SRC_DEFAULT_MINSAMPLES;
max_samples = SRC_DEFAULT_MAXSAMPLES;
+ max_unreach = SRC_DEFAULT_MAXUNREACH;
sel_options = 0;
offset = 0.0;
delay = 1e-9;
} else if (!strcasecmp(cmd, "maxsamples")) {
if (!SSCANF_IN_RANGE(line, "%d%n", &max_samples, &n, 0, INT_MAX))
break;
+ } else if (!strcasecmp(cmd, "maxunreach")) {
+ if (!SSCANF_IN_RANGE(line, "%d%n", &max_unreach, &n, 0, INT_MAX))
+ break;
} else if (!strcasecmp(cmd, "offset")) {
if (sscanf(line, "%lf%n", &offset, &n) != 1)
break;
refclock->pps_rate = pps_rate;
refclock->min_samples = min_samples;
refclock->max_samples = max_samples;
+ refclock->max_unreach = max_unreach;
refclock->sel_options = sel_options;
refclock->stratum = stratum;
refclock->tai = tai;
*maxsamples* _samples_:::
Set the maximum number of samples kept for this source. This overrides the
<<maxsamples,*maxsamples*>> directive.
+*maxunreach* _polls_:::
+This option specifies the maximum number of polls that this source can stay
+selected for synchronisation when it is unreachable (i.e. no valid response was
+received to the last 8 requests). Only sources with at least one sample more
+recent than the oldest sample of all reachable sources can be selected. The
+default is 100000.
*filter* _polls_:::
This option enables a median filter to reduce noise in NTP measurements. The
filter will process samples collected in the specified number of polls
*maxsamples* _samples_:::
Set the maximum number of samples kept for this source. This overrides the
<<maxsamples,*maxsamples*>> directive.
+*maxunreach* _polls_:::
+This option specifies the maximum number of polls that this source can stay
+selected for synchronisation when it is unreachable (i.e. no valid sample was
+received in the last 8 polls). Only sources with at least one sample more
+recent than the oldest sample of all reachable sources can be selected.
+The default is 100000.
[[manual]]*manual*::
The *manual* directive enables support at run-time for the
* _~_ - has a jitter larger than the maximum jitter (configured by the
<<chrony.conf.adoc#maxjitter,*maxjitter*>> directive).
* _w_ - waits for other sources to get out of the _M_ state.
-* _S_ - has older measurements than other sources.
+* _S_ - has only measurements older than reachable sources, or is unreachable
+ for too many polls (configured by the *maxunreach* option).
* _O_ - has a stratum equal or larger than the orphan stratum (configured by
the <<chrony.conf.adoc#local,*local*>> directive).
* _T_ - does not fully agree with sources that have the *trust* option.
SRC_NTP, NAU_IsAuthEnabled(result->auth),
params->sel_options, &result->remote_addr.ip_addr,
params->min_samples, params->max_samples,
- params->min_delay, params->asymmetry);
+ params->min_delay, params->asymmetry,
+ params->max_unreach);
if (params->max_delay_quant > 0.0) {
int k = round(CLAMP(0.05, params->max_delay_quant, 0.95) * DELAY_QUANT_Q);
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, 0, params->sel_options,
NULL, params->min_samples, params->max_samples,
- 0.0, 0.0);
+ 0.0, 0.0, params->max_unreach);
DEBUG_LOG("refclock %s refid=%s poll=%d dpoll=%d filter=%d",
params->driver_name, UTI_RefidToString(inst->ref_id),
int pps_rate;
int min_samples;
int max_samples;
+ int max_unreach;
int sel_options;
int max_lock_age;
int stratum;
/* Number of set bits in the reachability register */
int reachability_size;
- /* Updates since last reference update */
+ /* Number of reachability updates with cleared register */
+ int unreachable_run;
+
+ /* Maximum number of reachability updates with cleared register to still
+ allow selection */
+ int max_unreachable_run;
+
+ /* Number of selection updates since last reference update */
int updates;
- /* Updates left before allowing combining */
+ /* Number of selection updates left before allowing combining again */
int distant;
- /* Updates with a status requiring source replacement */
+ /* Number of selection updates with a status requiring source replacement */
int bad;
/* Flag indicating the status of the source */
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int authenticated,
int sel_options, IPAddr *addr, int min_samples,
- int max_samples, double min_delay, double asymmetry)
+ int max_samples, double min_delay, double asymmetry,
+ int max_unreach)
{
SRC_Instance result;
result->authenticated = authenticated;
result->conf_sel_options = sel_options;
result->sel_options = sel_options;
+ result->max_unreachable_run = max_unreach;
result->active = 0;
SRC_SetRefid(result, ref_id, addr);
instance->updates = 0;
instance->reachability = 0;
instance->reachability_size = 0;
+ instance->unreachable_run = 0;
instance->distant = 0;
instance->bad = 0;
instance->status = SRC_BAD_STATS;
if (inst->reachability_size < SOURCE_REACH_BITS)
inst->reachability_size++;
+ if (inst->reachability == 0) {
+ if (inst->unreachable_run < INT_MAX)
+ inst->unreachable_run++;
+ } else {
+ inst->unreachable_run = 0;
+ }
+
/* Check if special reference update mode failed */
if (REF_GetMode() != REF_ModeNormal && special_mode_end()) {
REF_SetUnsynchronised();
{
inst->reachability = 0;
inst->reachability_size = 0;
+ inst->unreachable_run = 0;
SRC_UpdateReachability(inst, 0);
}
/* Reachability is not a requirement for selection. An unreachable source
can still be selected if its newest sample is not older than the oldest
- sample from reachable sources. */
- if (!sources[i]->reachability && max_reach_sample_ago < si->last_sample_ago) {
+ sample from reachable sources and the number of consecutive unreachable
+ updates does not exceed the configured maximum. */
+ if (sources[i]->reachability == 0 &&
+ (si->last_sample_ago > max_reach_sample_ago ||
+ sources[i]->unreachable_run > sources[i]->max_unreachable_run)) {
mark_source(sources[i], SRC_STALE);
continue;
}
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int authenticated,
int sel_options, IPAddr *addr, int min_samples,
- int max_samples, double min_delay, double asymmetry);
+ int max_samples, double min_delay, double asymmetry,
+ int max_unreach);
/* Function to get rid of a source when it is being unconfigured.
This may cause the current reference source to be reselected, if this
int max_sources;
int min_samples;
int max_samples;
+ int max_unreach;
int filter_length;
int interleaved;
int sel_options;
#define SRC_DEFAULT_MAXSOURCES 4
#define SRC_DEFAULT_MINSAMPLES (-1)
#define SRC_DEFAULT_MAXSAMPLES (-1)
+#define SRC_DEFAULT_MAXUNREACH 100000
#define SRC_DEFAULT_ASYMMETRY 1.0
#define SRC_DEFAULT_NTSPORT 4460
#define SRC_DEFAULT_CERTSET 0
for chronyc_conf in \
"accheck 1.2.3.4" \
"add peer 10.0.0.0 minpoll 2 maxpoll 6" \
- "add server 10.0.0.0 minpoll 6 maxpoll 10 iburst burst key 1 certset 2 maxdelay 1e-3 maxdelayratio 10.0 maxdelaydevratio 10.0 maxdelayquant 0.5 mindelay 1e-4 asymmetry 0.5 offset 1e-5 minsamples 6 maxsamples 6 filter 3 offline auto_offline prefer noselect trust require xleave polltarget 20 port 123 presend 7 minstratum 3 version 4 nts ntsport 4460 copy extfield F323 extfield F324 ipv6 ipv4" \
+ "add server 10.0.0.0 minpoll 6 maxpoll 10 iburst burst key 1 certset 2 maxdelay 1e-3 maxdelayratio 10.0 maxdelaydevratio 10.0 maxdelayquant 0.5 mindelay 1e-4 asymmetry 0.5 offset 1e-5 minsamples 6 maxsamples 6 maxunreach 8 filter 3 offline auto_offline prefer noselect trust require xleave polltarget 20 port 123 presend 7 minstratum 3 version 4 nts ntsport 4460 copy extfield F323 extfield F324 ipv6 ipv4" \
"add server node1.net1.clk" \
"allow 1.2.3.4" \
"allow 1.2" \
--- /dev/null
+#!/usr/bin/env bash
+
+. ./test.common
+
+test_start "maxunreach option"
+
+limit=5000
+servers=2
+client_server_options="minpoll 6 maxpoll 6 minsamples 64"
+base_delay=$(cat <<-EOF | tr -d '\n'
+ (+ 1e-4
+ (* -1
+ (equal 0.1 from 3)
+ (equal 0.1 to 1)
+ (equal 0.1 (min time 2000) 2000))
+ (* 0.5
+ (+ (equal 0.1 from 2)
+ (equal 0.1 to 2))))
+EOF
+)
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+check_log_messages "Selected source 192.168.123.1" 1 1 || test_fail
+check_log_messages "Selected source 192.168.123.2" 0 0 || test_fail
+
+client_server_options="minpoll 6 maxpoll 6 minsamples 64 maxunreach 10"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+check_log_messages "Selected source 192.168.123.1" 1 1 || test_fail
+check_log_messages "Selected source 192.168.123.2" 1 1 || test_fail
+check_log_messages "00:52:..Z Selected source 192.168.123.2" 1 1 || test_fail
+
+test_pass
return SRC_CreateNewInstance(UTI_IPToRefid(addr), type, authenticated, sel_options,
type == SRC_NTP ? addr : NULL,
- SRC_DEFAULT_MINSAMPLES, SRC_DEFAULT_MAXSAMPLES, 0.0, 1.0);
+ SRC_DEFAULT_MINSAMPLES, SRC_DEFAULT_MAXSAMPLES, 0.0, 1.0,
+ SRC_DEFAULT_MAXUNREACH);
}
void