获取网络包的硬件时间戳

文章介绍了如何在Linux环境中利用ethtool命令检查网卡硬件时间戳能力,并通过配置MAC的硬件发送和接收时间戳以及socket选项来捕获硬件时间戳。通过飞灵科技的TSync开发板进行测试,确保时间同步精度,展示了发送和接收端的时间戳获取过程。
摘要由CSDN通过智能技术生成

转自:如何获取网络包的硬件时间戳_飞行的精灵的博客-CSDN博客

在一些应用中我们需要获取网路报文进出MAC的精准的时间戳。相比较于软件时间戳,硬件时间戳排除了系统软件引起的延时和抖动。如下图所示意:

 

 下面我们使用北京飞灵科技有限公司开发的TSync时钟同步开发板来测试 .
查看网卡捕获时间戳的能力

进入Linux命令行后,我们可以使用ethtool -T eth0 来查看对应的MAC捕获时间戳的能力。

    root@TSync:~# ethtool -T eth0
    Time stamping parameters for eth0:
    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: 0
    Hardware Transmit Timestamp Modes:
            off                   (HWTSTAMP_TX_OFF)
            on                    (HWTSTAMP_TX_ON)
    Hardware Receive Filter Modes:
            none                  (HWTSTAMP_FILTER_NONE)
            all                   (HWTSTAMP_FILTER_ALL)
     
     

在Capabilities 字段里, 我们可以知道这个MAC 支持捕获那些时间戳的类型。

    SOF_TIMESTAMPING_TX_HARDWARE 支持捕获硬件发送时间戳。
    SOF_TIMESTAMPING_RX_HARDWARE 支持捕获硬件接收时间戳。
    SOF_TIMESTAMPING_TX_SOFTWARE 支持捕获软件发送时间戳。
    SOF_TIMESTAMPING_RX_SOFTWARE 支持捕获软件接收时间戳。

捕获发送时间戳时,可配置为两种模式:

    HWTSTAMP_TX_OFF 表示网卡发送的报文都不捕获硬件时间戳。
    HWTSTAMP_TX_ON 表示网卡对所有接收到的报文都捕获硬件时间戳。

捕获接收报文的时间戳时,有几种过滤器,可以选择捕获特定数据流的时间戳:

    HWTSTAMP_FILTER_NONE: 所有收到的数据流都不捕获时间戳。
    HWTSTAMP_FILTER_ALL:所有收到的数据流都捕获时间戳。

除了以上两个过滤器外,一些网卡可能还有以下几种过滤器用于捕获PTP协议的报文时间戳。

    ptpv1-l4-sync            (HWTSTAMP_FILTER_PTP_V1_L4_SYNC)
    ptpv1-l4-delay-req    (HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ)
    ptpv2-l4-sync            (HWTSTAMP_FILTER_PTP_V2_L4_SYNC)
    ptpv2-l4-delay-req    (HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ)
    ptpv2-l2-sync            (HWTSTAMP_FILTER_PTP_V2_L2_SYNC)
    ptpv2-l2-delay-req    (HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ)
    ptpv2-event              (HWTSTAMP_FILTER_PTP_V2_EVENT)
    ptpv2-sync               (HWTSTAMP_FILTER_PTP_V2_SYNC)
    ptpv2-delay-req       (HWTSTAMP_FILTER_PTP_V2_DELAY_REQ)

配置捕获硬件时间戳功能

要捕获硬件时间戳,需要配置MAC上的PHC硬件和配置socket 生成时间戳的类型。

使能PHC时间戳功能

通过SIOCSHWTSTAMP ioctl命令配置硬件发送时间戳捕获模式和 硬件接收时间戳的过滤器。代码如下:

    struct ifreq hwtstamp;
    struct hwtstamp_config hwconfig;
    memset(&hwtstamp, 0, sizeof(hwtstamp));
    memset(&hwconfig, 0, sizeof(hwconfig));
    hwtstamp.ifr_name = "eth1";
    hwtstamp.ifr_data = (void*)&hwconfig;
    // 设置网卡捕获所有发送报文的硬件时间戳。
    hwconfig.tx_type = HWTSTAMP_TX_ON;
    // 设置网卡捕获所有接收到的报文的时间戳。
    hwconfig.rx_filter = HWTSTAMP_FILTER_ALL;
    ioctl(sock, SIOCSHWTSTAMP, &hwtstamp)

配置socket 捕获时间戳的类型

    int so_timestamping_flags = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE;
    setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING,&so_timestamping_flags, sizeof(so_timestamping_flags)) < 0)

获取发送或接收报文的时间戳

在发送完或接收完报文后,时间戳被记录到一个 cmsg_level为SOL_SOCKET, cmsg_type 为SCM_TIMESTAMPING, data为 struct scm_timestamping 的一个control message中。这个cmsg可以通过recvmsg() 接口读取。

对于发送报文的时间戳,是放在socket的error 队列中,使用下面函数取到msg中。

ssize_t recv_len = recvmsg(sock, &msg, MSG_ERRQUEUE);

对于接收到的报文的时间戳,使用下面函数取到msg中。

ssize_t recv_len = recvmsg(sock, &msg, 0);

