Blame SOURCES/chrony-timestamping.patch

ab3630
diff -up chrony-3.1/configure.timestamping chrony-3.1/configure
ab3630
--- chrony-3.1/configure.timestamping	2017-01-31 11:22:11.000000000 +0100
ab3630
+++ chrony-3.1/configure	2017-02-03 12:09:22.911633573 +0100
ab3630
@@ -651,8 +651,8 @@ if [ $feat_timestamping = "1" ] && [ $tr
ab3630
   test_code 'SW/HW timestamping' 'sys/types.h sys/socket.h linux/net_tstamp.h
ab3630
                                   linux/errqueue.h linux/ptp_clock.h' '' '' '
ab3630
     int val = SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE |
ab3630
-              SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_OPT_CMSG;
ab3630
-    return sizeof (struct scm_timestamping) + SCM_TSTAMP_SND + PTP_SYS_OFFSET +
ab3630
+              SOF_TIMESTAMPING_RAW_HARDWARE | 1;
ab3630
+    return 3 * sizeof (struct timespec) + 0 + PTP_SYS_OFFSET +
ab3630
            setsockopt(0, SOL_SOCKET, SO_SELECT_ERR_QUEUE + SO_TIMESTAMPING,
ab3630
                       &val, sizeof (val));'
ab3630
 then
ab3630
diff -up chrony-3.1/doc/chrony.conf.man.in.timestamping chrony-3.1/doc/chrony.conf.man.in
ab3630
--- chrony-3.1/doc/chrony.conf.man.in.timestamping	2017-01-31 11:34:16.000000000 +0100
ab3630
+++ chrony-3.1/doc/chrony.conf.man.in	2017-02-03 12:09:22.911633573 +0100
ab3630
@@ -3065,7 +3065,7 @@ timestamping. If the server or peer supp
ab3630
 be enabled by the \fBxleave\fP option in the \fBserver\fP or the
ab3630
 \fBpeer\fP directive.
ab3630
 .sp
ab3630
-This directive is supported on Linux 3.19 and newer. The NIC must support HW
ab3630
+This directive is supported on Linux. The NIC must support HW
ab3630
 timestamping, which can be verified with the \fBethtool \-T\fP command. The list of
ab3630
 capabilities should include \fISOF_TIMESTAMPING_RAW_HARDWARE\fP,
ab3630
 \fISOF_TIMESTAMPING_TX_HARDWARE\fP, \fISOF_TIMESTAMPING_RX_HARDWARE\fP, and the filter
ab3630
diff -up chrony-3.1/ntp_io_linux.c.timestamping chrony-3.1/ntp_io_linux.c
ab3630
--- chrony-3.1/ntp_io_linux.c.timestamping	2017-01-31 11:22:11.000000000 +0100
ab3630
+++ chrony-3.1/ntp_io_linux.c	2017-02-03 12:10:10.720767667 +0100
ab3630
@@ -36,6 +36,10 @@
ab3630
 #include <linux/sockios.h>
ab3630
 #include <net/if.h>
ab3630
 
ab3630
+/* Missing in older kernel headers */
ab3630
+#define SOF_TIMESTAMPING_OPT_CMSG (1<<10)
ab3630
+#define SCM_TSTAMP_SND 0
ab3630
+
ab3630
 #include "array.h"
ab3630
 #include "conf.h"
ab3630
 #include "hwclock.h"
ab3630
@@ -95,6 +99,10 @@ static int ts_tx_flags;
ab3630
 /* Flag indicating the socket options can't be changed in control messages */
ab3630
 static int permanent_ts_options;
ab3630
 
ab3630
+/* Index of a HW-timestamping interface, but only if the machine has not more
ab3630
+   than one */
ab3630
+static int single_hwts_if_index;
ab3630
+
ab3630
 /* ================================================== */
ab3630
 
ab3630
 static int
ab3630
@@ -253,6 +261,84 @@ update_interface_speed(struct Interface
ab3630
 
ab3630
 /* ================================================== */
ab3630
 
ab3630
+static int
ab3630
+check_sof_opt_cmsg()
ab3630
+{
ab3630
+  int sock_fd, flags;
ab3630
+
ab3630
+  sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
ab3630
+  if (sock_fd < 0)
ab3630
+    return 0;
ab3630
+
ab3630
+  flags = SOF_TIMESTAMPING_OPT_CMSG;
ab3630
+
ab3630
+  if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, &flags, sizeof (flags)) < 0) {
ab3630
+    DEBUG_LOG(LOGF_NtpIOLinux, "SOF_TIMESTAMPING_OPT_CMSG not supported");
ab3630
+    close(sock_fd);
ab3630
+    return 0;
ab3630
+  }
ab3630
+
ab3630
+  close(sock_fd);
ab3630
+  return 1;
ab3630
+}
ab3630
+
ab3630
+/* ================================================== */
ab3630
+
ab3630
+static int
ab3630
+get_single_hwts_index()
ab3630
+{
ab3630
+  struct ifaddrs *ifaddr, *ifa;
ab3630
+  struct ethtool_ts_info ts_info;
ab3630
+  struct ifreq req;
ab3630
+  int sock_fd, if_index, hwts_if_index = INVALID_IF_INDEX;
ab3630
+
ab3630
+  sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
ab3630
+  if (sock_fd < 0)
ab3630
+    return INVALID_IF_INDEX;
ab3630
+
ab3630
+  if (getifaddrs(&ifaddr)) {
ab3630
+    DEBUG_LOG(LOGF_NtpIOLinux, "getifaddrs() failed : %s", strerror(errno));
ab3630
+    close(sock_fd);
ab3630
+    return INVALID_IF_INDEX;
ab3630
+  }
ab3630
+
ab3630
+  for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
ab3630
+    memset(&req, 0, sizeof (req));
ab3630
+    memset(&ts_info, 0, sizeof (ts_info));
ab3630
+
ab3630
+    if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", ifa->ifa_name) >=
ab3630
+        sizeof (req.ifr_name))
ab3630
+      break;
ab3630
+
ab3630
+    if (ioctl(sock_fd, SIOCGIFINDEX, &req))
ab3630
+      break;
ab3630
+
ab3630
+    if_index = req.ifr_ifindex;
ab3630
+    ts_info.cmd = ETHTOOL_GET_TS_INFO;
ab3630
+    req.ifr_data = (char *)&ts_info;
ab3630
+
ab3630
+    if (ioctl(sock_fd, SIOCETHTOOL, &req))
ab3630
+      break;
ab3630
+
ab3630
+    if (ts_info.phc_index < 0)
ab3630
+      continue;
ab3630
+
ab3630
+    if (hwts_if_index != INVALID_IF_INDEX && hwts_if_index != if_index)
ab3630
+      break;
ab3630
+
ab3630
+    hwts_if_index = if_index;
ab3630
+  }
ab3630
+
ab3630
+  close(sock_fd);
ab3630
+  freeifaddrs(ifaddr);
ab3630
+
ab3630
+  if (ifa)
ab3630
+    return INVALID_IF_INDEX;
ab3630
+
ab3630
+  return hwts_if_index;
ab3630
+}
ab3630
+
ab3630
+/* ================================================== */
ab3630
 void
