]> git.ipfire.org Git - thirdparty/nqptp.git/commitdiff
Add a new state clock_is_becoming_master and don't promote to master until at least...
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Thu, 24 Jun 2021 09:23:20 +0000 (10:23 +0100)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Thu, 24 Jun 2021 09:23:20 +0000 (10:23 +0100)
nqptp-clock-sources.c
nqptp-clock-sources.h
nqptp-message-handlers.c
nqptp.c

index 6d479208a802a394cf275beb03e33af74ac0eefa..b1735155cf2289ee0fdf30e0c503661ed838666f 100644 (file)
@@ -155,6 +155,48 @@ void update_clock_self_identifications(clock_source_private_data *clocks_private
   freeifaddrs(ifap);
 }
 
+void debug_log_nqptp_status(int level) {
+  int records_in_use = 0;
+  int i;
+  for (i = 0; i < MAX_CLOCKS; i++)
+    if (clocks_private[i].in_use != 0)
+      records_in_use++;
+  if (records_in_use > 0) {
+    debug(level, "");
+    debug(level, "Current NQPTP Status:");
+    uint32_t peer_mask = (1 << clock_is_a_timing_peer);
+    uint32_t peer_clock_mask = peer_mask | (1 << clock_is_valid);
+    uint32_t peer_master_mask = peer_clock_mask | (1 << clock_is_master);
+    uint32_t peer_becoming_master_mask = peer_clock_mask | (1 << clock_is_becoming_master);
+    uint32_t non_peer_clock_mask = (1 << clock_is_valid);
+    uint32_t non_peer_master_mask = non_peer_clock_mask | (1 << clock_is_master);
+    for (i = 0; i < MAX_CLOCKS; i++) {
+      if (clocks_private[i].in_use != 0) {
+        if ((clocks_private[i].flags & peer_master_mask) == peer_master_mask) {
+          debug(level, "  Peer Master:            %" PRIx64 "  %s.", clocks_private[i].clock_id,
+                clocks_private[i].ip);
+        } else if ((clocks_private[i].flags & peer_becoming_master_mask) == peer_becoming_master_mask) {
+          debug(level, "  Peer Becoming Master:   %" PRIx64 "  %s.", clocks_private[i].clock_id,
+                clocks_private[i].ip);
+        } else if ((clocks_private[i].flags & peer_clock_mask) == peer_clock_mask) {
+          debug(level, "  Peer Clock:             %" PRIx64 "  %s.", clocks_private[i].clock_id,
+                clocks_private[i].ip);
+        } else if ((clocks_private[i].flags & peer_mask) == peer_mask) {
+          debug(level, "  Peer:                                     %s.", clocks_private[i].ip);
+        } else if ((clocks_private[i].flags & non_peer_master_mask) == non_peer_master_mask) {
+          debug(level, "  Non Peer Master:        %" PRIx64 "  %s.", clocks_private[i].clock_id,
+                clocks_private[i].ip);
+        } else if ((clocks_private[i].flags & non_peer_clock_mask) == non_peer_clock_mask) {
+          debug(level, "  Non Peer Clock:         %16" PRIx64 "  %s.", clocks_private[i].clock_id,
+                clocks_private[i].ip);
+        } else {
+          debug(level, "  Non Peer Record:                          %s.", clocks_private[i].ip);
+        }
+      }
+    }
+  }
+}
+
 void update_master() {
   // note -- this is definitely incomplete -- it doesn't do the full
   // data set comparison specified by the IEEE 588 standard
@@ -166,6 +208,7 @@ void update_master() {
       if (old_master == -1)
         old_master = i;                                 // find old master
     clocks_private[i].flags &= ~(1 << clock_is_master); // turn them all off
+    clocks_private[i].flags &= ~(1 << clock_is_becoming_master); // turn them all off
   }
 
   int best_so_far = -1;
@@ -218,146 +261,16 @@ void update_master() {
       debug(1, "No master clock not found!");
   } else {
     // we found a master clock
-    clocks_private[best_so_far].flags |= (1 << clock_is_master);
-
-    if (old_master != best_so_far) {
-      uint64_t oldest_acceptable_master_clock_time =
-          clocks_private[best_so_far].source_time + 1150000000; // ns.
-
-      // we will try to improve on this present, definitive, local_to_source_time_offset we have
-      int changes_made = 0;
-
-      uint64_t best_offset_so_far = clocks_private[best_so_far].local_to_source_time_offset;
-      uint64_t age_of_oldest_legitimate_sample = clocks_private[best_so_far].local_time;
-
-      int number_of_samples = MAX_TIMING_SAMPLES - clocks_private[best_so_far].vacant_samples;
-      int samples_checked = 0;
-      if (number_of_samples > 0) {
-        debug(3, "Number of samples: %d.", number_of_samples);
-        uint64_t time_now = get_time_now();
-
-        // Now we use the last few samples to calculate the best offset for the
-        // new master clock.
-
-        // The time of the oldest sample we use will become the time of the start of the
-        // mastership
-
-        // We will accept samples that would make the local-to-clock offset greatest,
-        // provided they are not too old and that they don't push the current clock time
-        // more than, say, 1000 ms plus one sample interval (i.e about 1.125 seconds) in the future.
-
-        // This present sample is the only time estimate we have when the clock is definitely a
-        // master, so we use it to eliminate any previous time estimates, made when the clock wasn't
-        // designated a master, that would put it more than, say, a 1.15 seconds further into the
-        // future.
 
-        // Allow the samples to give a valid master clock time up to this much later than the
-        // present, definitive, sample:
 
-        uint64_t oldest_acceptable_time = time_now - 10000000000; // only go back this far (ns)
-
-        int64_t cko = age_of_oldest_legitimate_sample - oldest_acceptable_time;
-        if (cko < 0)
-          debug(1,"starting sample is too old: %" PRId64 " ns.", cko);
-
-        int i;
-        for (i = 0; i < number_of_samples; i++) {
-
-          int64_t age = time_now - clocks_private[best_so_far].samples[i].local_time;
-
-          int64_t age_relative_to_oldest_acceptable_time =
-              clocks_private[best_so_far].samples[i].local_time - oldest_acceptable_time;
-          if (age_relative_to_oldest_acceptable_time > 0) {
-            debug(3, "sample accepted at %f seconds old.", 0.000000001 * age);
-            if (clocks_private[best_so_far].samples[i].local_time <
-                age_of_oldest_legitimate_sample) {
-              age_of_oldest_legitimate_sample = clocks_private[best_so_far].samples[i].local_time;
-            }
-            uint64_t possible_offset = clocks_private[best_so_far].samples[i].clock_time -
-                                       clocks_private[best_so_far].samples[i].local_time;
-            uint64_t possible_master_clock_time =
-                clocks_private[best_so_far].local_time + possible_offset;
-            int64_t age_relative_to_oldest_acceptable_master_clock_time =
-                possible_master_clock_time - oldest_acceptable_master_clock_time;
-            if (age_relative_to_oldest_acceptable_master_clock_time <= 0) {
-              samples_checked++;
-              // so, the sample was not obtained too far in the past
-              // and it would not push the estimated master clock_time too far into the future
-              // so, if it is greater than the best_offset_so_far, then make it the new one
-              if (possible_offset > best_offset_so_far) {
-                debug(3, "new best offset");
-                best_offset_so_far = possible_offset;
-                changes_made++;
-              }
-            } else {
-              debug(3, "sample too far into the future");
-            }
-          } else {
-            debug(3, "sample too old at %f seconds old.", 0.000000001 * age);
-          }
-        }
-      }
-
-      // it is possible that the clock has been designated master without any valid recent samples
-      // in which case the number of valid samples will be zero.
-      if (samples_checked == 0) {
-        debug(2,"clock %" PRIx64 " has become master without any recent samples...", clocks_private[best_so_far].clock_id);
-        // having no samples is a flag for the first FOLLOW_UP to set the bus mastership start time
-        // to its own reception time.
-        clocks_private[best_so_far].vacant_samples = MAX_TIMING_SAMPLES; // discard all samples
-      } else {
-        clocks_private[best_so_far].mastership_start_time = age_of_oldest_legitimate_sample;
-        int64_t offset_difference =
-            best_offset_so_far - clocks_private[best_so_far].local_to_source_time_offset;
-
-        debug(2, "Lookback difference: %f ms with %d samples checked of %d samples total.",
-              0.000001 * offset_difference, samples_checked, number_of_samples);
-        clocks_private[best_so_far].local_to_source_time_offset = best_offset_so_far;
-
-        debug(2, "Master sampling started %f ms before becoming master.",
-              0.000001 * (clocks_private[best_so_far].local_time - age_of_oldest_legitimate_sample));
-        update_master_clock_info(clocks_private[best_so_far].clock_id,
-                                 (const char *)&clocks_private[best_so_far].ip,
-                                 clocks_private[best_so_far].local_time,
-                                 clocks_private[best_so_far].local_to_source_time_offset,
-                                 clocks_private[best_so_far].mastership_start_time);
-      }
+    if (old_master != best_so_far) {
+      // if the naster is a new one
       clocks_private[best_so_far].previous_offset_time = 0; // resync
+      clocks_private[best_so_far].flags |= (1 << clock_is_becoming_master);
+    } else {
+      // if its the same one as before
+      clocks_private[best_so_far].flags |= (1 << clock_is_master);
     }
   }
-
-  int records_in_use = 0;
-  for (i = 0; i < MAX_CLOCKS; i++)
-    if (clocks_private[i].in_use != 0)
-      records_in_use++;
-  if (records_in_use > 0) {
-    debug(1, "");
-    debug(1, "Current NQPTP Status:");
-    uint32_t peer_mask = (1 << clock_is_a_timing_peer);
-    uint32_t peer_clock_mask = peer_mask | (1 << clock_is_valid);
-    uint32_t peer_master_mask = peer_clock_mask | (1 << clock_is_master);
-    uint32_t non_peer_clock_mask = (1 << clock_is_valid);
-    uint32_t non_peer_master_mask = non_peer_clock_mask | (1 << clock_is_master);
-    for (i = 0; i < MAX_CLOCKS; i++) {
-      if (clocks_private[i].in_use != 0) {
-        if ((clocks_private[i].flags & peer_master_mask) == peer_master_mask) {
-          debug(1, "  Peer Master:     %" PRIx64 "  %s.", clocks_private[i].clock_id,
-                clocks_private[i].ip);
-        } else if ((clocks_private[i].flags & peer_clock_mask) == peer_clock_mask) {
-          debug(1, "  Peer Clock:      %" PRIx64 "  %s.", clocks_private[i].clock_id,
-                clocks_private[i].ip);
-        } else if ((clocks_private[i].flags & peer_mask) == peer_mask) {
-          debug(1, "  Peer:                              %s.", clocks_private[i].ip);
-        } else if ((clocks_private[i].flags & non_peer_master_mask) == non_peer_master_mask) {
-          debug(1, "  Non Peer Master: %" PRIx64 "  %s.", clocks_private[i].clock_id,
-                clocks_private[i].ip);
-        } else if ((clocks_private[i].flags & non_peer_clock_mask) == non_peer_clock_mask) {
-          debug(1, "  Non Peer Clock:  %" PRIx64 "  %s.", clocks_private[i].clock_id,
-                clocks_private[i].ip);
-        } else {
-          debug(1, "  Non Peer Record:                   %s.", clocks_private[i].ip);
-        }
-      }
-    }
-  }
+  debug_log_nqptp_status(1);
 }
index 68de9e2cae63b785ac70862936be810060c5bcb8..c0674d612a01db20d9d9f409bec5d2d80234ddae 100644 (file)
@@ -29,6 +29,7 @@ typedef enum {
   clock_is_valid,
   clock_is_a_timing_peer,
   clock_is_qualified,
+  clock_is_becoming_master,
   clock_is_master
 } clock_flags;
 
@@ -89,4 +90,6 @@ extern clock_source_private_data clocks_private[MAX_CLOCKS];
 
 void update_master();
 
+void debug_log_nqptp_status(int level);
+
 #endif
index da3114a11adcc6f3fe5299682483ab529cafff86..46e91dac3ab0275bbe77b678a9aebeb5c67d140c 100644 (file)
@@ -244,13 +244,100 @@ void handle_follow_up(char *buf, __attribute__((unused)) ssize_t recv_len,
     clock_private_info->next_sample_goes_here = 0;
 
   debug(2, "FOLLOWUP from %" PRIx64 ", %s.", clock_private_info->clock_id, &clock_private_info->ip);
-
   uint64_t offset = preciseOriginTimestamp - reception_time;
-
   int64_t jitter = 0;
-  // if there has never been a previous follow_up or if it was long ago (more than 15 seconds),
-  // don't use it
-  if (clock_private_info->previous_offset_time != 0) {
+
+    if ((clock_private_info->flags & (1 << clock_is_becoming_master)) != 0) {
+      // we definitely have at least one sample since the request was made to
+      // designate it a master, so we assume it is legitimate. That is, we assume
+      // that the clock originator knows that it a clock master by now.
+      uint64_t oldest_acceptable_master_clock_time =
+          clock_private_info->source_time + 1150000000; // ns.
+
+      // we will try to improve on this present, definitive, local_to_source_time_offset we have
+      int changes_made = 0;
+
+      uint64_t best_offset_so_far = clock_private_info->local_to_source_time_offset;
+      uint64_t age_of_oldest_legitimate_sample = clock_private_info->local_time;
+
+      int number_of_samples = MAX_TIMING_SAMPLES - clock_private_info->vacant_samples;
+      int samples_checked = 0;
+      if (number_of_samples > 0) {
+        debug(3, "Number of samples: %d.", number_of_samples);
+
+        // Now we use the last few samples to calculate the best offset for the
+        // new master clock.
+
+        // The time of the oldest sample we use will become the time of the start of the
+        // mastership.
+
+        // We will accept samples that would make the local-to-clock offset greatest,
+        // provided they are not too old and that they don't push the current clock time
+        // more than, say, 1000 ms plus one sample interval (i.e about 1.125 seconds) in the future.
+
+        // This present sample is the only time estimate we have when the clock is definitely a
+        // master, so we use it to eliminate any previous time estimates, made when the clock wasn't
+        // designated a master, that would put it more than, say, a 1.15 seconds further into the
+        // future.
+
+        // Allow the samples to give a valid master clock time up to this much later than the
+        // present, definitive, sample:
+
+        uint64_t oldest_acceptable_time = reception_time - 10000000000; // only go back this far (ns)
+
+        int64_t cko = age_of_oldest_legitimate_sample - oldest_acceptable_time;
+        if (cko < 0)
+          debug(1,"starting sample is too old: %" PRId64 " ns.", cko);
+
+        int i;
+        for (i = 0; i < number_of_samples; i++) {
+          int64_t age = reception_time - clock_private_info->samples[i].local_time;
+          int64_t age_relative_to_oldest_acceptable_time =
+              clock_private_info->samples[i].local_time - oldest_acceptable_time;
+          if (age_relative_to_oldest_acceptable_time > 0) {
+            debug(3, "sample accepted at %f seconds old.", 0.000000001 * age);
+            if (clock_private_info->samples[i].local_time <
+                age_of_oldest_legitimate_sample) {
+              age_of_oldest_legitimate_sample = clock_private_info->samples[i].local_time;
+            }
+            uint64_t possible_offset = clock_private_info->samples[i].clock_time -
+                                       clock_private_info->samples[i].local_time;
+            uint64_t possible_master_clock_time =
+                clock_private_info->local_time + possible_offset;
+            int64_t age_relative_to_oldest_acceptable_master_clock_time =
+                possible_master_clock_time - oldest_acceptable_master_clock_time;
+            if (age_relative_to_oldest_acceptable_master_clock_time <= 0) {
+              samples_checked++;
+              // so, the sample was not obtained too far in the past
+              // and it would not push the estimated master clock_time too far into the future
+              // so, if it is greater than the best_offset_so_far, then make it the new one
+              if (possible_offset > best_offset_so_far) {
+                debug(3, "new best offset");
+                best_offset_so_far = possible_offset;
+                changes_made++;
+              }
+            } else {
+              debug(3, "sample too far into the future");
+            }
+          } else {
+            debug(3, "sample too old at %f seconds old.", 0.000000001 * age);
+          }
+        }
+      }
+      clock_private_info->mastership_start_time = age_of_oldest_legitimate_sample;
+      int64_t offset_difference =
+          best_offset_so_far - clock_private_info->local_to_source_time_offset;
+
+      debug(2, "Lookback difference: %f ms with %d samples checked of %d samples total.",
+            0.000001 * offset_difference, samples_checked, number_of_samples);
+      clock_private_info->local_to_source_time_offset = best_offset_so_far;
+
+      debug(2, "Master sampling started %f ms before becoming master.",
+            0.000001 * (reception_time - age_of_oldest_legitimate_sample));
+      clock_private_info->flags &= ~(1 << clock_is_becoming_master);
+      clock_private_info->flags |= 1 << clock_is_master;
+    } else if (clock_private_info->previous_offset_time != 0) {
+      // i.e. if it's not becoming a master and there has been a previous follow_up
     int64_t time_since_last_sync = reception_time - clock_private_info->last_sync_time;
     int64_t sync_timeout = 60000000000; // nanoseconds
     debug(2, "Sync interval: %f seconds.", 0.000000001 * time_since_last_sync);
@@ -295,23 +382,11 @@ void handle_follow_up(char *buf, __attribute__((unused)) ssize_t recv_len,
     clock_private_info->last_sync_time = reception_time;
   }
 
-  uint32_t old_flags = clock_private_info->flags;
-
   clock_private_info->local_time = reception_time;
   clock_private_info->source_time = preciseOriginTimestamp;
   clock_private_info->local_to_source_time_offset = offset;
 
-  if (old_flags != clock_private_info->flags) {
-    update_master();
-  } else if ((clock_private_info->flags & (1 << clock_is_master)) != 0) {
-    // if there were no prior samples, then this must be the first sample with this clock
-    // as master. Therefore set its mastership_start_time to the reception time.
-    if (clock_private_info->vacant_samples == (MAX_TIMING_SAMPLES - 1)) {
-      debug(2,"Clock %" PRIx64 " became a bus master with no valid prior samples -- this is its first one.", clock_private_info->clock_id);
-      clock_private_info->mastership_start_time = reception_time;
-    }
-
-
+  if ((clock_private_info->flags & (1 << clock_is_master)) != 0) {
     update_master_clock_info(clock_private_info->clock_id, (const char *)&clock_private_info->ip,
                              reception_time, offset, clock_private_info->mastership_start_time);
     debug(3, "clock: %" PRIx64 ", time: %" PRIu64 ", offset: %" PRId64 ", jitter: %+f ms.",
diff --git a/nqptp.c b/nqptp.c
index 603564a543c5af335a761b5cd34a2d047bd3510b..f90c364203167ef3346225d4c682b5eed2889432 100644 (file)
--- a/nqptp.c
+++ b/nqptp.c
@@ -66,7 +66,7 @@ int epoll_fd;
 void update_master_clock_info(uint64_t master_clock_id, const char *ip, uint64_t local_time,
                               uint64_t local_to_master_offset, uint64_t mastership_start_time) {
   if (shared_memory->master_clock_id != master_clock_id)
-    debug(1, "Master clock is: %" PRIx64 ".", master_clock_id);
+    debug_log_nqptp_status(1);
   int rc = pthread_mutex_lock(&shared_memory->shm_mutex);
   if (rc != 0)
     warn("Can't acquire mutex to update master clock!");