上一篇画了地图:gPTP 是 TSN 的地基,全网必须对齐到同一个时间源——GM(Grandmaster,主时钟)。

问题来了:一个网络里可能有一堆带时钟的节点(域控、交换机、ECU),凭什么你说的算?GM 是怎么选出来的?选错了怎么办?主挂了谁接班?

答案就是 BMCA(Best Master Clock Algorithm,最佳主时钟算法)。这篇把它讲透。

一、先认识时钟家族里的三种角色

gPTP 网络里的设备,按时钟能力分三类:

角色全称干什么车载典型设备
OCOrdinary Clock(普通时钟)单端口设备,要么当 GM,要么同步别人ECU、域控、摄像头
BCBoundary Clock(边界时钟)多端口交换机,每个端口独立参与 BMCA,向上游同步、向下游转发时间车载交换机、中央网关
TCTransparent Clock(透明时钟)只测量并补偿报文在自己这里的驻留时间,不参与"选王"早期 1588 方案里常见

车载网络几乎只用 BC,不用 TC。 为什么?

TC 的玩法是"报文本机转发,我只在 correctionField 里记一笔自己花了多久"——听起来高效,但它对报文敏感:每转一跳,驻留时间的测量误差、报文的串行化延迟都会往 correctionField 里累加,级联几跳后噪声就上来了。

BC 则是"中转站"模式:交换机在自己的 GM 口同步上游时间,然后在其他端口以主时钟的身份重新发出 Sync。下游设备看到的是一个"新的、干净的"主时钟,驻留时间在 BC 内部就被吸收掉了,不往报文里累加误差。级联十跳,误差也不叠加。

这也是 802.1AS 相对 1588 的一个明确取向:大规模级联网络,BC 是标配。

二、BMCA 比什么:七个字段的"选王积分榜"

每个时钟节点都有一份"成绩单",学名叫 defaultDS(数据集),核心字段:

字段含义设计建议
priority1一级优先级,手工配置想手动指定谁是 GM,改它最直接
clockClass时钟等级,描述时钟源的"血统"6 = 同步到主参考(GPS 等),187 = 默认自由运行
clockAccuracy声称的时间精度等级按时钟源真实能力填,别虚报
offsetScaledLogVariance时钟稳定度(方差的对数)由时钟硬件质量决定,一般自动
priority2二级优先级,手工配置同一血统内区分主备
clockIdentity时钟唯一标识,8 字节 EUI-64最终 tiebreaker,比大小,纯看"运气"
stepsRemoved经过了多少个 BCAnnounce 报文每过一跳 +1

BMCA 的规则很朴素:字段依次往下比,分出胜负就停。顺序是:

priority1        (越小越优先)
  ↓ 打平
clockClass       (越小越优先,血统越正)
  ↓ 打平
clockAccuracy    (越小越优先)
  ↓ 打平
offsetScaledLogVariance
  ↓ 打平
priority2        (越小越优先)
  ↓ 还打平
clockIdentity    (纯比大小,谁小谁赢)

stepsRemoved 不参与"比优劣",它只在路径选择时起作用:当一个端口同时收到多个 Announce,选 stepsRemoved 最小的那条路径;一样大才回到上面的字段比较。

注意全是"越小越优先"。priority 填 0 是最想当主,填 255 是最不想。别搞反。

三、BMCA 怎么跑起来:Announce 报文的分级传播

光有成绩单不够,还得让所有节点都看见彼此的成绩。BMCA 靠 Announce 报文完成,整个过程分两级:

3.1 每个端口本地选"最优外来时钟"

设备每个端口都会收邻居发来的 Announce,在端口本地做个比较:收到的外来时钟 vs 自己心里记的"当前推荐时钟",用上面那套规则比。赢了的留下,输出不变。

3.2 设备级选 GM,定端口的角色

把所有端口选出的最优外来时钟,再和设备自己比一次:

  • 自己赢 → 本设备就是 GM,宣告"我就是王"
  • 外来时钟赢 → 本设备当从时钟,收到胜出 Announce 的那个端口变成 slave port(从端口),其他端口继续对外发 Announce——但发的不是原创,而是转发学到的"王"的成绩单(stepsRemoved +1)

