11

I've been reading the network timestamping documentation of linux kernel and there is something that it's not clear to me.

Where is the timestamp provided by SO_TIMESTAMPNS generated? In hardware or in the kernel? If so it is gerated as soon as an interrupt for a new packet is raised?

SO_TIMESTAMPING should also allow the generation of hardware timestamps. Is this supported by all the NICs? How does SO_TIMESTAMPING with options SOF_TIMESTAMPING_RX_HARDWARE and SO_TIMESTAMPNS? In that case is the hardware timestamp referring to the system clock or to the NIC clock? In the second case how to retrieve the NIC clock to compute elapsed time?

Maverik
  • 2,358
  • 6
  • 34
  • 44
  • 4
    Hardware if supported, else kernel. Normally such hardware will use something like PTP to keep the card synchronized, so you should receive a timestamp in relation to the clock (not sure that it is guaranteed to be monotonic though - maybe someone else can comment..) – Nim Jan 23 '17 at 12:03
  • @Nim, which one returns hardware if supported? SO_TIMESTAMPNS? Do I have to enable the hardware timestamping? – Maverik Jan 23 '17 at 21:06
  • 2
    Normally hardware that supports this functionality will see the socket option (`SO_TIMESTAMPNS` or `SO_TIMESTAMP`) and then will stamp the packets. So, for example, if you have an appropriate solarflare card, then setting the options will cause the card to timestamp. Else it will be managed by the kernel. Frankly speaking, I really do not like that you have to read the control headers to actually get the timestamp though - it's a horrible interface.. – Nim Jan 24 '17 at 09:07
  • Thanks. Well, I guess we have to live with this interface :( – Maverik Jan 24 '17 at 13:45

1 Answers1

12

The socket attribute used for software timestamping is, SO_TIMESTAMPNS. This socket attribute returns the time from the system clock. It is not generated in the hardware, rather it is the snapshot of the system time when the interrupt is handled in the software. We can access this timestamp through the ancillary data (CMSG) that is not part of the socket payload, using:

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

The SO_TIMESTAMPING socket option offers many different flags, some of them are,

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

This socket option is not supported by all Network Interface Cards (NICs). Currently many ethernet NICs support SO_TIMESTAMPING. In order to find if a particular interface driver supports SO_TIMESTAMPING, use:

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

This will return all the socket attributes ethX supports for timestamping.

To use hardware timestamping feature provided by a particular NIC, use the code:

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);
      }
}
Fatima
  • 121
  • 5