Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linux timestamping for TCP sockets

I am working in a project to get the receive and transmit time stamping from the NIC for TCP socket as mentioned in the document Linux timestamping. But all the documentation and test coding are done for UDP sockets. But I am getting the Transmit timestamping for the NIC and not getting the time stamping for the receive TCP packets.

My Interface support the following time stamps

    Time stamping parameters for enp4s0:
Capabilities:
    hardware-transmit     (SOF_TIMESTAMPING_TX_HARDWARE)
    software-transmit     (SOF_TIMESTAMPING_TX_SOFTWARE)
    hardware-receive      (SOF_TIMESTAMPING_RX_HARDWARE)
    software-receive      (SOF_TIMESTAMPING_RX_SOFTWARE)
    software-system-clock (SOF_TIMESTAMPING_SOFTWARE)
    hardware-raw-clock    (SOF_TIMESTAMPING_RAW_HARDWARE)
PTP Hardware Clock: 3
Hardware Transmit Timestamp Modes:
    off                   (HWTSTAMP_TX_OFF)
    on                    (HWTSTAMP_TX_ON)
Hardware Receive Filter Modes:
    none                  (HWTSTAMP_FILTER_NONE)
    all                   (HWTSTAMP_FILTER_ALL)

I enable the timestamping for NIC after bind() using ioctl(sockfd, SIOCSHWTSTAMP, &net_device); with

memset(&net_device, 0, sizeof(net_device));
strncpy(net_device.ifr_name, interface_name, sizeof(net_device.ifr_name));
net_device.ifr_data = (void *)&tstconfig;
memset(&tstconfig, 0, sizeof(tstconfig));

tstconfig.tx_type = HWTSTAMP_TX_OFF;
tstconfig.rx_filter = HWTSTAMP_FILTER_ALL;

then enable the time stamping in the NIC through setsockopt()

int opt= 0;
opt |= SOF_TIMESTAMPING_RX_HARDWARE;
opt |= SOF_TIMESTAMPING_RAW_HARDWARE;
if (setsockopt(sockfd, SOL_SOCKET, SO_TIMESTAMPING,
           (char *)&opt, sizeof(opt))) {
    error(1, 0, "setsockopt timestamping");
    bail("setsockopt SO_TIMESTAMPING");
}

After the listen() and accept(), I do select(), and check whether fd is rfds then call the recvmsg() with following options

int rc;
struct iovec vec[1];
struct msghdr msg;
char data[8192];
struct cmsghdr *cmsg;

union {
    struct cmsghdr cm;
    char control[256];
} cmsg_un;

vec[0].iov_base = data;
vec[0].iov_len = sizeof(data);

memset(&msg, 0, sizeof(msg));
memset(&from_addr, 0, sizeof(from_addr));
memset(&cmsg_un, 0, sizeof(cmsg_un));

msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = vec;
msg.msg_iovlen = 1;
msg.msg_control = cmsg_un.control;
msg.msg_controllen = sizeof(cmsg_un.control);   
rc = recvmsg(flow->fd, &msg, 0);

printf("tried reading %d bytes, got %d", bytes, rc);
if (msg.msg_flags & MSG_TRUNC) {
    printf("received truncated message\n");
    return 0;
}

if (msg.msg_flags & MSG_CTRUNC) {
    printf("received truncated ancillary data\n");
    return 0;
}

if (msg.msg_controllen <= 0) {
    printf("`received short ancillary data (%ld/%ld)`\n",
            (long)msg.msg_controllen, (long)sizeof(cmsg_un.control));
    return 0;
}

But I am always getting the following message,

received short ancillary data (0/256)

I am not getting the ancillary data from the recvmsg(), I like to know whether linux support TCP receive hardware time stamping for the NIC.

like image 630
RK Amudhan Avatar asked Feb 26 '15 12:02

RK Amudhan


2 Answers

I was able to use SO_TIMESTAMPING with a TCP socket using a recent kernel version (4.18). This works for both TX and RX timestamps. I am still working on this but I can try to write a minimal proof of concept if you want.

like image 91
Malt3 Avatar answered Oct 19 '22 17:10

Malt3


Linux timestamping doesn't support the receive hardware or software timestamping for TCP. Documentation of linux timestamping mentioned only regarding the in terms of "packets". This refers UDP, which is used for the implementation of synchronization of PTP hardware clock in NIC, look the code of PTP daemon and linux ptp for more understanding. Linux 3.18 support only the timestamping in transmit. So basically you can't achieve the linux timestamping for TCP in receiver.

like image 30
Philips Avatar answered Oct 19 '22 19:10

Philips