2017-01-23 42 views
5

Czytałem dokumentację jądra Linuxa network timestamping i jest coś, co nie jest dla mnie jasne.Jądro Linuksa Czas odbioru UDP

Gdzie generowany jest znacznik czasu dostarczony przez SO_TIMESTAMPNS? W sprzęcie lub w jądrze? Jeśli tak, to jest gerated, gdy tylko podniesione zostanie przerwanie dla nowego pakietu?

powinien również umożliwiać generowanie sprzętowych znaczników czasu. Czy jest to obsługiwane przez wszystkie karty sieciowe? Jak działa SO_TIMESTAMPING z opcjami SOF_TIMESTAMPING_RX_HARDWARE andSO_TIMESTAMPNS? W takim przypadku jest to sprzętowy znacznik czasu odnoszący się do zegara systemowego lub zegara NIC? W drugim przypadku, jak odzyskać zegar NIC do obliczenia upływu czasu?

+3

Hardware Jeśli obsługiwana, innego jądra. Zwykle taki sprzęt będzie używał czegoś podobnego do PTP, aby zachować synchronizację karty, więc powinieneś otrzymać sygnaturę czasową w stosunku do zegara (nie masz pewności, że jest monotoniczna - może ktoś inny może komentować). – Nim

+0

@Nim, który jeden zwraca sprzęt, jeśli jest obsługiwany? SO_TIMESTAMPNS? Czy muszę włączyć sygnaturę czasową sprzętu? – Maverik

+0

Zwykle sprzęt obsługujący tę funkcję będzie widział opcję gniazda ('SO_TIMESTAMPNS' lub' SO_TIMESTAMP'), a następnie stempluje pakiety. Na przykład, jeśli masz odpowiednią kartę Solarflare, ustawienie opcji spowoduje, że karta będzie miała znacznik czasu. Inaczej będzie zarządzany przez jądro. Szczerze mówiąc, naprawdę nie podoba mi się, że musisz czytać nagłówki kontrolne, aby otrzymać znacznik czasu - to okropny interfejs .. – Nim

Odpowiedz

4

Atrybut gniazda używany do oznaczania czasu oprogramowania to SO_TIMESTAMPNS. Ten atrybut gniazda zwraca czas z zegara systemowego. Nie jest generowany w sprzęcie, lecz jest migawką czasu systemowego, gdy przerwanie jest obsługiwane w oprogramowaniu. Możemy uzyskać dostęp do tego znacznika czasu poprzez danych pomocniczych (cmsg), które nie jest częścią ładunku gniazda, używając:

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); 
    } 
} 

Opcja gniazdo SO_TIMESTAMPING oferuje wiele różnych flagi, niektóre z nich są

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 

Ta opcja gniazda nie jest obsługiwana przez wszystkie karty sieciowe (NIC). Obecnie wiele kart sieciowych obsługuje SO_TIMESTAMPING. Aby się dowiedzieć, czy dany sterownik interfejs obsługuje SO_TIMESTAMPING, przeznaczenie:

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

ten powróci wszystkie atrybuty gniazdo eth.x obsługuje do timestamping.

Aby korzystać z funkcji sprzętu timestamping dostarczone przez konkretnego NIC, należy użyć kodu:

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); 
     } 
}