from the measurements log file is shown below.
@example
-1998-07-22 05:40:50 158.152.1.76 N 8 1111 11 1111 10 10 1 \
+2010-12-22 05:40:50 158.152.1.76 N 8 1111 111 1111 10 10 1.0 \
-4.966e-03 2.296e-01 1.577e-05 1.615e-01 7.446e-03
@end example
@enumerate 1
@item
-Date [1998-07-22]
+Date [2010-12-22]
@item
Hour:Minute:Second [05:40:50]. Note that the date/time pair is
expressed in UTC, not the local time zone.
@item
RFC1305 tests 1 through 4 (1=pass, 0=fail) [1111]
@item
-Tests for maximum delay and maximum delay ratio, against user defined
-parameters (1=pass, 0=fail) [11]
+Tests for maximum delay, maximum delay ratio and maximum delay dev ratio,
+against defined parameters (1=pass, 0=fail) [111]
@item
RFC1305 tests 5 through 8 (1=pass, 0=fail) [1111]
@item
delay that is greater than the maxdelayratio times the minimum delay, it
will be rejected.
+@item maxdelaydevratio
+If a measurement has ratio of the increase in round-trip delay from
+the minimum delay amongst the previous measurements to the standard
+deviation of the previous measurements that is greater than
+maxdelaydevratio, it will be rejected. The default is 10.0.
+
@item presend
If the timing measurements being made by @code{chronyd} are the only
network data passing between two computers, you may find that some
break;
}
+ if (data.params.max_delay_dev_ratio != SRC_DEFAULT_MAXDELAYDEVRATIO) {
+ fprintf(stderr, "Option maxdelaydevratio not supported\n");
+ break;
+ }
+
msg->data.ntp_source.port = htonl((unsigned long) data.port);
UTI_IPHostToNetwork(&data.ip_addr, &msg->data.ntp_source.ip_addr);
msg->data.ntp_source.minpoll = htonl(data.params.minpoll);
case CPS_BadPresend:
fprintf(stderr, "Unreadable presend value\n");
break;
+ case CPS_BadMaxdelaydevratio:
+ fprintf(stderr, "Unreadable max delay dev ratio value\n");
+ break;
case CPS_BadMaxdelayratio:
fprintf(stderr, "Unreadable max delay ratio value\n");
break;
/* not transmitted in cmdmon protocol yet */
params.min_stratum = SRC_DEFAULT_MINSTRATUM;
params.poll_target = SRC_DEFAULT_POLLTARGET;
+ params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
status = NSR_AddSource(&rem_addr, type, ¶ms);
switch (status) {
src->params.authkey = INACTIVE_AUTHKEY;
src->params.max_delay = SRC_DEFAULT_MAXDELAY;
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
+ src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
src->params.online = 1;
src->params.auto_offline = 0;
src->params.iburst = 0;
} else {
line += n;
}
+ } else if (!strncasecmp(cmd, "maxdelaydevratio", 16)) {
+ if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1) {
+ result = CPS_BadMaxdelaydevratio;
+ ok = 0;
+ done = 1;
+ } else {
+ line += n;
+ }
/* This MUST come before the following one ! */
} else if (!strncasecmp(cmd, "maxdelayratio", 13)) {
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1) {
CPS_BadMinpoll,
CPS_BadMaxpoll,
CPS_BadPresend,
+ CPS_BadMaxdelaydevratio,
CPS_BadMaxdelayratio,
CPS_BadMaxdelay,
CPS_BadKey,
case CPS_BadPresend:
LOG(LOGS_WARN, LOGF_Configure, "Unreadable presend value at line %d", line_number);
break;
+ case CPS_BadMaxdelaydevratio:
+ LOG(LOGS_WARN, LOGF_Configure, "Unreadable max delay dev ratio value at line %d", line_number);
+ break;
case CPS_BadMaxdelayratio:
LOG(LOGS_WARN, LOGF_Configure, "Unreadable max delay ratio value at line %d", line_number);
break;
min_delay_in_register that we can
tolerate. */
+ double max_delay_dev_ratio; /* Maximum ratio of increase in delay / stddev */
+
int do_auth; /* Flag indicating whether we
authenticate packets we send to
this machine (if it's serving us or
NCR_Initialise(void)
{
logfileid = CNF_GetLogMeasurements() ? LOG_FileOpen("measurements",
- " Date (UTC) Time IP Address L St 1234 ab 5678 LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
+ " Date (UTC) Time IP Address L St 1234 abc 5678 LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
: -1;
access_auth_table = ADF_CreateTable();
result->max_delay = params->max_delay;
result->max_delay_ratio = params->max_delay_ratio;
+ result->max_delay_dev_ratio = params->max_delay_dev_ratio;
result->tx_count = 0;
int test1, test2, test3, test4, test5, test6, test7, test8;
- int test4a, test4b;
+ int test4a, test4b, test4c;
/* In the words of section 3.4.4 of RFC1305, valid_data means
that the NTP protocol association with the peer/server is
test4b = 1; /* Success */
}
+ /* Test 4c (additional to RFC1305) requires that the ratio of the
+ increase in delay from the minimum one in the stats data register to
+ the standard deviation of the offsets in the register is less than an
+ administrator-defined value or the difference between measured offset
+ and predicted offset is larger than the increase in delay */
+ if (!SRC_IsGoodSample(inst->source, -theta, delta, inst->max_delay_dev_ratio,
+ LCL_GetMaxClockError(), &sample_time)) {
+ test4c = 0; /* Failed */
+ } else {
+ test4c = 1; /* Success */
+ }
+
/* Test 5 relates to authentication. */
if (inst->do_auth) {
if (do_auth) {
valid_kod = test1 && test2 && test5;
- valid_data = test1 && test2 && test3 && test4 && test4a && test4b;
+ valid_data = test1 && test2 && test3 && test4 && test4a && test4b && test4c;
valid_header = test5 && test6 && test7 && test8;
root_delay = pkt_root_delay + delta;
/* Do measurement logging */
if (logfileid != -1) {
- LOG_FileWrite(logfileid, "%s %-15s %1c %2d %1d%1d%1d%1d %1d%1d %1d%1d%1d%1d %2d %2d %4.2f %10.3e %10.3e %10.3e %10.3e %10.3e",
+ LOG_FileWrite(logfileid, "%s %-15s %1c %2d %1d%1d%1d%1d %1d%1d%1d %1d%1d%1d%1d %2d %2d %4.2f %10.3e %10.3e %10.3e %10.3e %10.3e",
UTI_TimeToLogForm(sample_time.tv_sec),
UTI_IPToString(&inst->remote_addr.ip_addr),
sync_stats[pkt_leap],
message->stratum,
test1, test2, test3, test4,
- test4a, test4b,
+ test4a, test4b, test4c,
test5, test6, test7, test8,
inst->local_poll, inst->remote_poll,
inst->poll_score,
return SST_MinRoundTripDelay(inst->stats);
}
+/* ================================================== */
+
+int
+SRC_IsGoodSample(SRC_Instance inst, double offset, double delay,
+ double max_delay_dev_ratio, double clock_error, struct timeval *when)
+{
+ return SST_IsGoodSample(inst->stats, offset, delay, max_delay_dev_ratio,
+ clock_error, when);
+}
+
/* ================================================== */
/* This routine is registered as a callback with the local clock
module, to be called whenever the local clock changes frequency or
currently held in the register */
extern double SRC_MinRoundTripDelay(SRC_Instance inst);
+/* This routine determines if a new sample is good enough that it should be
+ accumulated */
+extern int SRC_IsGoodSample(SRC_Instance inst, double offset, double delay, double max_delay_dev_ratio, double clock_error, struct timeval *when);
+
extern void SRC_DumpSources(void);
extern void SRC_ReloadSources(void);
return inst->peer_delays[inst->min_delay_sample];
}
+/* ================================================== */
+
+int
+SST_IsGoodSample(SST_Stats inst, double offset, double delay,
+ double max_delay_dev_ratio, double clock_error, struct timeval *when)
+{
+ double elapsed, allowed_increase, delay_increase;
+
+ if (inst->n_samples < 3)
+ return 1;
+
+ UTI_DiffTimevalsToDouble(&elapsed, when, &inst->offset_time);
+
+ /* Require that the ratio of the increase in delay from the minimum to the
+ standard deviation is less than max_delay_dev_ratio. In the allowed
+ increase in delay include also skew and clock_error. */
+
+ allowed_increase = sqrt(inst->variance) * max_delay_dev_ratio +
+ elapsed * (inst->skew + clock_error);
+ delay_increase = (delay - SST_MinRoundTripDelay(inst)) / 2.0;
+
+ if (delay_increase < allowed_increase)
+ return 1;
+
+ offset -= inst->estimated_offset + elapsed * inst->estimated_frequency;
+
+ /* Before we decide to drop the sample, make sure the difference between
+ measured offset and predicted offset is not significantly larger than
+ the increase in delay */
+ if (fabs(offset) - delay_increase > allowed_increase)
+ return 1;
+
+#if 0
+ LOG(LOGS_INFO, LOGF_SourceStats, "bad sample: offset=%f delay=%f incr_delay=%f allowed=%f", offset, delay, allowed_increase, delay_increase);
+#endif
+
+ return 0;
+}
+
/* ================================================== */
/* This is used to save the register to a file, so that we can reload
it after restarting the daemon */
/* Find the minimum round trip delay in the register */
extern double SST_MinRoundTripDelay(SST_Stats inst);
+/* This routine determines if a new sample is good enough that it should be
+ accumulated */
+extern int SST_IsGoodSample(SST_Stats inst, double offset, double delay,
+ double max_delay_dev_ratio, double clock_error, struct timeval *when);
+
extern void SST_SaveToFile(SST_Stats inst, FILE *out);
extern int SST_LoadFromFile(SST_Stats inst, FILE *in);
unsigned long authkey;
double max_delay;
double max_delay_ratio;
+ double max_delay_dev_ratio;
SRC_SelectOption sel_option;
} SourceParameters;
#define SRC_DEFAULT_PRESEND_MINPOLL 0
#define SRC_DEFAULT_MAXDELAY 16.0
#define SRC_DEFAULT_MAXDELAYRATIO 16384.0
+#define SRC_DEFAULT_MAXDELAYDEVRATIO 10.0
#define SRC_DEFAULT_MINSTRATUM 0
#define SRC_DEFAULT_POLLTARGET 6
#define INACTIVE_AUTHKEY 0UL