/* RX and TX timestamp saved for clients using interleaved mode */
typedef struct {
uint64_t rx_ts;
- uint16_t flags;
+ uint8_t flags;
+ uint8_t tx_ts_source;
uint16_t slew_epoch;
int32_t tx_ts_offset;
} NtpTimestamps;
/* Maximum number of timestamps moved in the array to insert a new timestamp */
#define NTPTS_INSERT_LIMIT 64
+/* Maximum expected value of the timestamp source */
+#define MAX_NTP_TS NTP_TS_HARDWARE
+
/* Global statistics */
static uint32_t total_hits[MAX_SERVICES];
static uint32_t total_drops[MAX_SERVICES];
/* ================================================== */
static void
-set_ntp_tx_offset(NtpTimestamps *tss, NTP_int64 *rx_ts, struct timespec *tx_ts)
+set_ntp_tx(NtpTimestamps *tss, NTP_int64 *rx_ts, struct timespec *tx_ts,
+ NTP_Timestamp_Source tx_src)
{
struct timespec ts;
tss->tx_ts_offset = (int32_t)ts.tv_nsec + (int32_t)ts.tv_sec * (int32_t)NSEC_PER_SEC;
tss->flags |= NTPTS_VALID_TX;
+ tss->tx_ts_source = tx_src;
}
/* ================================================== */
static void
-get_ntp_tx(NtpTimestamps *tss, struct timespec *tx_ts)
+get_ntp_tx(NtpTimestamps *tss, struct timespec *tx_ts, NTP_Timestamp_Source *tx_src)
{
int32_t offset = tss->tx_ts_offset;
NTP_int64 ntp_ts;
} else {
UTI_ZeroTimespec(tx_ts);
}
+
+ *tx_src = tss->tx_ts_source;
}
/* ================================================== */
void
-CLG_SaveNtpTimestamps(NTP_int64 *rx_ts, struct timespec *tx_ts)
+CLG_SaveNtpTimestamps(NTP_int64 *rx_ts, struct timespec *tx_ts, NTP_Timestamp_Source tx_src)
{
NtpTimestamps *tss;
uint32_t i, index;
tss->rx_ts = rx;
tss->flags = 0;
tss->slew_epoch = ntp_ts_map.slew_epoch;
- set_ntp_tx_offset(tss, rx_ts, tx_ts);
+ set_ntp_tx(tss, rx_ts, tx_ts, tx_src);
DEBUG_LOG("Saved RX+TX index=%"PRIu32" first=%"PRIu32" size=%"PRIu32,
index, ntp_ts_map.first, ntp_ts_map.size);
/* ================================================== */
void
-CLG_UpdateNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts)
+CLG_UpdateNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts,
+ NTP_Timestamp_Source tx_src)
{
uint32_t index;
if (!find_ntp_rx_ts(ntp64_to_int64(rx_ts), &index))
return;
- set_ntp_tx_offset(get_ntp_tss(index), rx_ts, tx_ts);
+ set_ntp_tx(get_ntp_tss(index), rx_ts, tx_ts, tx_src);
}
/* ================================================== */
int
-CLG_GetNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts)
+CLG_GetNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts,
+ NTP_Timestamp_Source *tx_src)
{
NtpTimestamps *tss;
uint32_t index;
if (tss->flags & NTPTS_DISABLED)
return 0;
- get_ntp_tx(tss, tx_ts);
+ get_ntp_tx(tss, tx_ts, tx_src);
return 1;
}
ntp_rx = message->originate_ts;
local_ntp_rx = &ntp_rx;
UTI_ZeroTimespec(&local_tx.ts);
- interleaved = CLG_GetNtpTxTimestamp(&ntp_rx, &local_tx.ts);
+ local_tx.source = NTP_TS_DAEMON;
+ interleaved = CLG_GetNtpTxTimestamp(&ntp_rx, &local_tx.ts, &local_tx.source);
tx_ts = &local_tx;
if (interleaved)
return;
if (local_ntp_rx)
- CLG_SaveNtpTimestamps(local_ntp_rx, &tx_ts->ts);
+ CLG_SaveNtpTimestamps(local_ntp_rx, &tx_ts->ts, tx_ts->source);
}
/* ================================================== */
local_ntp_rx = &message->receive_ts;
new_tx = *tx_ts;
- if (!CLG_GetNtpTxTimestamp(local_ntp_rx, &old_tx.ts))
+ if (!CLG_GetNtpTxTimestamp(local_ntp_rx, &old_tx.ts, &old_tx.source))
return;
/* Undo a clock adjustment between the RX and TX timestamps to minimise error
update_tx_timestamp(&old_tx, &new_tx, local_ntp_rx, NULL, message);
- CLG_UpdateNtpTxTimestamp(local_ntp_rx, &new_tx.ts);
+ CLG_UpdateNtpTxTimestamp(local_ntp_rx, &new_tx.ts, new_tx.source);
}
/* ================================================== */
{
uint64_t ts64, prev_first_ts64, prev_last_ts64, max_step;
uint32_t index2, prev_first, prev_size;
+ NTP_Timestamp_Source ts_src, ts_src2;
struct timespec ts, ts2;
int i, j, k, index, shift;
CLG_Service s;
TEST_CHECK(!ntp_ts_map.timestamps);
UTI_ZeroNtp64(&ntp_ts);
- CLG_SaveNtpTimestamps(&ntp_ts, NULL);
+ CLG_SaveNtpTimestamps(&ntp_ts, NULL, 0);
TEST_CHECK(ntp_ts_map.timestamps);
TEST_CHECK(ntp_ts_map.first == 0);
TEST_CHECK(ntp_ts_map.size == 0);
UTI_ZeroTimespec(&ts);
}
+ ts_src = random() % (MAX_NTP_TS + 1);
CLG_SaveNtpTimestamps(&ntp_ts,
- UTI_IsZeroTimespec(&ts) ? (random() % 2 ? &ts : NULL) : &ts);
+ UTI_IsZeroTimespec(&ts) ? (random() % 2 ? &ts : NULL) : &ts,
+ ts_src);
if (j < ntp_ts_map.max_size) {
TEST_CHECK(ntp_ts_map.size == j + 1);
}
TEST_CHECK(ntp_ts_map.cached_index == ntp_ts_map.size - 1);
TEST_CHECK(get_ntp_tss(ntp_ts_map.size - 1)->slew_epoch == ntp_ts_map.slew_epoch);
- TEST_CHECK(CLG_GetNtpTxTimestamp(&ntp_ts, &ts2));
+ TEST_CHECK(CLG_GetNtpTxTimestamp(&ntp_ts, &ts2, &ts_src2));
TEST_CHECK(UTI_CompareTimespecs(&ts, &ts2) == 0);
+ TEST_CHECK(UTI_IsZeroTimespec(&ts) || ts_src == ts_src2);
for (k = random() % 4; k > 0; k--) {
index2 = random() % ntp_ts_map.size;
int64_to_ntp64(get_ntp_tss(index2)->rx_ts, &ntp_ts);
if (random() % 2)
- TEST_CHECK(CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
+ TEST_CHECK(CLG_GetNtpTxTimestamp(&ntp_ts, &ts, &ts_src2));
UTI_Ntp64ToTimespec(&ntp_ts, &ts);
UTI_AddDoubleToTimespec(&ts, TST_GetRandomDouble(-1.999, 1.999), &ts);
1.0e-9);
}
- CLG_UpdateNtpTxTimestamp(&ntp_ts, &ts);
+ ts_src = random() % (MAX_NTP_TS + 1);
+ CLG_UpdateNtpTxTimestamp(&ntp_ts, &ts, ts_src);
- TEST_CHECK(CLG_GetNtpTxTimestamp(&ntp_ts, &ts2));
+ TEST_CHECK(CLG_GetNtpTxTimestamp(&ntp_ts, &ts2, &ts_src2));
TEST_CHECK(UTI_CompareTimespecs(&ts, &ts2) == 0);
+ TEST_CHECK(ts_src == ts_src2);
if (random() % 2) {
uint16_t prev_epoch = ntp_ts_map.slew_epoch;
index = random() % (ntp_ts_map.size - 1);
if (get_ntp_tss(index)->rx_ts + 1 != get_ntp_tss(index + 1)->rx_ts) {
int64_to_ntp64(get_ntp_tss(index)->rx_ts + 1, &ntp_ts);
- TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
+ TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts, &ts_src2));
int64_to_ntp64(get_ntp_tss(index + 1)->rx_ts - 1, &ntp_ts);
- TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
- CLG_UpdateNtpTxTimestamp(&ntp_ts, &ts);
+ TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts, &ts_src2));
+ CLG_UpdateNtpTxTimestamp(&ntp_ts, &ts, ts_src);
CLG_UndoNtpTxTimestampSlew(&ntp_ts, &ts);
}
}
if (random() % 2) {
int64_to_ntp64(get_ntp_tss(0)->rx_ts - 1, &ntp_ts);
- TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
+ TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts, &ts_src2));
int64_to_ntp64(get_ntp_tss(ntp_ts_map.size - 1)->rx_ts + 1, &ntp_ts);
- TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
- CLG_UpdateNtpTxTimestamp(&ntp_ts, &ts);
+ TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts, &ts_src2));
+ CLG_UpdateNtpTxTimestamp(&ntp_ts, &ts, ts_src);
CLG_UndoNtpTxTimestampSlew(&ntp_ts, &ts);
}
}
while (ntp_ts_map.size < ntp_ts_map.max_size) {
ts64 += get_random64() >> (shift + 8);
int64_to_ntp64(ts64, &ntp_ts);
- CLG_SaveNtpTimestamps(&ntp_ts, NULL);
+ CLG_SaveNtpTimestamps(&ntp_ts, NULL, 0);
if (ntp_ts_map.cached_index + NTPTS_INSERT_LIMIT < ntp_ts_map.size)
ts64 = get_ntp_tss(ntp_ts_map.size - 1)->rx_ts;
}
prev_size = ntp_ts_map.size;
prev_first_ts64 = get_ntp_tss(0)->rx_ts;
prev_last_ts64 = get_ntp_tss(prev_size - 1)->rx_ts;
- CLG_SaveNtpTimestamps(&ntp_ts, NULL);
+ CLG_SaveNtpTimestamps(&ntp_ts, NULL, 0);
TEST_CHECK(find_ntp_rx_ts(ts64, &index2));
if (random() % 10 == 0) {
CLG_DisableNtpTimestamps(&ntp_ts);
- TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
+ TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts, &ts_src2));
}
for (k = random() % 10; k > 0; k--) {
ts64 = get_random64() >> shift;
int64_to_ntp64(ts64, &ntp_ts);
- CLG_GetNtpTxTimestamp(&ntp_ts, &ts);
+ CLG_GetNtpTxTimestamp(&ntp_ts, &ts, &ts_src2);
}
}
LCL_ChangeUnknownStep, NULL);
TEST_CHECK(ntp_ts_map.size == 0);
TEST_CHECK(ntp_ts_map.cached_rx_ts == 0ULL);
- TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
- CLG_UpdateNtpTxTimestamp(&ntp_ts, &ts);
+ TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts, &ts_src2));
+ CLG_UpdateNtpTxTimestamp(&ntp_ts, &ts, ts_src);
}
}