PTP(Precision Time Protocol)高精度时间同步协议+linuxptp代码学习

本文介绍了PTP(Precision Time Protocol)在项目中的应用,重点关注基于linuxptp的实现。讨论了PTP报文的种类,如Signaling、Announce、Sync、Follow_Up等,以及它们的功能和在主从同步模式下的工作原理。同时,详细分析了request unicast transmission TLV和grant unicast transmission TLV的使用,强调了它们在主从通信中的作用。文章还涵盖了PTP报文的生成、处理流程及源码解析。
AI助手已提取文章相关产品:

最近项目中用到了PTP做时间同步,基于linuxptp做的改进和开发。刚入门对很多东西不是很清楚,用wireshark在测试设备的slave这边抓了个包,对照源码和官方文档学习一波,请各位大佬多多批评指正。
目前设备上采用的是主从同步,oneStep模式,所以重点先看看这部分的实现逻辑。

PTP报文

设备在PTP这块采用的传输层协议是UDP。PTP协议使用的端口号是319和320,其中319对应事件消息(EVENT),需要网口记录收发时间戳,320对应普通消息(GENERAL),无需记录收发时间戳。

Signaling报文

Signaling报文负责传输搭载的TLV消息。一个Signaling报文可以携带多个TLV消息。可携带的TLV类型messageType对应官方文档14节。
Signaling报文占用空间大小与携带的TLV相关,为头部(34字节)+targetPortIdentity(10字节)+每个TLV所占空间。TLV消息所占空间与其携带数据有关,携带的数据大小为lengthField字段的值,总大小为TLV类型(2字节)+TLV数据长度(2字节)+数据。
Signaling报文格式
对应代码
port_signaling.c中的port_signaling_construct,生成初始不带TLV的Signaling报文。
port_signaling.c中的process_signaling,处理收到的Signaling报文:

  1. 判断当前端口状态,状态正常即可(除INITIALIZING、FAULTY和DISABLED外);
  2. 遍历消息的TLV链表,根据TLV类型以及TLV带的messageType执行对应的操作。
    如果收到的TLV是Request Unicast Transmission,需要解析其中的messageType。如果messageType是Announce或Sync,需要进一步添加或更新源端client。最后调用unicast_service_reply返回对应Grant Unicast Transmission报文。
    如果收到的TLV是Grant Unicast Transmission,对应函数unicast_client_grant。需要判断源端是否是自己发送Request的master,然后判断对方的grant对自己的messageType类型,最后根据Unicast状态执行对应操作。
request unicast transmission TLV

功能
Slave端口→Master端口,Slave端口请求Master端口发送对应TLV中指定的报文(包括Announce、Sync、Delay_Resp或Pdelay_Resp),并约定发送间隔。这部分主从的约定功能是可选的,对应官方文档16.1节。
logInterMessagePeriod字段用于约定后续消息发送间隔,用以2为底的对数表示。
例如,开始时Slave端口发送了一个Signaling报文,如下所示。
requestUnicast TLV
可以看到,该Signaling报文搭载了request unicast transmission的TLV、请求的报文类型是Announce报文,logInterMessagePeriod字段为1。说明Master端口在grant该请求后,需要每2秒(212^121)发送一条Announce报文给Slave端口。后续抓包结果中的Announce报文如下。
Announce抓包结果
抓包结果显示master端基本以2秒间隔定期发送Announce报文。最后一个字段durationField指的是如果在这段时间内都没有收到来自master端的Announce报文,就认为主时钟失效。
这个TLV占用空间大小为10字节,为TLV类型(2字节)+TLV数据长度(2字节)+消息类型(1字节)+消息发送间隔(1字节)+请求返回时间(4字节)。
requestUnicast TLV格式
所以也可以看到搭载了这个TLV的Signaling报文的messageLength是54。
对应代码
unicast_client.c中的attach_request,将request unicast transmission的TLV添加到Signaling报文后面。
unicast_client.c中的unicast_client_announce,生成Signaling报文,并调用attach_request添加request信息,最后发送。

grant unicast transmission TLV

功能
Master端口→Slave端口,应答Slave端口的request unicast transmission请求。对应官方文档16.1节。
grantUnicast TLV
占用空间大小为12字节,除了上述request TLV的数据均有,还有预留空间(1字节)+是否更新grant(1字节)。
grantUnicast TLV格式
对应代码
unicast_service.c中的attach_grant,将grant unicast transmission的TLV添加到Signaling报文后面。
unicast_service.c中的unicast_service_reply,生成Signaling报文,并调用attach_grant添加grant信息,最后发送。

Announce报文

功能
Master端口向Slave端口定期发送,发送间隔取决于对应Signaling报文的约定。若一段时间内Slave端口未收到Master端口发来的Announce报文,则认为Master端口失效。
Announce报文
占用空间大小为64字节。
Announce报文结构
对应代码
port.c中的port_tx_announce,生成Announce报文并发送。
unicast_service.c中的unicast_service_clients,检查client队列中保持连接的Slave端口(已经grant了对应了Announce请求且未过期的),并调用port_tx_announce
port.c中的process_announce,处理收到的Announce报文:

  1. 判断消息地址是否是master的地址;
  2. 判断当前端口状态,根据状态不同选择执行是添加外部master时钟/更新当前master时钟。

