2017-01-23 2 views
5

Я читал документацию о Linux-ящике network timestamping, и есть что-то, что мне непонятно.Ядро Linux UDP-прием timestamp

Сгенерирована метка времени, предоставленная SO_TIMESTAMPNS? В аппаратных средствах или в ядре? Если это так, то как только прерывается новый пакет?

SO_TIMESTAMPING также должен обеспечивать создание временных меток оборудования. Поддерживается ли это всеми сетевыми адаптерами? Как SO_TIMESTAMPING с опциями SOF_TIMESTAMPING_RX_HARDWARE andSO_TIMESTAMPNS? В этом случае это временная метка оборудования, относящаяся к системным часам или часам сетевого адаптера? Во втором случае, как получить часы NIC для вычисления прошедшего времени?

+3

оборудование, если поддерживается, другое ядро. Обычно такое аппаратное обеспечение будет использовать что-то вроде PTP, чтобы синхронизировать карту, поэтому вы должны получать временную метку по отношению к часам (не уверен, что она гарантирована как монотонная, хотя, может быть, кто-то может прокомментировать ..) – Nim

+0

@Nim, который один возвращает оборудование, если поддерживается? SO_TIMESTAMPNS? Должен ли я включать аппаратную метку времени? – Maverik

+0

Обычно аппаратные средства, поддерживающие эту функциональность, будут видеть опцию сокета ('SO_TIMESTAMPNS' или' SO_TIMESTAMP'), а затем будут штамповать пакеты. Так, например, если у вас есть соответствующая карта солнечной вспышки, то настройка параметров приведет к тому, что карта будет отмечена меткой времени. Иначе это будет управлять ядром. Честно говоря, мне действительно не нравится, что вы должны прочитать заголовки элементов управления, чтобы на самом деле получить временную метку, хотя это ужасный интерфейс. – Nim

ответ

4

Атрибут сокета, используемый для временной привязки программного обеспечения, SO_TIMESTAMPNS. Этот атрибут socket возвращает время от системных часов. Он не генерируется в аппаратном обеспечении, скорее это моментальный снимок системного времени, когда прерывание обрабатывается в программном обеспечении. Мы можем получить доступ к этой метке времени через вспомогательные данные (CMSG), который не является частью полезной нагрузки сокета, используя:

int level, type; 
struct cmsghdr *cm; 
struct timespec *ts = NULL; 
for (cm = CMSG_FIRSTHDR(&msg); cm != NULL; cm = CMSG_NXTHDR(&msg, cm)) 
{ 
    level = cm->cmsg_level; 
    type = cm->cmsg_type; 
    if (SOL_SOCKET == level && SO_TIMESTAMPNS == type) { 
     ts = (struct timespec *) CMSG_DATA(cm); 
     printf("SW TIMESTAMP %ld.%09ld\n", (long)ts[0].tv_sec, (long)ts[0].tv_nsec); 
    } 
} 

Опция SO_TIMESTAMPING гнездо предлагает множество различных флагов, некоторые из них,

SOF_TIMESTAMPING_TX_HARDWARE // Transmit timestamp generated in hardware by NIC clock 
SOF_TIMESTAMPING_RX_HARDWARE // Receive timestamp generated in hardware by NIC clock 
SOF_TIMESTAMPING_TX_SOFTWARE // Transmit timestamp generated in kernel driver by NIC clock 
SOF_TIMESTAMPING_RX_SOFTWARE // Receive timestamp generated in kernel driver by NIC clock 

Эта опция сокета не поддерживается всеми сетевыми интерфейсами (NIC). В настоящее время многие сетевые сетевые адаптеры поддерживают SO_TIMESTAMPING. Для того, чтобы найти, если конкретный драйвер поддерживает интерфейс SO_TIMESTAMPING, использование:

ethtool -T ethX // where X corresponds to your particular interface 

Это будет возвращать все атрибуты сокета ethX поддерживает для временных меток.

Чтобы использовать аппаратные функции меток времени, предоставляемый определенным сетевым адаптером, используйте код:

int flags; 
flags = SOF_TIMESTAMPING_TX_HARDWARE 
      | SOF_TIMESTAMPING_RX_HARDWARE 
      | SOF_TIMESTAMPING_TX_SOFTWARE 
      | SOF_TIMESTAMPING_RX_SOFTWARE 
      | SOF_TIMESTAMPING_RAW_HARDWARE; 
    if (setsockopt(sd, SOL_SOCKET, SO_TIMESTAMPING, &flags, sizeof(flags)) < 0) 
     printf("ERROR: setsockopt SO_TIMESTAMPING\n"); 

int level, type; 
struct cmsghdr *cm; 
struct timespec *ts = NULL; 
for (cm = CMSG_FIRSTHDR(&msg); cm != NULL; cm = CMSG_NXTHDR(&msg, cm)) 
{ 
    if (SOL_SOCKET == level && SO_TIMESTAMPING == type) { 
     ts = (struct timespec *) CMSG_DATA(cm); 
     printf("HW TIMESTAMP %ld.%09ld\n", (long)ts[2].tv_sec, (long)ts[2].tv_nsec); 
     } 
} 
Смежные вопросы