获取网络包的硬件时间戳

news2024/7/6 17:57:56

转自:如何获取网络包的硬件时间戳_飞行的精灵的博客-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上下载。资料下载 - 飞灵科技-文档 :
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/763461.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在命令行执行命令后出现 Permission denied 的问题解决

解决在项目目录安装一个有 “bin” 配置的依赖包后&#xff0c;执行 “bin” 命令&#xff0c;出现了 Permission denied 的问题。 问题 比如有这样一个包 json2playwright &#xff0c;它的 package.json 中 “bin” 是&#xff1a; "bin": {"pince": &q…

如何让Vue项目本地运行的时候,同时支持http://localhost和http://192.168.X.X访问?

方法1&#xff1a;在package.json的"scripts":→ "dev":末尾追加 --host 0.0.0.0 方法2&#xff1a;将config\index.js的"dev":→ "host":修改为0.0.0.0

攻不下dfs不参加比赛(十八)

标题 为什么练dfs题目为什么练dfs 相信学过数据结构的朋友都知道dfs(深度优先搜索)是里面相当重要的一种搜索算法,可能直接说大家感受不到有条件的大家可以去看看一些算法比赛。这些比赛中每一届或多或少都会牵扯到dfs,可能提到dfs大家都知道但是我们为了避免眼高手低有的东…

CANoe-Symbol Mapping介绍

在CANoe的Environment菜单下有一个模块叫:Symbol Mapping。 打开后的界面为: 它的作用是: 在mapping对话框内,你可以映射系统变量、环境变量、信号、通信对象的值或分布式对象的成员以及系统变量的命名空间。当测量过程中源变量的值发生变化时,目标变量的值会自动设置。 你…

JDK安装

JDK安装 1、Windows环境下JDK的安装 1.1 下载 到 Java 的官网下载 JDK 安装包&#xff0c;下载地址&#xff1a; http://www.oracle.com/technetwork/java/javase/downloads/index.html 选择一个适合自己的 JDK 版本下载即可。 1.2 安装 通过双击软件并且点击下一步进行…

Fiddler抓包使用简介

目录 Fiddler简介 请求抓包 抓取PC端HTTPS请求 抓取移动端请求 请求查看 发送请求 Mock接口 断点调试 弱网模拟 请求重放 修改HOSTS 总结&#xff1a; Fiddler简介 Fiddler是一款免费的Windows平台的抓包工具&#xff0c;功能强大&#xff0c;使用简单。Fiddler抓…

【SCI征稿】老牌期刊2023年上涨质量高!中科院2/1区(TOP),国人发文友好!

您有一个评职称弯道超车的机会&#xff1f; 因为本期小编要推荐一本中科院2/1区&#xff08;TOP&#xff09;期刊&#xff0c;期刊质量不论是评职晋升求职毕业都是首选的好刊&#xff01;究竟怎么回事&#xff1f;且看下文&#xff1a; 期刊简介&#xff1a; 影响因子&#…

传感器信息系统中的节能收集(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

消息队列——spring和springboot整合rabbitmq

目录 spring整合rabbitmq——生产者 rabbitmq配置文件信息 倒入生产者工程的相关代码 简单工作模式 spring整合rabbitmq——消费者 spring整合rabbitmq——配置详解 SpringBoot整合RabbitMQ——生产者 SpringBoot整合RabbitMQ——消费者 spring整合rabbitmq——生产者 使…

分布式应用之存储(Ceph)

分布式应用之存储&#xff08;Ceph) 一、数据存储类型 存储类型说明典型代表块存储一对一&#xff0c;只能被一个主机挂载使用数据以块为单位进行存储硬盘文件存储一对多&#xff0c;能同时被多个主机挂载/传输使用&#xff0c;数据以文件的形式存储&#xff08;元数据和实际…

Appium+python自动化(十)- 元素定位秘籍助你打通任督二脉 - 上卷(超详解)

1、 常用定位方法讲解 对象定位是自动化测试中很关键的一步&#xff0c;也可以说是最关键的一步&#xff0c;毕竟你对象都没定位那么你想操作也不行。所以本章节的知识宏哥希望小伙伴们多动手去操作和实战&#xff0c;不要仅仅只是书本上的知识&#xff0c;毕竟这个我只能够举例…

AtcoderABC301场

A - Order Something Else A - Order Something Else 题目大意 计算 Takahashi 最少需要支付多少钱才能获得 AtCoder Drink。AtCoder Drink 可以按照原价 P 日元购买&#xff0c;也可以使用折扣券以 Q 日元的价格购买&#xff0c;但必须再额外购买 N 道菜品中的一道才能使用折…

Navicat代码片段存储位置

1、在Navicat的主界面中&#xff0c;选择“工具”——》“选项”——》文件位置&#xff0c;如下图 配置文件就是存放自动保存、代码片段等文件的位置&#xff0c;其中snippets&#xff08;片段&#xff09;就是自定义片段的存储位置了

【Android】在某个model中找不到自己的R资源的原因

背景 在某个新建的model为lib包的时候&#xff0c;我想在这个model内的activity引用R.string 等等资源&#xff0c;但是Android studio找不到。 解决 原来我之前误删了这个manifest中的 补齐包名即可。

Triton_server部署学习笔记

下载镜像 docker pill http://nvcr.io/nvidia/tritonserver:22.07-py3 docker run --gpus all -itd -p8000:8000 -p8001:8001 -p8002:8002 -v /home/ai-developer/server/docs/examples/model_repository/:/models nvcr.io/nvidia/tritonserver:22.07-py3 docker exec -it a5…

使用shell监控应用运行状态通过企业微信接收监控通知

目的&#xff1a;编写shell脚本来监控应用服务运行状态&#xff0c;若是应用异常则自动重启应用通过企业微信接收监控告警通知 知识要点&#xff1a; 使用shell脚本监控应用服务使用shell脚本自动恢复异常服务通过企业微信通知接收监控结果shell脚本使用数组知识&#xff0c;…

[黑苹果EFI]Lenovo ThinkPad T490电脑 Hackintosh 黑苹果引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件型号驱动情况 主板Lenovo ThinkPad T490 处理器Intel Intel Core i5 8265U (Quad Core)已驱动 内存16 GB:8 GB Samsung DDR 4 2666 Mhz *2已驱动 硬盘PC SN520 NVM…

maven项目使用java命令行运行类的main方式示例

因为需要测试一个东西,本地测试无问题,测试环境一直有问题,就想在测试环境测试下 直接写了个测试类,main方法直接运行测试逻辑 测试类写好,发现自己不会使用命令行运行 运行测试类一直报"错误: 找不到或无法加载主类" 折腾好久,终于找到两个帖子 记录下来,避免自己下…

Docker容器常用命令大全:熟练掌握使容器优化更加高效

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

mysql查询当天/昨天/近7天/近30天/本月/上个月/本季度/上季度/本年/上一年 数据

查询当天数据 select * from tab where FROM_UNIXTIME(fabutime, %Y%m%d) 20230717; mysql TO_DAYS(date) 函数 TO_DAYS(date) 给定一个日期date, 返回一个天数 (从年份0开始的天数 )。 mysql> SELECT TO_DAYS(950501); -> 728779 mysql查询今天、昨天、7天、近30天…