Sync报文

功能
Master端口向Slave端口定期发送,发送间隔取决于对应Signaling报文的约定。报文中带当前Master端口的时间戳(config中设定了twoStepFlag=0,即单步模式,时间戳随Sync报文发送;两步模式中,Sync报文的originTimestamp为0或估计的出端时间戳,不重要)。
占用空间大小为44字节。
Sync报文结构
对应代码
port.c中的port_tx_sync,生成Sync报文并发送。
unicast_service.c中的unicast_service_clients,检查client队列中保持连接的Slave端口(已经grant了对应了Sync请求且未过期的),并调用port_tx_sync
prot.c中的process_sync,处理收到的Sync报文:

  1. 判断当前端口状态,只有uncalibrated和slave两种状态需要处理Sync报文;
  2. 判断端口的父时钟端口ID和消息源端口ID是否一致,只有一致才需要处理;
  3. 如果消息不是单播,且消息中的logMessageInterval字段与端口的log_sync_interval不同,说明是父时钟端口更新Sync消息间隔,则对应更新端口的Sync消息间隔;
  4. 在消息头的correction中修正不对称性(若不对称性已知,即主-从和从-主的时延不同);
  5. 若当前是单步模式,调用port_synchronize,计算修正后的t1并记录t2;
    若当前是两步模式,判断本次Sync消息和在收到本次Sync消息之前端口收到的上一个Follow_Up消息是否是同一个SequenceID,并更新端口的syfu状态。若ID匹配,调用port_synchronize计算修正后的t1并记录t2。(这是因为虽然Master端会先发Sync后发Follow_Up报文,但由于网络原因可能同一次的Follow_Up报文会比Sync报文先到达Slave端,因此需要记录并判断SequenceID

Follow_Up报文

功能:Master端口→Slave端口,在两步模式(twoStepFlag=1)中,Master端口在发送完Sync报文后发送相应的Follow_Up报文,携带有对应Sync报文发送时的精确时间戳。官方文档建议Follow_Up报文应在Sync报文发送后尽快发送,源码中也是紧随Sync报文发出的。
Follow_Up报文占用空间大小为44字节,与Sync报文一致。
Follow_Up报文结构
对应代码
port.c中的port_tx_sync,在生成Sync报文后立即生成Follow_Up报文并发送。
port.c中的process_follow_up,处理收到的Follow_Up报文:

  1. 判断当前端口状态,只有UNCALIBRATED和SLAVE两种状态需要处理Follow_Up报文;
  2. 判断端口的父时钟端口ID和消息源端口ID是否一致,只有一致才需要处理;
  3. 提取Follow_Up报文中的信息;
  4. 判断本次Follow_Up消息和在收到本次Follow_Up消息之前端口收到的上一个Sync消息是否是同一个SequenceID,并更新端口的syfu状态。若ID匹配,调用port_synchronize计算修正后的t1并记录t2。(这是因为由于网络原因,Follow_Up报文有可能先于Sync到达端口)

Delay_Req报文

功能
Slave端口→Master端口,请求Master端口发送Delay_Resp报文。
占用空间大小为44字节。报文格式与Sync报文相同。
对应代码:
port.c中的port_delay_request,生成Delay_Req报文并发送。
port.c中的bc_event,调用port_delay_request
port.c中的process_delay_req,处理收到的Delay_Req报文:

  1. 判断当前端口状态,只有MASTER和GRANDMASTER两种状态需要处理Delay_Req报文;
  2. 创建Delay_Resp消息,在receiveTimestamp中填上收到Delay_Req的时间戳,并设置好其他部分封装成Delay_Resp报文;
  3. 向发送Delay_Req的端口发送Delay_Resp报文。

Delay_Resp报文

功能:Master端口→Slave端口,Master端口回复Slave端口自己收到Delay_Resp报文的精确时间戳。
Delay_Resp报文
占用空间大小为54字节。
Delay_Resp报文结构
对应代码
port.c中的process_delay_req,生成Delay_Resp报文并发送。
port.c中的bc_event,调用process_delay_req
port.c中的process_delay_resp,处理收到的Delay_Resp报文:

  1. 判断当前端口状态,只有UNCALIBRATED和SLAVE两种状态需要处理Delay_Resp报文;
  2. 依次检查:
    ①Delay_Resp携带的requesting端口是否为当前端口;
    ②Delay_Resp是否来自当前端口对应的父时钟端口,只有均一致才需要处理;
  3. 遍历当前端口已发送的Delay_Req队列,查找到该Resp对应的Req,只有找到才进一步处理;
  4. 记录接收时间t4并修正不对称性误差,记录对应Req的发送时间t3;
  5. 在Delay_Req队列中删除对应的Req。

目前主要看了这些,P2P的时间同步还没开始看,后面看了再更。希望各位大佬不吝赐教~

您可能感兴趣的与本文相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值