Files
utun2/src/ntp_node_time_doc.md
T

6.1 KiB
Raw Blame History

NTP Node Time

1. Назначение

Обмен временем с прямыми ETCP-пирами. Если у узла ещё нет поправки, он принимает время синхронизированного пира с оценкой сетевой задержки. Поправка хранится в instance->ntp и применяется getters из ntp_time.h; часы ОС не меняются. Отключение интернет-NTP (ntp.enabled=0) не отключает этот обмен. Уже синхронизированный узел повторно не принимает поправку от пиров, но интернет-NTP может её обновить.

2. Как пользоваться

В uasync-потоке после создания instance->connections вызвать ntp_node_time_init(). Он привязывает raw packet ID ETCP_ID_NTP_TIME = 0x04 (прямой ETCP, без роутера), подписывается на новые соединения и на INIT всех существующих, в том числе pending. На INIT отправляется TIME_SYNC; при запуске модуля пакет также отправляется уже инициализированным соединениям. Повторный активный init возвращает 0 без дублирования подписок. При занятом ID или ошибке регистрации возвращается -1; свои частичные регистрации снимаются.

TIME_SYNC — 10 байт: ID (1), flags (1, bit 0 = synced), время отправителя (int64 Unix мкс в нативном порядке байтов). Синхронизированный отправитель передаёт скорректированное время, остальные — локальное. При первом сообщении сохраняется исходное смещение для диагностики. Если получатель не синхронизирован, а отправитель синхронизирован, применяется:

offset_us = local_receive_us - sender_us - mean_link_rtt_us / 2.

Среднее RTT — арифметическое по всем элементам conn->links, включая нулевые значения и down-линки; rtt_last переводится из 0,1 мс в микросекунды. При отсутствии линков задержка считается нулевой. Это приближённая оценка: симметричность пути и точность часов пира не гарантируются.

После принятия поправки устанавливаются ntp.synced и ntp.last_sync_tb, затем время рассылается остальным. Синхронизированный получатель отвечает несинхронизированному отправителю. Когда оба синхронизированы, ответа нет — бесконечный обмен не возникает. Полученный entry и его dgram освобождаются при обработке, в том числе при заполненном кеше диагностики.

ntp_node_sync_peers() рассылает время по соединениям с initialized && links_up, если модуль активен и есть поправка. Вызывается также после успешной интернет-NTP-синхронизации.

Нюансы:

  • Кеш содержит до 32 диагностических записей, а не ограничивает число соседей. При заполнении вытесняется запись с наименьшим last_seen_tb (при равенстве — первая по индексу); исходное смещение новой записи сбрасывается.
  • Диагностическое смещение — raw_local_receive_us - sender_us, без вычитания задержки. Оно отличается от глобальной поправки, принятой с оценкой половины RTT.
  • При повторном сообщении модуль сравнивает смещение с предыдущим. Модуль разности строго >2 с даёт WARN, строго >10 с — ERROR. Это изменение относительного смещения: оно может включать коррекцию часов отправителя и изменение задержки, а не только дрейф часов.
  • destroy вызывается в uasync-потоке вне callbacks модуля/соединений. Снимает raw binding, подписку новых соединений и свои callbacks со всех текущих соединений, очищает кеш. Глобальную поправку не меняет. Повторный вызов и NULL безопасны.

3. API

Структуры:

  • struct NTP_NODE_PEER — ID пира, предыдущее диагностическое смещение, наличие исходного значения и время последнего обновления.
  • struct NTP_NODE_TIME — кеш, число занятых записей и флаг активности; контракты полей/функций описаны в ntp_node_time.h.

Функции:

  • ntp_node_time_init(inst) — 0 при успехе/уже активном модуле, -1 при ошибке; inst и очередь connections обязательны.
  • ntp_node_time_destroy(inst) — снимает регистрации и очищает кеш, сохраняя глобальную поправку.
  • ntp_node_sync_peers(inst) — рассылает время готовым прямым соседям; для NULL/неактивного/несинхронизированного модуля ничего не делает.