Add test for ratio of increase in delay to stddev

Require 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 maxdelaydevratio or the difference between
measured offset and predicted offset is larger than the increase in
delay. In the allowed delay increase is included also skew and maximum
clock frequency error.

maxdelaydevratio is 10.0 by default.
This commit is contained in:
Miroslav Lichvar 2010-12-03 18:35:33 +01:00
parent feb8811f37
commit b977c95be4
12 changed files with 112 additions and 9 deletions

View file

@ -1828,7 +1828,7 @@ An example line (which actually appears as a single line in the file)
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
@ -1837,7 +1837,7 @@ values from the example line above) :
@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.
@ -1853,8 +1853,8 @@ Stratum of remote computer. [2]
@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
@ -2595,6 +2595,12 @@ measurements that it has buffered. If a measurement has a round trip
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

View file

@ -963,6 +963,11 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
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);
@ -998,6 +1003,9 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
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;

View file

@ -1271,6 +1271,7 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m
/* 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, &params);
switch (status) {

View file

@ -56,6 +56,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
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;
@ -123,6 +124,14 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} 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) {

View file

@ -42,6 +42,7 @@ typedef enum {
CPS_BadMinpoll,
CPS_BadMaxpoll,
CPS_BadPresend,
CPS_BadMaxdelaydevratio,
CPS_BadMaxdelayratio,
CPS_BadMaxdelay,
CPS_BadKey,

3
conf.c
View file

@ -391,6 +391,9 @@ parse_source(const char *line, NTP_Source_Type type)
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;

View file

@ -119,6 +119,8 @@ struct NCR_Instance_Record {
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
@ -213,7 +215,7 @@ void
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();
@ -284,6 +286,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
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;
@ -777,7 +780,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
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
@ -941,6 +944,18 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
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) {
@ -1011,7 +1026,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
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;
@ -1240,13 +1255,13 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
/* 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,

View file

@ -794,6 +794,16 @@ SRC_MinRoundTripDelay(SRC_Instance inst)
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

View file

@ -145,6 +145,10 @@ extern double SRC_PredictOffset(SRC_Instance inst, struct timeval *when);
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);

View file

@ -693,6 +693,45 @@ SST_MinRoundTripDelay(SST_Stats inst)
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 */

View file

@ -137,6 +137,11 @@ extern double SST_PredictOffset(SST_Stats inst, struct timeval *when);
/* 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);

View file

@ -45,6 +45,7 @@ typedef struct {
unsigned long authkey;
double max_delay;
double max_delay_ratio;
double max_delay_dev_ratio;
SRC_SelectOption sel_option;
} SourceParameters;
@ -54,6 +55,7 @@ typedef struct {
#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