ntp: improve detection of missed packets in interleaved mode

In interleaved symmetric mode, check if the remote TX timestamp is
before RX timestamp. Only the first response from the peer after
receiving a request should pass this test. Check also the interval
between last two remote transmit timestamps when we know the remote poll
can't be constrained by minpoll. Use the minimum of previous remote and
local poll as a lower bound of the actual interval between peer's
transmissions.
This commit is contained in:
Miroslav Lichvar 2017-08-01 12:42:35 +02:00
parent e1645966ec
commit 2668a12e4e

View file

@ -178,8 +178,9 @@ struct NCR_Instance_Record {
NTP_int64 local_ntp_tx;
NTP_Local_Timestamp local_tx;
/* Previous local transmit timestamp for the interleaved mode */
/* Previous values of some variables needed in interleaved mode */
NTP_Local_Timestamp prev_local_tx;
int prev_local_poll;
/* The instance record in the main source management module. This
performs the statistical analysis on the samples we generate */
@ -655,6 +656,7 @@ NCR_ResetInstance(NCR_Instance instance)
UTI_ZeroNtp64(&instance->local_ntp_tx);
zero_local_timestamp(&instance->local_rx);
zero_local_timestamp(&instance->prev_local_tx);
instance->prev_local_poll = 0;
}
/* ================================================== */
@ -1424,7 +1426,8 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
if (synced_packet && (!interleaved_packet || inst->valid_timestamps)) {
/* These are the timespec equivalents of the remote and local epochs */
struct timespec remote_receive, remote_transmit, remote_request_receive;
struct timespec local_average, remote_average;
struct timespec local_average, remote_average, prev_remote_transmit;
double prev_remote_poll_interval;
/* Select remote and local timestamps for the new sample */
if (interleaved_packet) {
@ -1444,10 +1447,12 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
local_transmit = inst->local_tx;
}
UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
UTI_Ntp64ToTimespec(&inst->remote_ntp_tx, &prev_remote_transmit);
local_receive = inst->local_rx;
} else {
UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
UTI_ZeroTimespec(&prev_remote_transmit);
remote_request_receive = remote_receive;
local_receive = *rx_ts;
local_transmit = inst->local_tx;
@ -1491,20 +1496,28 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
dispersion = MAX(precision, MAX(local_transmit.err, local_receive.err)) +
skew * fabs(local_interval);
/* If the source is an active peer, this is the minimum assumed interval
between previous two transmissions (if not constrained by minpoll) */
prev_remote_poll_interval = UTI_Log2ToDouble(MIN(inst->remote_poll,
inst->prev_local_poll));
/* Additional tests required to pass before accumulating the sample */
/* Test A requires that the minimum estimate of the peer delay is not
larger than the configured maximum, in client mode that the server
processing time is sane, in the interleaved client mode that the
timestamps are not too old, and in the interleaved symmetric mode
that the delay is not longer than half of the remote polling interval
to detect missed packets */
larger than the configured maximum, in both client modes that the server
processing time is sane, in interleaved client mode that the timestamps
are not too old, and in interleaved symmetric mode that the delay and
intervals between remote timestamps don't indicate a missed response */
testA = delay - dispersion <= inst->max_delay && precision <= inst->max_delay &&
!(inst->mode == MODE_CLIENT &&
(response_time > MAX_SERVER_INTERVAL ||
(interleaved_packet && inst->tx_count > MAX_CLIENT_INTERLEAVED_TX + 1))) &&
!(inst->mode == MODE_ACTIVE && interleaved_packet &&
delay > UTI_Log2ToDouble(message->poll - 1));
(delay > 0.5 * prev_remote_poll_interval ||
UTI_CompareNtp64(&message->receive_ts, &message->transmit_ts) <= 0 ||
(inst->remote_poll <= inst->prev_local_poll &&
UTI_DiffTimespecsToDouble(&remote_transmit, &prev_remote_transmit) >
1.5 * prev_remote_poll_interval)));
/* Test B requires in client mode that the ratio of the round trip delay
to the minimum one currently in the stats data register is less than an
@ -1610,7 +1623,9 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
inst->remote_stratum = message->stratum != NTP_INVALID_STRATUM ?
message->stratum : NTP_MAX_STRATUM;
inst->prev_local_poll = inst->local_poll;
inst->tx_count = 0;
SRC_UpdateReachability(inst->source, synced_packet);
if (good_packet) {