ntp: keep kernel RX timestamping permanently enabled on Linux
The Linux kernel has a counter for sockets using kernel RX timestamping and timestamps (all) received packets only when it is not zero. However, this counter is updated asynchronously from setsockopt(). If there are currently no other sockets using the timestamping, it is possible that a fast server response is received before the kernel timestamping is actually enabled after setting the socket option and sending a request. Open a dummy socket on start to make sure there is always at least one timestamping socket to avoid the race condition.
This commit is contained in:
parent
b563048ee2
commit
0df8328ceb
1 changed files with 35 additions and 0 deletions
|
@ -107,6 +107,12 @@ static SCH_TimeoutID resume_timeout_id;
|
|||
|
||||
#define RESUME_TIMEOUT 200.0e-6
|
||||
|
||||
/* Unbound socket keeping the kernel RX timestamping permanently enabled
|
||||
in order to avoid a race condition between receiving a server response
|
||||
and the kernel actually starting to timestamp received packets after
|
||||
enabling the timestamping and sending a request */
|
||||
static int dummy_rxts_socket;
|
||||
|
||||
#define INVALID_SOCK_FD -3
|
||||
|
||||
/* ================================================== */
|
||||
|
@ -316,6 +322,29 @@ check_timestamping_option(int option)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_dummy_socket(void)
|
||||
{
|
||||
int sock_fd, events = 0;
|
||||
|
||||
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0
|
||||
#ifdef FEAT_IPV6
|
||||
&& (sock_fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0
|
||||
#endif
|
||||
)
|
||||
return INVALID_SOCK_FD;
|
||||
|
||||
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, 1, &events)) {
|
||||
close(sock_fd);
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
UTI_FdSetCloexec(sock_fd);
|
||||
return sock_fd;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Linux_Initialise(void)
|
||||
{
|
||||
|
@ -368,6 +397,9 @@ NIO_Linux_Initialise(void)
|
|||
|
||||
monitored_socket = INVALID_SOCK_FD;
|
||||
suspended_socket = INVALID_SOCK_FD;
|
||||
|
||||
/* Open a socket to keep the kernel RX timestamping permanently enabled */
|
||||
dummy_rxts_socket = open_dummy_socket();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
@ -378,6 +410,9 @@ NIO_Linux_Finalise(void)
|
|||
struct Interface *iface;
|
||||
unsigned int i;
|
||||
|
||||
if (dummy_rxts_socket != INVALID_SOCK_FD)
|
||||
close(dummy_rxts_socket);
|
||||
|
||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||
iface = ARR_GetElement(interfaces, i);
|
||||
HCL_DestroyInstance(iface->clock);
|
||||
|
|
Loading…
Reference in a new issue