于是整网形成一条 GM → 各级 BC → 末端 OC 的同步树,像这样:

        ┌─────┐
        │ GM  │  ← priority1=0,clockClass=6(GPS 参考)
        └──┬──┘
           │ Announce 传播
      ┌────┴────┐
      │ BC-1    │  域控内交换机,slave 口朝上,GM 口朝下
      └──┬──┬──┘
         │  │
      ┌──┴┐ ┌┴───┐
      │OC │ │OC  │  ← 摄像头 / 雷达 ECU,全部同步到 GM 时间
      └───┘ └────┘

每个 OC 眼里只有一个"王"——GM。它不知道中间过了几个 BC,那些是 BC 该操心的事。

3.3 GM 挂了怎么办

GM 失联后,slave 口的 Announce 会超时(gPTP 里 Announce 接收超时典型 3 个间隔)。超时后该端口立刻重新参与本地比较——次优的那个时钟自动上位。

假设 GM 平时 priority1=0、备用域控 priority1=8:平时域控安安分分当 BC,GM 一挂,域控的成绩单秒杀全场,自动继位。不需要人工干预,不需要上层协议栈介入,这就是 BMCA 设计的漂亮之处。

故障恢复还有个细节:旧 GM 恢复后不会立刻抢回王位,要看 priority——如果它 priority1=0 还是最高,那全网会重新收敛到它。所以备时钟的 priority 一定要设得比主高,否则抢主权打得不可开交。

四、一个实例:把七个字段过一遍

假设域控里两个候选:

字段域控 A域控 B
priority1128128
clockClass66
clockAccuracy0x200x20
offsetScaledLogVariance0x4E5D0x4361
priority2128128

比到 offsetScaledLogVariance:0x4361 < 0x4E5D,B 赢,B 当 GM。

假设 B 挂了一段时间又回来,而 A 已经当了两年"王"——没关系,BMCA 是状态机不是历史问题。B 的 Announce 一到,A 发现 B 的成绩单更好,乖乖交出王位,全网重新收敛。收敛时间取决于 Announce 间隔,几百毫秒量级。

再假设两个域控成绩单一模一样,连 clockIdentity 都是同厂同型号撞了——比 clockIdentity 大小,小赢。纯运气,但保证了全网的确定性:不会出现"一半设备跟 A、一半跟 B"的分裂局面。

工程教训:clockIdentity 默认常由 MAC 地址派生。同型号板子的 MAC 段址相近,比大小结果基本随机。想控制谁当 GM,老老实实配 priority,别赌 clockIdentity。

五、工程配置的三条经验

  1. GM 必须挂在最好的时钟源上。GM 是全网的"发源地",它自己歪了,后面全歪。域控有 GPS/GNSS 参考的,priority1 设 0;没有外部参考的节点,clockClass 老老实实填 187(自由运行),别虚报 6——虚报血统,GM 挂了它接班,全网时间开始漂,查起来要人命
  2. priority 分层设计:主 GM(GPS)→ 备 GM(域控本地时钟)→ 交换机(不当王)→ 末端 ECU。一个清晰的主备链,故障场景行为可预测
  3. 时钟源要监控:BMCA 只管选,不管"选出来的王健康不健康"。建议在域控里加看护:slave 口 offset 长期超出阈值就告警,clockClass 异常跳变就告警——BMCA 不会告诉你"王中风了",它只会忠实地跟着王一起歪

六、结语

BMCA 的本质就一句话:一套确定性的优先级规则 + Announce 报文的分级传播,让全网在谁都可以当主的环境里,稳定收敛到唯一的最优时钟。

它没有投票、没有协商、没有"我觉得",全是查表比大小——所以它快(收敛以 Announce 间隔为单位)、且行为完全可预测。对车载这种"宁可确定性宕,不要概率性飘"的场景,这就是正确的气质。

下一篇讲 gPTP 的对时数学:Sync、Follow_Up、Delay_Req、Delay_Resp 四个报文怎么把 offset 和链路延迟算出来。那是 gPTP 最"硬"也最值得琢磨的部分。

你们网络里的主备时钟是怎么配的?有没有遇到过"王位"抢来抢去的问题?评论区见。

TSNgPTP802.1ASBMCA时钟同步