【问题标题】:Linux timestamping for TCP socketsTCP 套接字的 Linux 时间戳
【发布时间】:2015-02-26 12:36:26
【问题描述】:

我正在一个项目中工作,以从文档Linux timestamping 中提到的 TCP 套接字的 NIC 获取接收和传输时间戳。但是所有文档和测试编码都是针对 UDP 套接字完成的。但是我得到了 NIC 的传输时间戳,而没有得到接收 TCP 数据包的时间戳。

我的界面支持以下时间戳

    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)

我在bind() 之后使用ioctl(sockfd, SIOCSHWTSTAMP, &net_device); 为网卡启用时间戳

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;

然后通过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");
}

在listen() 和accept() 之后,我执行select(),并检查fd 是否为rfds,然后使用以下选项调用recvmsg()

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

但我总是收到以下消息,

received short ancillary data (0/256)

我没有从recvmsg()获取辅助数据,我想知道linux是否支持TCP接收网卡的硬件时间戳。

【问题讨论】:

    标签: linux sockets tcp linux-kernel timestamping


    【解决方案1】:

    我能够使用最近的内核版本 (4.18) 将 SO_TIMESTAMPING 与 TCP 套接字一起使用。这适用于 TX 和 RX 时间戳。我仍在努力,但如果您愿意,我可以尝试编写一个最小的概念证明。

    【讨论】:

    • 如果您读取来自多个段的数据,您会得到哪个时间戳?或者有什么方法可以暴露分段视图?
    【解决方案2】:

    Linux 时间戳不支持 TCP 的接收硬件或软件时间戳。仅在“数据包”方面提到的 linux 时间戳文档。这里指的是UDP,用于实现网卡中PTP硬件时钟的同步,看PTP daemon和linux ptp的代码了解更多。 Linux 3.18 仅支持传输中的时间戳。所以基本上你无法在接收器中实现 TCP 的 linux 时间戳。

    【讨论】:

    • 无论如何要获取 TCP 的时间戳?
    • 值得补充的是,一些 NIC 和 Linux 驱动程序支持 UDP 数据包的一般时间戳,而不仅仅适用于 PTP。
    • 我知道这是旧的,但我认为libpcap 支持 TCP 硬件时间戳。
    • 截至今天,2017 年 4 月 18 日,Solarflare(网卡制造商)的支持人员报告说 Linux 内核不支持 TCP 硬件时间戳。您可以使用 SFN8522-PLUS 之类的卡从卸载的网卡驱动程序中获得它,但该卡也没有完全出炉:-(。
    • 我的问题是即使支持它是什么意思? TCP是一个流,一般不会暴露流的分段,所以你得到的时间戳对应...?
    猜你喜欢
    • 2017-10-27
    • 1970-01-01
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 2023-03-10
    • 2013-05-21
    • 2021-11-12
    相关资源
    最近更新 更多