ab3630
 NIO_Linux_Initialise(void)
ab3630
 {
ab3630
@@ -289,8 +375,20 @@ NIO_Linux_Initialise(void)
ab3630
     ts_tx_flags = SOF_TIMESTAMPING_TX_SOFTWARE;
ab3630
   }
ab3630
 
ab3630
-  /* Enable IP_PKTINFO in messages looped back to the error queue */
ab3630
-  ts_flags |= SOF_TIMESTAMPING_OPT_CMSG;
ab3630
+  single_hwts_if_index = INVALID_IF_INDEX;
ab3630
+
ab3630
+  /* Enable IP_PKTINFO in messages looped back to the error queue if possible.
ab3630
+     If not, HW timestamping of IPv4 packets can be supported only with one
ab3630
+     interface capable of HW timestamping. */
ab3630
+  if (check_sof_opt_cmsg()) {
ab3630
+    ts_flags |= SOF_TIMESTAMPING_OPT_CMSG;
ab3630
+  } else if (ARR_GetSize(interfaces) > 0) {
ab3630
+    single_hwts_if_index = get_single_hwts_index();
ab3630
+    if (single_hwts_if_index == INVALID_IF_INDEX)
ab3630
+      LOG(LOGS_WARN, LOGF_NtpIOLinux, "Missing SOF_TIMESTAMPING_OPT_CMSG option for HW timestamping with multiple HW-timestamping interfaces");
ab3630
+    else
ab3630
+      LOG(LOGS_INFO, LOGF_NtpIOLinux, "Enabled single-interface HW-timestamping mode");
ab3630
+  }
ab3630
 
ab3630
   /* Kernels before 4.7 ignore timestamping flags set in control messages */
ab3630
   permanent_ts_options = !SYS_Linux_CheckKernelVersion(4, 7);
ab3630
@@ -499,7 +597,9 @@ NIO_Linux_ProcessMessage(NTP_Remote_Addr
ab3630
 
ab3630
   for (cmsg = CMSG_FIRSTHDR(hdr); cmsg; cmsg = CMSG_NXTHDR(hdr, cmsg)) {
ab3630
     if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING) {
ab3630
-      struct scm_timestamping ts3;
ab3630
+      struct {
ab3630
+        struct timespec ts[3];
ab3630
+      } ts3;
ab3630
 
ab3630
       memcpy(&ts3, CMSG_DATA(cmsg), sizeof (ts3));
ab3630
 
ab3630
@@ -507,6 +607,10 @@ NIO_Linux_ProcessMessage(NTP_Remote_Addr
ab3630
         LCL_CookTime(&ts3.ts[0], &local_ts->ts, &local_ts->err);
ab3630
         local_ts->source = NTP_TS_KERNEL;
ab3630
       } else if (!UTI_IsZeroTimespec(&ts3.ts[2])) {
ab3630
+        if (local_addr->if_index == INVALID_IF_INDEX &&
ab3630
+            single_hwts_if_index != INVALID_IF_INDEX)
ab3630
+          local_addr->if_index = single_hwts_if_index;
ab3630
+
ab3630
         iface = get_interface(local_addr->if_index);
ab3630
         if (iface) {
ab3630
           process_hw_timestamp(iface, &ts3.ts[2], local_ts, !is_tx ? length : 0,