第三章 802.1AS协议栈:协议层次结构与数据帧格式

说实话,刚接触802.1AS那会儿,我盯着协议栈分层图发了好一阵呆。你想想看,在车载网络或者工业以太网里,时钟同步要求亚微秒级精度,那么底层到底怎么把时间戳精准地嵌进报文里?层次搞不清楚,后面配置测试点、定位丢包问题全得卡壳。所以这一章咱们把协议栈剥开,看看每一层到底干了什么,数据帧又长什么样。

3.1 协议栈的分层哲学

802.1AS本质上是个Layer 2的协议,但它依赖物理层给时间戳打标记。分层结构从下往上依次是:

  • PHY层:负责物理介质收发,关键是在帧头帧尾的特定位置捕获精确时间戳。我遇到过某款PHY芯片时间戳点位偏了一个bit,结果同步误差直接窜到微秒级。
  • MAC层:负责介质访问控制,封装以太网帧头,接收PHY层上报的时间戳。
  • 协议层(广义精确时间协议):运行在MAC之上,处理Sync、Follow_Up、Delay_Req/Resp等报文,完成主从时钟的偏移与延迟计算。
  • 应用层:上层调用服务,比如音频视频桥接中的时间感知整形,或控制系统的同步调度。
重要概念:时间戳捕获点不在协议栈最顶层,而在最底层的PHY与MAC之间。802.1AS要求“驻留时间”计算必须扣除协议栈内部延迟,否则算出来的同步链路时间全是错的。

为什么非要这么分层?说白了,每层只关心一件事。PHY只管抓时间,MAC只管送包,只管算时间差。我曾经在测试中碰到一个问题:某个设备把时间戳捕捉放在了MAC软件层,结果每个包的时间戳偏差几十微秒——因为软件中断响应不可预测。从那以后我习惯先核查物理层时间戳接口的硬件实现。

个人经验:你看芯片手册时,重点看“Timestamping Unit”的框图。如果时间戳不是在PHY的MII接口处采样,那这芯片大概率不适合做边界时钟。

3.2 协议栈核心结构图

下面这张图是我在项目里经常拿出来跟团队对齐用的,可以直观看出层次关系和关键接口。里面标出了时间戳捕获点、协议层交互,以及最终报文在介质上的样子。

802.1AS 协议栈层次结构与帧封装 应用层(时钟同步应用 / 桥接服务) 调用服务接口,发起同步请求 协议层 Sync、Follow_Up、Delay_Req/Resp 报文生成与解析 最佳主时钟算法(BMCA) MAC层 + 逻辑链路控制(LLC) 以太网帧封装 / 解析 | 注册以太网类型 0x88F7 PHY层(物理层) MII接口 / 时间戳单元(TSU) 在SFD之后精确采样时间 ★ 时间戳捕获点 PTP 数据帧(IEEE 802.3 MAC帧) DA+SA EthType (0x88F7) PTP Header (34B) Message Body TLV FCS
看图要点:时间戳捕获点位于PHY层上方虚线处,通常在SFD(帧起始定界符)后的第一个比特同步时钟沿。层不直接跟时间戳打交道,它通过MAC层的接口拿到打戳后的报文。这个分离设计让协议栈可以移植到不同PHY上。

3.3 数据帧格式拆解

802.1AS使用标准的IEEE 802.3以太网帧,以太网类型固定为0x88F7。我刚开始用Wireshark抓包时,看到这个值就知道是了。帧结构包含以下几个关键部分:

字段 长度(字节) 说明
前导码 + SFD 8 物理层添加,MAC层不处理
目的MAC 6 一般为组播地址(比如01-80-C2-00-00-0E)
源MAC 6 发送端口MAC
以太网类型 2 0x88F7(标识)
PTP头部 34 包含版本、消息类型、域号、序列ID等
消息体 可变 不同类型报文内容不同(Sync 44B, Delay_Req 44B等)
TLV(可选) 可变 用于扩展,比如验证时间戳的follow_up信息
FCS 4 帧校验序列

PTP头部是理解同步流程的核心。你打开Wireshark看一眼就知道了,里面最关键的是messageType字段(占4bit),它决定了这个报文的作用:

  • 0x0 – Sync:主时钟发出,从时钟记录到达时间t2
  • 0x1 – Delay_Req:从时钟发出,主时钟记录到达时间t4
  • 0x2 – Follow_Up:主时钟将Sync的精确发送时间t1告诉从时钟
  • 0x3 – Delay_Resp:主时钟将Delay_Req的到达时间t4告诉从时钟
我的避坑指南:曾经我在一个项目中,发现从时钟算出来的偏移量总在正负100ns之间跳。后来抓包比对,原来是主时钟发出的Sync和Follow_Up报文的sequenceId不匹配。记住:802.1AS要求每条Sync必须有一条同sequenceId的Follow_Up,否则从时钟无法关联时间戳。

3.4 报文类型与关键参数速查

为了便于记忆,我整理了常用报文的核心参数对比。你可以在测试时快速查阅:

报文类型 messageType 发送方向 头部特殊字段 典型作用
Sync 0x0 主→从 无时间戳(由Follow_Up携带) 触发从时钟本地捕获
Follow_Up 0x2 主→从 preciseOriginTimestamp 补偿Sync的精确发送时间t1
Delay_Req 0x1 从→主 无时间戳(由Delay_Resp携带) 要求主时钟记录到达时间t4
Delay_Resp 0x3 主→从 receiptTimestamp 返回t4,用于计算链路延迟
关键提醒:802.1AS中Sync和Delay_Req报文的实际发送/到达时间并不在报文本体里,而是通过后续报文(Follow_Up/Delay_Resp)带过来。这是因为时间戳必须由硬件在出/入端口时打上,没法预知。如果你看到某个报文内部直接写了时间戳,那大概率是软件时间戳,精度不可靠。

3.5 实践:用Wireshark抓一个Sync帧

我个人习惯在实际调试时先用Wireshark打开抓取的pcap文件。一个典型的Sync帧(去掉前导码和SFD)看起来大概这样:

Frame 123: 64 bytes on wire (512 bits), 64 bytes captured
Ethernet II, Src: aa:bb:cc:dd:ee:01, Dst: 01:80:c2:00:00:0e
    Destination: 01:80:c2:00:00:0e (PTP v2 primary)
    Source: aa:bb:cc:dd:ee:01 (Some device)
    Type: 802.1AS (0x88f7)
Precision Time Protocol (IEEE 1588v2)
    0000 000. .... .... = transportSpecific: 0x0
    .... ...0 0000 0000 = messageId: Sync (0x0)
    .... .... .... 0000 = version: PTP version 2 (0x00)
    Message length: 44
    Domain number: 0
    Reserved: 00
    Flags: 0x0000
    Correction field: 0
    Reserved: 0x00000000
    Source port identity: ...
    Sequence id: 0x0001
    Control field: 0x00
    Log message interval: 0x01 (间隔 2^1 = 2秒)

注意,这里时间戳字段(如preciseOriginTimestamp)是空的——它会在后面的Follow_Up报文里出现。我刚开始学的时候老找不对地方,后来养成习惯:看Sync先看sequenceId,再看对应的Follow_Up,两者对上号才能开始算偏移。

经验技巧:如果你在Wireshark里看到多个连续的Sync而缺少Follow_Up,可以检查一下主时钟的“twoStepFlag”是否置位。802.1AS默认使用two-step模式(Sync+Follow_Up),但也有单步模式(one-step),不过很少见。调试时优先确认模式一致。