diff --git a/conf.c b/conf.c index 0597836..54652a0 100644 --- a/conf.c +++ b/conf.c @@ -274,6 +274,9 @@ static int no_system_cert = 0; /* Array of CNF_HwTsInterface */ static ARR_Instance hwts_interfaces; +/* Timeout for resuming reading from sockets waiting for HW TX timestamp */ +static double hwts_timeout = 0.001; + /* PTP event port (disabled by default) */ static int ptp_port = 0; @@ -602,6 +605,8 @@ CNF_ParseLine(const char *filename, int number, char *line) parse_string(p, &hwclock_file); } else if (!strcasecmp(command, "hwtimestamp")) { parse_hwtimestamp(p); + } else if (!strcasecmp(command, "hwtstimeout")) { + parse_double(p, &hwts_timeout); } else if (!strcasecmp(command, "include")) { parse_include(p); } else if (!strcasecmp(command, "initstepslew")) { @@ -2505,6 +2510,14 @@ CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface) /* ================================================== */ +double +CNF_GetHwTsTimeout(void) +{ + return hwts_timeout; +} + +/* ================================================== */ + int CNF_GetPtpPort(void) { diff --git a/conf.h b/conf.h index d7acb4f..5ce6559 100644 --- a/conf.h +++ b/conf.h @@ -154,6 +154,7 @@ typedef struct { } CNF_HwTsInterface; extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface); +extern double CNF_GetHwTsTimeout(void); extern int CNF_GetPtpPort(void); diff --git a/doc/chrony.conf.adoc b/doc/chrony.conf.adoc index f4dff33..b1e489c 100644 --- a/doc/chrony.conf.adoc +++ b/doc/chrony.conf.adoc @@ -2606,6 +2606,31 @@ hwtimestamp eth1 txcomp 300e-9 rxcomp 645e-9 hwtimestamp * ---- +[[hwtstimeout]]*hwtstimeout* _timeout_:: +If hardware timestamping is used with a close NTP server, or the NIC or its +driver is slow in providing the transmit timestamp of NTP requests, a response +from the server can be received before the transmit timestamp of the request. +To avoid calculating the offset with a less accurate transmit timestamp, +*chronyd* suspends reading of NTP packets from the socket until the hardware +transmit timestamp is provided. There is no guarantee that the timestamp will +actually be provided (NICs typically have a limited rate of transmit +timestamping). This directive configures how long should *chronyd* wait +for the timestamp before resuming reading from the socket. ++ +The suspension is activated only on sockets that are not expected to receive +requests, i.e. it does not work with the *peer* directive and also with the +*server* and *pool* directives if the ports specified by the *port* and +*acquisitionport* directives are equal. ++ +The default value is 0.001 seconds, which should be sufficient with most +hardware. If you frequently see kernel transmit timestamps in the +_measurements.log_ file or <> report, and it is +not a server handling a high rate of requests in the interleaved mode on the +same interface (which would compete with timestamping of the server's own +requests), increasing the timeout to 0.01 or possibly even longer might help. +Note that setting a timeout longer than the NTP polling interval causes the +responses to be ignored when the timestamp is missing. + [[keyfile]]*keyfile* _file_:: This directive is used to specify the location of the file containing symmetric keys which are shared between NTP servers and clients, or peers, in order to diff --git a/ntp_io_linux.c b/ntp_io_linux.c index b3d828e..3f0620a 100644 --- a/ntp_io_linux.c +++ b/ntp_io_linux.c @@ -91,8 +91,6 @@ static int permanent_ts_options; suspend reading of packets from the receive queue until a HW transmit timestamp is received from the error queue or a timeout reached. */ -#define RESUME_TIMEOUT 0.001 - struct HwTsSocket { int sock_fd; int suspended; @@ -546,15 +544,16 @@ static void suspend_socket(int sock_fd) { struct HwTsSocket *ts_sock = get_hw_ts_socket(sock_fd, 1); + double timeout = CNF_GetHwTsTimeout(); - if (!ts_sock) + if (!ts_sock || timeout <= 0.0) return; /* Remove previous timeout if there is one */ SCH_RemoveTimeout(ts_sock->timeout_id); ts_sock->suspended = 1; - ts_sock->timeout_id = SCH_AddTimeoutByDelay(RESUME_TIMEOUT, resume_timeout, ts_sock); + ts_sock->timeout_id = SCH_AddTimeoutByDelay(timeout, resume_timeout, ts_sock); SCH_SetFileHandlerEvent(ts_sock->sock_fd, SCH_FILE_INPUT, 0); DEBUG_LOG("Suspended RX processing fd=%d", ts_sock->sock_fd);