时间戳信息以struct scm_timestamping结构保存在cmsg消息的data段中。结构里包含三个时间戳:

    struct scm_timestamping {
        struct timespec ts[3];
    };

    ts[0]里存放的时software 时间戳,如果使能的话有效,否则为0。
    ts[1]里存放的是一个被转化为系统时间的硬件时间戳,这个硬件时间类似一个影子时钟,用来系统时间和MAC上phc 时钟同步。
    ts[2]里存放的便是我们想要获取的硬件时间戳。

使用下面代码,即可获提取到我们想要的时间戳。

    struct cmsghdr *cmsg = NULL;
    struct scm_timestamping hw_ts;
    struct timespec ts;
    for(cmsg=CMSG_FIRSTHDR(&msg);cmsg!=NULL;cmsg=CMSG_NXTHDR(&msg, cmsg)) {
        if(cmsg->cmsg_level==SOL_SOCKET && cmsg->cmsg_type==SO_TIMESTAMPING) {
            hw_ts=*((struct scm_timestamping *)CMSG_DATA(cmsg));
            fprintf(stdout,"HW: %lu s, %lu ns\n",hw_ts.ts[2].tv_sec,hw_ts.ts[2].tv_nsec);
            fprintf(stdout,"ts: %lu s, %lu ns\n",hw_ts.ts[1].tv_sec,hw_ts.ts[1].tv_nsec);
            fprintf(stdout,"SW: %lu s, %lu ns\n",hw_ts.ts[0].tv_sec,hw_ts.ts[0].tv_nsec);
            memcpy(&ts, &scm_ts.ts[2], sizeof(struct timespec)); // 拷贝捕获的硬件时钟到timespec 结构中。
        }
    }

代码测试

为了验证获取的时间戳的正确性,我们使用两块飞灵科技的TSync时钟同步开发板作为报文的发送端和接收端,并分别在两个板子上捕获发送和接收的硬件时间戳。

 为了使发送端和接收端的时间一致,我们首先让他们分别和GNSS 卫星时间同步。板子上电后,点击下图按钮,打开GNSS同步。

 将两个板子分别通过PTP端口连接到路由器。 在串口控制台运行dhcp获取IP地址。分别拷贝stamp_send.c 和 stamp_recv.c 文件到两块板子上,并分别如下编译:

    gcc stamp_recv.c -o stamp_recv
    gcc stamp_send.c -o stamp_send

在接收端运行 ./stamp_recv eth0

    root@TSync:~/stamp_test# ./stamp_recv eth0
    source IP: 192.168.1.78
    Test started.
    Recv pakage: hello world 0
    HW: 1639236711 s, 631040873 ns
    ts[1]: 0 s, 0 ns
    SW: 0 s, 0 ns
    Hardwave recv timestamp: 1639236711 s, 631040873 ns
     
    Recv pakage: hello world 1
    HW: 1639236712 s, 632989572 ns
    ts[1]: 0 s, 0 ns
    SW: 0 s, 0 ns
    Hardwave recv timestamp: 1639236712 s, 632989572 ns
     
    Recv pakage: hello world 2
    HW: 1639236713 s, 635084458 ns
    ts[1]: 0 s, 0 ns
    SW: 0 s, 0 ns
    Hardwave recv timestamp: 1639236713 s, 635084458 ns
     
    Recv pakage: hello world 3
    HW: 1639236714 s, 637115333 ns
    ts[1]: 0 s, 0 ns
    SW: 0 s, 0 ns
    Hardwave recv timestamp: 1639236714 s, 637115333 ns

在发送端运行 “./stamp_send eth0 192.168.1.78”,192.168.1.78 为接收端的IP 地址。

    root@TSync:~/stamp_test# ./stamp_send eth0 192.168.1.78
    source IP: 192.168.1.79
    Test started.
    Sent packet number (0/10) : hello world 0
    HW: 1639236711 s, 631013470 ns
    ts[1]: 0 s, 0 ns
    SW: 0 s, 0 ns
    Hardwave send timestamp: 1639236711 s, 631013470 ns
     
    Sent packet number (1/10) : hello world 1
    HW: 1639236712 s, 632962036 ns
    ts[1]: 0 s, 0 ns
    SW: 0 s, 0 ns
    Hardwave send timestamp: 1639236712 s, 632962036 ns
     
    Sent packet number (2/10) : hello world 2
    HW: 1639236713 s, 635057007 ns
    ts[1]: 0 s, 0 ns
    SW: 0 s, 0 ns
    Hardwave send timestamp: 1639236713 s, 635057007 ns
     
    Sent packet number (3/10) : hello world 3
    HW: 1639236714 s, 637087896 ns
    ts[1]: 0 s, 0 ns
    SW: 0 s, 0 ns
    Hardwave send timestamp: 1639236714 s, 637087896 ns

从发送端和接收端的log可以看到, 报文的接收时间戳和发送时间戳之差,就是路由器的链路延时。

测试源码文件“硬件时间戳使用示例代码.zip”可以从飞灵科技的Wiki上下载。资料下载 - 飞灵科技-文档 :
 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值