ntp: add alternative method of retrieving transmitted messages

When chronyd gets a kernel or hardware transmit timestamp after sending
an NTP message to a server, peer, or client (using interleaved mode), it
needs the address and content of the message to be able to correctly
assign the timestamp to the server, peer, or client. The timestamps are
processed asynchronously. The kernel provides with each timestamp the
data-link frame that was timestamped, but chronyd can extract the
necessary data only from plain IPv4 and IPv6 packets in Ethernet frames,
possibly including VLAN tags. If the NTP packets are transmitted by a
non-Ethernet device, or they are encapsulated in another layer (e.g. a
WireGuard tunnel), chronyd is not able to extract the data and use the
kernel or hardware transmit timestamps, having to fall back to less
accurate daemon timestamps.

Add an alternative method using transmit IDs assigned to each message
(supported since Linux 6.13), which are provided by the kernel with the
timestamp in the error queue, and map them to messages, addresses and
ports saved in a ring buffer, whose size can be configured by the new
maxtxbuffers directive.

Fow now, set the default maxtxbuffers to 0 (disabled). If set to a
non-zero value, allocate the ring buffer to the maximum size on start.
As a future improvement, it could be allocated only when the extraction
of the UDP payload fails, or the extracted message is not the expected
NTP message. The size could grow dynamically when a transmit ID is
missed.
This commit is contained in:
Miroslav Lichvar
2025-11-13 16:02:17 +01:00
parent 4507359952
commit e5abf3ad2b
7 changed files with 176 additions and 6 deletions

13
conf.c
View File

@@ -300,6 +300,9 @@ static ARR_Instance hwts_interfaces;
/* Timeout for resuming reading from sockets waiting for HW TX timestamp */
static double hwts_timeout = 0.001;
/* Maximum number of saved messages for TX timestamp identification */
static int max_tx_buffers = 0;
/* PTP event port (disabled by default) */
static int ptp_port = 0;
/* PTP domain number of NTP-over-PTP messages */
@@ -708,6 +711,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
parse_int(p, &max_stratum, 0, INT_MAX);
} else if (!strcasecmp(command, "maxupdateskew")) {
parse_double(p, &max_update_skew);
} else if (!strcasecmp(command, "maxtxbuffers")) {
parse_int(p, &max_tx_buffers, 0, 1048576);
} else if (!strcasecmp(command, "minsamples")) {
parse_int(p, &min_samples, 0, INT_MAX);
} else if (!strcasecmp(command, "minsources")) {
@@ -2778,6 +2783,14 @@ CNF_GetHwTsTimeout(void)
/* ================================================== */
int
CNF_GetMaxTxBuffers(void)
{
return max_tx_buffers;
}
/* ================================================== */
int
CNF_GetPtpPort(void)
{