]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
Limit sources included in combining
authorMiroslav Lichvar <mlichvar@redhat.com>
Mon, 10 Jun 2013 16:37:08 +0000 (18:37 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Wed, 12 Jun 2013 08:25:46 +0000 (10:25 +0200)
Combine only sources whose distance is shorter than distance of the
selected source multiplied by the value of combinelimit and their
estimated frequencies are close to the frequency of the selected source.
Add outlyer status for sources which are selectable, but not included in
the combining. The status is displayed as '-' in the chronyc sources
output.

chrony.texi.in
client.c
cmdmon.c
conf.c
conf.h
reports.h
sources.c

index 41727b1863dcdd3eedb38d17340a04124bed5709..108a2637bc5a7e44d0ae33b60694b68a846510dd 100644 (file)
@@ -1169,6 +1169,7 @@ directives can occur in any order in the file.
 * broadcast directive::         Make chronyd act as an NTP broadcast server
 * cmdallow directive::          Give control access to chronyc on other computers
 * cmddeny directive::           Deny control access to chronyc on other computers
+* combinelimit directive::      Limit sources included in combining algorithm
 * commandkey directive::        Set runtime command key
 * corrtimeratio directive::     Set correction time ratio
 * cmdport directive::           Set port to use for runtime commanding
@@ -1447,6 +1448,30 @@ The syntax is identical.
 There is also a @code{cmddeny all} directive with similar behaviour to the
 @code{cmdallow all} directive.
 @c }}}
