]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
ntp: add options for compensating HW timestamping errors
authorMiroslav Lichvar <mlichvar@redhat.com>
Thu, 5 Jan 2017 15:37:28 +0000 (16:37 +0100)
committerMiroslav Lichvar <mlichvar@redhat.com>
Fri, 6 Jan 2017 12:12:19 +0000 (13:12 +0100)
conf.c
conf.h
doc/chrony.conf.adoc
ntp_io.c
ntp_io_linux.c

diff --git a/conf.c b/conf.c
index 5de7f427a7293a5846873d306683c98e3954cd3d..346fce1da446eadf835d012247a3f79d171dfc4c 100644 (file)
--- a/conf.c
+++ b/conf.c
@@ -223,7 +223,13 @@ static char *leapsec_tz = NULL;
 /* Name of the user to which will be dropped root privileges. */
 static char *user;
 
-/* Array of strings for interfaces with HW timestamping */
+typedef struct {
+  char *name;
+  double tx_comp;
+  double rx_comp;
+} HwTs_Interface;
+
+/* Array of HwTs_Interface */
 static ARR_Instance hwts_interfaces;
 
 typedef struct {
@@ -327,7 +333,7 @@ CNF_Initialise(int r)
 {
   restarted = r;
 
-  hwts_interfaces = ARR_CreateInstance(sizeof (char *));
+  hwts_interfaces = ARR_CreateInstance(sizeof (HwTs_Interface));
 
   init_sources = ARR_CreateInstance(sizeof (IPAddr));
   ntp_sources = ARR_CreateInstance(sizeof (NTP_Source));
@@ -354,7 +360,7 @@ CNF_Finalise(void)
   unsigned int i;
 
   for (i = 0; i < ARR_GetSize(hwts_interfaces); i++)
-    Free(*(char **)ARR_GetElement(hwts_interfaces, i));
+    Free(((HwTs_Interface *)ARR_GetElement(hwts_interfaces, i))->name);
   ARR_DestroyInstance(hwts_interfaces);
 
   for (i = 0; i < ARR_GetSize(ntp_sources); i++)
@@ -1245,8 +1251,39 @@ parse_tempcomp(char *line)
 static void
 parse_hwtimestamp(char *line)
 {
-  check_number_of_args(line, 1);
-  *(char **)ARR_GetNewElement(hwts_interfaces) = Strdup(line);
+  HwTs_Interface *iface;
+  char *p;
+  int n;
+
+  if (!*line) {
+    command_parse_error();
+    return;
+  }
+
+  p = line;
+  line = CPS_SplitWord(line);
+
+  iface = ARR_GetNewElement(hwts_interfaces);
+  iface->name = Strdup(p);
+  iface->tx_comp = 0.0;
+  iface->rx_comp = 0.0;
+
+  for (p = line; *p; line += n, p = line) {
+    line = CPS_SplitWord(line);
+
+    if (!strcasecmp(p, "rxcomp")) {
+      if (sscanf(line, "%lf%n", &iface->rx_comp, &n) != 1)
+        break;
+    } else if (!strcasecmp(p, "txcomp")) {
+      if (sscanf(line, "%lf%n", &iface->tx_comp, &n) != 1)
+        break;
+    } else {
+      break;
+    }
+  }
+
+  if (*p)
+    command_parse_error();
 }
 
 /* ================================================== */
@@ -1930,8 +1967,18 @@ CNF_GetInitStepThreshold(void)
 
 /* ================================================== */
 
-ARR_Instance
-CNF_GetHwTsInterfaces(void)
+int
+CNF_GetHwTsInterface(unsigned int index, char **name, double *tx_comp, double *rx_comp)
 {
-  return hwts_interfaces;
+  HwTs_Interface *iface;
+
+  if (index >= ARR_GetSize(hwts_interfaces))
+    return 0;
+
+  iface = ARR_GetElement(hwts_interfaces, index);
+  *name = iface->name;
+  *tx_comp = iface->tx_comp;
+  *rx_comp = iface->rx_comp;
+
+  return 1;
 }
diff --git a/conf.h b/conf.h
index d24166503c18ca20e5659a10f480bf22e16bfbf8..a24b8d9f6beece0397198e94dfd30ae9bed1f1f5 100644 (file)
--- a/conf.h
+++ b/conf.h
@@ -29,7 +29,6 @@
 #define GOT_CONF_H
 
 #include "addressing.h"
-#include "array.h"
 #include "reference.h"
 
 extern void CNF_Initialise(int restarted);
@@ -120,6 +119,6 @@ extern char *CNF_GetHwclockFile(void);
 extern int CNF_GetInitSources(void);
 extern double CNF_GetInitStepThreshold(void);
 
-extern ARR_Instance CNF_GetHwTsInterfaces(void);
+extern int CNF_GetHwTsInterface(unsigned int index, char **name, double *tx_comp, double *rx_comp);
 
 #endif /* GOT_CONF_H */
index f1b5f0ebbfe86c55d7376ed8d6b99efda0d8891e..ca454da7800854201293747bc73a3f70e3991793 100644 (file)
@@ -1776,7 +1776,7 @@ sendmail binary.
 
 === Miscellaneous
 
-[[hwtimestamp]]*hwtimestamp* _interface_::
+[[hwtimestamp]]*hwtimestamp* _interface_ [_option_]...::
 This directive enables hardware timestamping of NTP packets sent to and
 received from the specified network interface. The network interface controller
 (NIC) uses its own clock to accurately timestamp the actual transmissions and
@@ -1807,10 +1807,25 @@ and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in *chronyc*.
 If the specified interface is _*_, *chronyd* will try to enable HW timestamping
 on all available interfaces.
 +
-An example of the directive is:
+The *hwtimestamp* directive has the following options:
++
+*txcomp* _compensation_:::
+This option specifies the difference in seconds between the actual transmission
+time at the physical layer and the reported transmit timestamp. This value will
+be added to transmit timestamps obtained from the NIC. The default value is 0.
+*rxcomp* _compensation_:::
+This option specifies the difference in seconds between the reported receive
+timestamp and the actual reception time at the physical layer. This value will
+be subtracted from receive timestamps obtained from the NIC. The default value
+is 0.
+::
++
+Examples of the directive are:
 +
 ----
 hwtimestamp eth0
+hwtimestamp eth1 txcomp 300e-9 rxcomp 645e-9
+hwtimestamp *
 ----
 
 [[include]]*include* _pattern_::
index 380e2f1795bc47c1efd205e2f674b434d7aa8a51..884344977607e2a16137a508b172acb5ba0af423 100644 (file)
--- a/ntp_io.c
+++ b/ntp_io.c
@@ -364,8 +364,12 @@ NIO_Initialise(int family)
 #ifdef HAVE_LINUX_TIMESTAMPING
   NIO_Linux_Initialise();
 #else
-  if (ARR_GetSize(CNF_GetHwTsInterfaces()))
-    LOG_FATAL(LOGF_NtpIO, "HW timestamping not supported");
+  if (1) {
+    double tx_comp, rx_comp;
+    char *name;
+    if (CNF_GetHwTsInterface(0, &name, &tx_comp, &rx_comp))
+      LOG_FATAL(LOGF_NtpIO, "HW timestamping not supported");
+  }
 #endif
 
   recv_messages = ARR_CreateInstance(sizeof (struct Message));
index 7ea15f15695e8796016e93ac191ad0b991d53b2b..cbfe6ab711a948042a35b6bb476474de8967873d 100644 (file)
@@ -66,6 +66,9 @@ struct Interface {
   /* Start of UDP data at layer 2 for IPv4 and IPv6 */
   int l2_udp4_ntp_start;
   int l2_udp6_ntp_start;
+  /* Compensation of errors in TX and RX timestamping */
+  double tx_comp;
+  double rx_comp;
   HCL_Instance clock;
 };
 
@@ -88,7 +91,7 @@ static int permanent_ts_options;
 /* ================================================== */
 
 static int
-add_interface(const char *name)
+add_interface(const char *name, double tx_comp, double rx_comp)
 {
   struct ethtool_ts_info ts_info;
   struct hwtstamp_config ts_config;
@@ -169,6 +172,9 @@ add_interface(const char *name)
   iface->l2_udp4_ntp_start = 42;
   iface->l2_udp6_ntp_start = 62;
 
+  iface->tx_comp = tx_comp;
+  iface->rx_comp = rx_comp;
+
   iface->clock = HCL_CreateInstance();
 
   DEBUG_LOG(LOGF_NtpIOLinux, "Enabled HW timestamping on %s", name);
@@ -179,7 +185,7 @@ add_interface(const char *name)
 /* ================================================== */
 
 static int
-add_all_interfaces(void)
+add_all_interfaces(double tx_comp, double rx_comp)
 {
   struct ifaddrs *ifaddr, *ifa;
   int r;
@@ -190,7 +196,7 @@ add_all_interfaces(void)
   }
 
   for (r = 0, ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
-    if (add_interface(ifa->ifa_name))
+    if (add_interface(ifa->ifa_name, tx_comp, rx_comp))
       r = 1;
   }
   
@@ -236,34 +242,30 @@ update_interface_speed(struct Interface *iface)
 void
 NIO_Linux_Initialise(void)
 {
-  ARR_Instance config_hwts_ifaces;
-  char *if_name;
+  double tx_comp, rx_comp;
+  char *name;
   unsigned int i;
-  int wildcard, hwts;
+  int hwts;
 
   interfaces = ARR_CreateInstance(sizeof (struct Interface));
 
-  config_hwts_ifaces = CNF_GetHwTsInterfaces();
-
   /* Enable HW timestamping on specified interfaces.  If "*" was specified, try
      all interfaces.  If no interface was specified, enable SW timestamping. */
 
-  for (i = wildcard = 0; i < ARR_GetSize(config_hwts_ifaces); i++) {
-    if (!strcmp("*", *(char **)ARR_GetElement(config_hwts_ifaces, i)))
-      wildcard = 1;
+  for (i = hwts = 0; CNF_GetHwTsInterface(i, &name, &tx_comp, &rx_comp); i++) {
+    if (!strcmp("*", name))
+      continue;
+    if (!add_interface(name, tx_comp, rx_comp))
+      LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", name);
+    hwts = 1;
   }
 
-  if (!wildcard && ARR_GetSize(config_hwts_ifaces)) {
-    for (i = 0; i < ARR_GetSize(config_hwts_ifaces); i++) {
-      if_name = *(char **)ARR_GetElement(config_hwts_ifaces, i);
-      if (!add_interface(if_name))
-        LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", if_name);
-    }
-    hwts = 1;
-  } else if (wildcard && add_all_interfaces()) {
-    hwts = 1;
-  } else {
-    hwts = 0;
+  for (i = 0; CNF_GetHwTsInterface(i, &name, &tx_comp, &rx_comp); i++) {
+    if (strcmp("*", name))
+      continue;
+    if (add_all_interfaces(tx_comp, rx_comp))
+      hwts = 1;
+    break;
   }
 
   if (hwts) {
@@ -447,6 +449,11 @@ process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
     UTI_AddDoubleToTimespec(hw_ts, rx_correction, hw_ts);
   }
 
+  if (!rx_ntp_length && iface->tx_comp)
+    UTI_AddDoubleToTimespec(hw_ts, iface->tx_comp, hw_ts);
+  else if (rx_ntp_length && iface->rx_comp)
+    UTI_AddDoubleToTimespec(hw_ts, -iface->rx_comp, hw_ts);
+
   if (!HCL_CookTime(iface->clock, hw_ts, &ts, &err))
     return;