【问题标题】:Linux kernel UDP reception timestampLinux内核UDP接收时间戳
【发布时间】:2017-06-07 22:10:12
【问题描述】:

我一直在阅读 linux 内核的network timestamping 文档,有些地方我不清楚。

SO_TIMESTAMPNS提供的时间戳是在哪里生成的?在硬件中还是在内核中?如果是这样,它会在引发新数据包的中断时立即生成?

SO_TIMESTAMPING 还应该允许生成硬件时间戳。所有网卡都支持吗? SO_TIMESTAMPING 与选项 SOF_TIMESTAMPING_RX_HARDWARE and SO_TIMESTAMPNS 的效果如何? 在这种情况下,硬件时间戳是指系统时钟还是 NIC 时钟?在第二种情况下,如何检索 NIC 时钟来计算经过的时间?

【问题讨论】:

  • 硬件(如果支持),否则为内核。通常这样的硬件会使用 PTP 之类的东西来保持卡同步,所以你应该收到一个与时钟相关的时间戳(虽然不确定它是否保证是单调的——也许其他人可以评论..)
  • @Nim,如果支持,哪一个会返回硬件? SO_TIMESTAMPNS?我必须启用硬件时间戳吗?
  • 通常支持此功能的硬件将看到套接字选项(SO_TIMESTAMPNSSO_TIMESTAMP),然后将标记数据包。因此,例如,如果您有一张合适的 solarflare 卡,那么设置选项将导致该卡带有时间戳。否则它将由内核管理。坦率地说,我真的不喜欢你必须阅读控制标题才能真正获得时间戳 - 这是一个可怕的界面..
  • 谢谢。好吧,我想我们必须忍受这个界面:(

标签: c linux sockets linux-kernel


【解决方案1】:

用于软件时间戳的套接字属性是 SO_TIMESTAMPNS。此套接字属性从系统时钟返回时间。它不是在硬件中生成的,而是在软件中处理中断时系统时间的快照。我们可以通过不属于套接字有效负载的辅助数据(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 支持时间戳的所有套接字属性。

要使用特定 NIC 提供的硬件时间戳功能,请使用以下代码:

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

【讨论】:

    猜你喜欢
    • 2014-04-08
    • 1970-01-01
    • 2014-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多