]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
Add test for ratio of increase in delay to stddev
authorMiroslav Lichvar <mlichvar@redhat.com>
Fri, 3 Dec 2010 17:35:33 +0000 (18:35 +0100)
committerMiroslav Lichvar <mlichvar@redhat.com>
Tue, 7 Dec 2010 15:47:57 +0000 (16:47 +0100)
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.

12 files changed:
chrony.texi
client.c
cmdmon.c
cmdparse.c
cmdparse.h
conf.c
ntp_core.c
sources.c
sources.h
sourcestats.c
sourcestats.h
srcparams.h

index bee73f5498d42eb0ec73bc8ea929d7a1d097c68d..d25421f56ebdaa9cddf2454e8e079842c1a95480 100644 (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
index eaf92ab21a0b272cd731152dc76dfbb5cc738eb0..67456e43a033566fe80e10143aea281e0b37da7a 100644 (file)
--- a/client.c
+++ b/client.c
@@ -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;
index 884c62328b3819d8f1b579bc286e70a090be1e6e..3d5df7404c2966cd7d8f9eefda507da4fbed5c1d 100644 (file)
--- a/cmdmon.c
+++ b/cmdmon.c
@@ -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) {
index be4598941e936171c7c2ead2d47b0d95cf5a9c19..983c334fc729b165051992ff04c10a2f7823ba9e 100644 (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) {
index a6353bd53b8373708a4e9e95e6c52f5595395e21..0f41cfd8868a3a5405392f670bd447fc77c6829e 100644 (file)
@@ -42,6 +42,7 @@ typedef enum {
   CPS_BadMinpoll,
   CPS_BadMaxpoll,
   CPS_BadPresend,
+  CPS_BadMaxdelaydevratio,
   CPS_BadMaxdelayratio,
   CPS_BadMaxdelay,
   CPS_BadKey,
diff --git a/conf.c b/conf.c
index f6fd9b2f451a5acdd94420f9f3b2b20b540e459e..b64c4bca8823772b17502950341747a589429651 100644 (file)
--- a/conf.c
+++ b/conf.c
@@ -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;
index 8306ad2f3c85afb4de027799715b066730689d17..42115942c020c05e8215b7c0366908e6a4540232 100644 (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,
index 38706cac76adcaa91386732b01c41645f9b56876..20c0855971df3bef2bdc76e8102c90b265d97449 100644 (file)
--- a/sources.c
+++ b/sources.c
@@ -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
index d89ce597a979e79bd155bb835a9641d6b11598c9..b731191edeaf40dd618d6c1e59a3d7b6be7ac299 100644 (file)
--- a/sources.h
+++ b/sources.h
@@ -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);
index c149db9a9ad76ffc3e10fbe08b87b18c96e0d0fc..522abd0ca331e131c0aab11cf689da4aa0d241eb 100644 (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 */
index e47287f79cb3f9a08da756109886640ecaceb01f..27908c89ab590c0aee0aa1741d26801e6088b821 100644 (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);
index 58395cb43d9e35c904ba837c4e7767bb63578a43..0cab90ac40a12da6837321447f12229dd14fdd61 100644 (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