+@c {{{ combinelimit
+@node combinelimit directive
+@subsection combinelimit
+When @code{chronyd} has multiple sources available for synchronization, it has
+to select one source as the synchronization source. The measured offsets and
+frequencies of the system clock relative to the other sources, however, can be
+combined with the selected source to improve the accuracy of the system clock.
+
+The @code{combinelimit} directive limits which sources are included in the
+combining algorithm. Their synchronization distance has to be shorter than the
+distance of the selected source multiplied by the value of the limit. Also,
+their measured frequencies have to be close to the frequency of the selected
+source.
+
+By default, the limit is 3. Setting the limit to 0 effectively disables the
+source combining algorithm and only the selected source will be used to
+control the system clock.
+
+The syntax is
+
+@example
+combinelimit <limit>
+@end example
+@c }}}
 @c {{{ commandkey
 @node commandkey directive
 @subsection commandkey
@@ -4080,12 +4105,15 @@ reference clock.
 
 @item S
 This column indicates the state of the sources.  @code{*} indicates the
-source to which @code{chronyd} is current synchronised.  @code{+} indicates
-other acceptable sources.  @code{?} indicates sources to which
-connectivity has been lost.  @code{x} indicates a clock which @code{chronyd}
+source to which @code{chronyd} is currently synchronised.  @code{+}
+indicates acceptable sources which are combined with the selected
+source.  @code{-} indicates acceptable sources which are excluded by
+the combining algorithm.  @code{?} indicates sources to which
+connectivity has been lost or whose packets don't pass all tests.
+@code{x} indicates a clock which @code{chronyd}
 thinks is is a falseticker (i.e. its time is inconsistent with a
 majority of other sources).  @code{~} indicates a source whose time
-appears to have too much variability.  The @code{~} condition is also
+appears to have too much variability.  The @code{?} condition is also
 shown at start-up, until at least 3 samples have been gathered from it.
 
 @item Name/IP address
index 1ddaeefa256555ae798e181735309cdd6a2dbe4c..fec503b504f1eb67ef76fc5ab611e2a3da4e4b66 100644 (file)
--- a/client.c
+++ b/client.c
@@ -1693,8 +1693,8 @@ process_cmd_sources(char *line)
     if (verbose) {
       printf("\n");
       printf("  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.\n");
-      printf(" / .- Source state '*' = current synced, '+' = OK for sync, '?' = unreachable,\n");
-      printf("| /                'x' = time may be in error, '~' = time is too variable.\n");
+      printf(" / .- Source state '*' = current synced, '+' = combined , '-' = not combined,\n");
+      printf("| /   '?' = unreachable, 'x' = time may be in error, '~' = time too variable.\n");
       printf("||                                                 .- xxxx [ yyyy ] +/- zzzz\n");
       printf("||                                                /   xxxx = adjusted offset,\n");
       printf("||         Log2(Polling interval) -.             |    yyyy = measured offset,\n");
index 7bc2f96caf5ae88078ff947a4c4711520459149a..c9fa39bac738b417551b68804a5249ab0374199e 100644 (file)
--- a/cmdmon.c
+++ b/cmdmon.c
@@ -1050,6 +1050,9 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
       case RPT_CANDIDATE:
         tx_message->data.source_data.state   = htons(RPY_SD_ST_CANDIDATE);
         break;
+      case RPT_OUTLYER:
+        tx_message->data.source_data.state   = htons(RPY_SD_ST_OUTLYER);
+        break;
     }
     switch (report.mode) {
       case RPT_NTP_CLIENT:
diff --git a/conf.c b/conf.c
index 734d1f7c9b5f25ae0b9244094c19013117332051..76db3e66ecc41bc6864e4c112e5c44cd64b87ada 100644 (file)
--- a/conf.c
+++ b/conf.c
@@ -66,6 +66,7 @@ static void parse_clientloglimit(char *);
 static void parse_cmdallow(char *);
 static void parse_cmddeny(char *);
 static void parse_cmdport(char *);
+static void parse_combinelimit(char *);
 static void parse_commandkey(char *);
 static void parse_corrtimeratio(char *);
 static void parse_deny(char *);
@@ -126,6 +127,7 @@ static double max_clock_error = 1.0; /* in ppm */
 
 static double reselect_distance = 1e-4;
 static double stratum_weight = 1.0;
+static double combine_limit = 3.0;
 
 static int cmd_port = DEFAULT_CANDM_PORT;
 
@@ -374,6 +376,8 @@ CNF_ReadFile(const char *filename)
         parse_cmddeny(p);
       } else if (!strcasecmp(command, "cmdport")) {
         parse_cmdport(p);
+      } else if (!strcasecmp(command, "combinelimit")) {
+        parse_combinelimit(p);
       } else if (!strcasecmp(command, "commandkey")) {
         parse_commandkey(p);
       } else if (!strcasecmp(command, "corrtimeratio")) {
@@ -757,6 +761,17 @@ parse_stratumweight(char *line)
 
 /* ================================================== */
 
+static void
+parse_combinelimit(char *line)
+{
+  check_number_of_args(line, 1);
+  if (sscanf(line, "%lf", &combine_limit) != 1) {
+    command_parse_error();
+  }
+}
+
+/* ================================================== */
+
 static void
 parse_driftfile(char *line)
 {
@@ -1630,6 +1645,14 @@ CNF_GetStratumWeight(void)
 
 /* ================================================== */
 
+double
+CNF_GetCombineLimit(void)
+{
+  return combine_limit;
+}
+
+/* ================================================== */
+
 int
 CNF_GetManualEnabled(void)
 {
diff --git a/conf.h b/conf.h
index af8e2a0bba35544fdc04adb6bd86ab4f95c40a99..2d986e672b5a8b7b2eacff9ecb65a67055844bec 100644 (file)
--- a/conf.h
+++ b/conf.h
@@ -83,6 +83,7 @@ extern double CNF_GetCorrectionTimeRatio(void);
 
 extern double CNF_GetReselectDistance(void);
 extern double CNF_GetStratumWeight(void);
+extern double CNF_GetCombineLimit(void);
 
 extern int CNF_AllowLocalReference(int *stratum);
 
index 646210668c8e3441e1ca0d1f39a20840cc43ccaa..3eeb5ab51dd36b8af6ec3192f422650af69e767c 100644 (file)
--- a/reports.h
+++ b/reports.h
@@ -37,7 +37,7 @@ typedef struct {
   int stratum;
   int poll;
   enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode;
-  enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE} state;
+  enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE, RPT_OUTLYER} state;
   enum {RPT_NORMAL, RPT_PREFER, RPT_NOSELECT} sel_option;
 
   int reachability;
index a8d17fbad365f47db9003f88754b2ddb0a3fc20d..f44451aa3d3de2168a6dee5e5b801ae8f3012a5f 100644 (file)
--- a/sources.c
+++ b/sources.c
@@ -96,6 +96,9 @@ struct SRC_Instance_Record {
   /* Reachability register */
   int reachability;
 
+  /* Updates left before resetting outlyer status */
+  int outlyer;
+
   /* Flag indicating the status of the source */
   SRC_Status status;
 
@@ -138,8 +141,12 @@ static int selected_source_index; /* Which source index is currently
 /* Score needed to replace the currently selected source */
 #define SCORE_LIMIT 10.0
 
+/* Number of updates needed to reset the outlyer status */
+#define OUTLYER_PENALTY 32
+
 static double reselect_distance;
 static double stratum_weight;
+static double combine_limit;
 
 /* ================================================== */
 /* Forward prototype */
@@ -162,6 +169,7 @@ void SRC_Initialise(void) {
   selected_source_index = INVALID_SOURCE;
   reselect_distance = CNF_GetReselectDistance();
   stratum_weight = CNF_GetStratumWeight();
+  combine_limit = CNF_GetCombineLimit();
   initialised = 1;
 
   LCL_AddParameterChangeHandler(slew_sources, NULL);
@@ -211,6 +219,7 @@ SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOpt
   result->ip_addr = addr;
   result->selectable = 0;
   result->reachability = 0;
+  result->outlyer = 0;
   result->status = SRC_BAD_STATS;
   result->type = type;
   result->sel_score = 1.0;
@@ -431,6 +440,23 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
                         &src_frequency, &src_skew,
                         &src_root_delay, &src_root_dispersion);
 
+    /* Don't include this source if its distance is longer than the distance of
+       the selected source multiplied by the limit, their estimated frequencies
+       are not close, or it was recently marked as outlyer */
+
+    if (index != selected_source_index &&
+        (sources[index]->sel_info.root_distance > combine_limit *
+           (reselect_distance + sources[selected_source_index]->sel_info.root_distance) ||
+         fabs(*frequency - src_frequency) >
+           combine_limit * (*skew + src_skew + LCL_GetMaxClockError()))) {
+      sources[index]->outlyer = OUTLYER_PENALTY;
+    }
+
+    if (sources[index]->outlyer) {
+      sources[index]->outlyer--;
+      continue;
+    }
+
     UTI_DiffTimevalsToDouble(&elapsed, ref_time, &src_ref_time);
     src_offset += elapsed * src_frequency;
     weight = 1.0 / sources[index]->sel_info.root_distance;
@@ -817,6 +843,7 @@ SRC_SelectSource(uint32_t match_refid)
           /* Reset score for non-selectable sources */
           if (sources[i]->status != SRC_SELECTABLE) {
             sources[i]->sel_score = 1.0;
+            sources[i]->outlyer = OUTLYER_PENALTY;
             continue;
           }
             
@@ -880,6 +907,7 @@ SRC_SelectSource(uint32_t match_refid)
           /* New source has been selected, reset all scores */
           for (i=0; i < n_sources; i++) {
             sources[i]->sel_score = 1.0;
+            sources[i]->outlyer = 0;
           }
         }
 
@@ -1156,7 +1184,7 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
         report->state = RPT_FALSETICKER;
         break;
       case SRC_SELECTABLE:
-        report->state = RPT_CANDIDATE;
+        report->state = src->outlyer ? RPT_OUTLYER : RPT_CANDIDATE;
         break;
       default:
         assert(0);