Какой фактический временной момент генерируется SOF_TIMESTAMPING_RX_SOFTWARE для данных tcp bytestream?

Вопрос или проблема

Я изучаю, как использовать опцию SO_TIMESTAMPING, чтобы получать временные метки для измерения задержки моего приложения, которое использует TCP для передачи данных. Сетевой адаптер моего тестового сервера поддерживает SOF_TIMESTAMPING_SOFTWARE, так что мне удалось использовать сокетную опцию SO_TIMESTAMPING с SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE и recvmsg для получения временных меток. Сначала все казалось, что работает хорошо.

Однако, когда я провел тест ниже, я обнаружил, что временная метка на самом деле не является временем, когда байты были получены сетевым адаптером.

ТЕСТ

  • TCP-сервер принимает входящие клиентские соединения и записывает 20B данных 20 раз, спя 1 секунду после каждой записи. Для серверного сокета установлена опция TCP_NODELAY.
  • TCP-клиент спит 20 секунд после подключения к серверу (т.е. до завершения записи на сервере), а затем вызывает recvmsg с размером буфера 20B, так что он вызовет recvmsg 20 раз и получит 20 RX временных меток.

Поскольку сервер включает TCP_NODELAY, я ожидаю, что каждая запись сервера будет немедленно создавать пакет с 20B TCP полезной нагрузки, и клиент будет получать этот пакет и ставить на него временную метку каждый раз, когда пакет приходит, даже если клиент спит и еще не вызывает recvmsg. Используя tcpdump на стороне клиента, вывод показывает, что пакеты действительно принимаются один за другим, каждую секунду.

Однако мой тест показывает, что все 20 вызовов recvmsg имеют одинаковую RX временную метку, которая является временем последнего пакета.

Вывод (индекс чтения, RX временная метка, Полезная нагрузка с временной меткой отправки):

# все RX временные метки 1729223045.596191883, и последний пакет был отправлен в 1729223045.596149
# системные часы сервера и клиента почти синхронизированы, RTT сети < 100us

0 1729223045.596191883 1729223026.594545...
1 1729223045.596191883 1729223027.594635...
2 1729223045.596191883 1729223028.594719...
3 1729223045.596191883 1729223029.594802...
4 1729223045.596191883 1729223030.594888...
5 1729223045.596191883 1729223031.594971...
6 1729223045.596191883 1729223032.595056...
7 1729223045.596191883 1729223033.595140...
8 1729223045.596191883 1729223034.595223...
9 1729223045.596191883 1729223035.595306...
10 1729223045.596191883 1729223036.595391...
11 1729223045.596191883 1729223037.595475...
12 1729223045.596191883 1729223038.595559...
13 1729223045.596191883 1729223039.595647...
14 1729223045.596191883 1729223040.595731...
15 1729223045.596191883 1729223041.595813...
16 1729223045.596191883 1729223042.595899...
17 1729223045.596191883 1729223043.595981...
18 1729223045.596191883 1729223044.596067...
19 1729223045.596191883 1729223045.596149...

Я использую ядро 4.14.252-195.483.amzn2.x86_64.

Я прочитал документацию ядра по временным меткам

В ней описывается SOF_TIMESTAMPING_RX_SOFTWARE как:

Запрашивает RX временные метки, когда данные входят в ядро. Эти временные метки генерируются сразу после того, как драйвер устройства передает пакет в стек получения ядра.

Разве не должен каждый пакет в 20B “передаваться ядру” сразу после его поступления в сетевой адаптер?

Если я изменю код клиента, чтобы получать все данные без ожидания, RX временные метки будут нормальными.

Ответ или решение

Вопрос, который вы поднимаете, имеет большое значение для понимания обработки временных меток в TCP-соединениях, особенно при использовании опции SO_TIMESTAMPING_RX_SOFTWARE. Позвольте мне объяснить, почему вы получаете одно и то же значение временной метки для всех 20 вызовов recvmsg, и как это связано со спецификой реализации сетевого стека в ядре Linux.

Что такое SO_TIMESTAMPING_RX_SOFTWARE?

Опция SO_TIMESTAMPING_RX_SOFTWARE инициирует получение временных меток, когда пакет данных попадает в стек приема ядра после его обработки драйвером сетевого интерфейсного контроллера (NIC). Эта временная метка генерируется сразу после того, как пакет передан из драйвера в сетевой стек ядра. Может возникнуть путаница, если мы ожидаем, что временные метки будут отражать время прихода каждого пакета на сетевой интерфейс, но это не совсем так.

Анализ вашей ситуации

В приведенном вами тесте сервер поочередно отправляет 20 пакетов по 20 байт с паузами в 1 секунду между отправками. Клиент, в свою очередь, ждет 20 секунд и затем вызывает recvmsg, чтобы получить данные. Основная проблема заключается в том, что когда клиент начинает получать данные, все 20B пакетов были уже доставлены в стек ядра, и, следовательно, соответствующие временные метки будут отражать время обработки последнего пакета.

Когда ваш клиент вызывает recvmsg после 20 секунд ожидания, все ранее полученные пакеты уже находятся в очереди, и временная метка, присвоенная пакету, совпадает с временной меткой, когда последний пакет был обработан ядром. Это объясняет, почему вы видите одно и то же значение временной метки для всех вызовов recvmsg.

Что произойдет, если изменить время вызова recvmsg?

Если вы измените код клиента, чтобы он вызывал recvmsg без задержки, то каждый вызов будет обрабатывать пакет, как только он становится доступным в очереди, и временная метка будет отражать реальное время получения каждого пакета. Это связано с тем, что каждый вызов recvmsg будет захватывать временную метку на момент, когда пакет передан из драйвера в сетевой стек.

Рекомендации по устранению проблемы

  1. Не используйте фиксированное ожидание в клиенте: Если вашей целью является получение точных временных меток для каждого пакета, избегайте использования пауз между вызовами recvmsg. Вместо этого используйте не блокирующий ввод-вывод или мультиплексирование для обработки входящих данных.

  2. Тестируйте с разными параметрами: Вы можете проводить тесты с различными значениями времени ожидания и наблюдать за изменениями в результатах временных меток.

  3. Используйте другие опции временных меток: Помимо SO_TIMESTAMPING_RX_SOFTWARE, вы можете использовать и другие опции, такие как SO_TIMESTAMP, которая может предоставлять различные временные метки в зависимости от контекста использования.

Заключение

Опция SO_TIMESTAMPING_RX_SOFTWARE полезна для получения временных меток, но обращение к ней следует делать правильно для достижения точных результатов. Синхронизация взаимодействия между сервером и клиентом, а также использование асинхронных методов получения данных помогут улучшить точность временных меток при работе с TCP.

Если у вас есть дополнительные вопросы или вам нужна помощь с другими аспектами вашей системы, не стесняйтесь обращаться!

Оцените материал
Добавить комментарий

Капча загружается...