⚠️ 提示:本站 AI 助手使用博主个人 API Token,没事别特么瞎用。
运维 · · 约 54 分钟阅读

PTP / IEEE 1588 高精度时间同步完全指南:linuxptp(ptp4l / phc2sys / pmc / ts2phc)部署、四大 Profile 对比、以及 8 个硬件/配置坑

NTP 能把时间同步到 1~10ms,但到了 5G O-RU 帧头对齐、金融交易所订单撮合、广电 4K 演播室 SMPTE ST 2059-2、TSN 工业以太网、高速数据采集 DAQ 这些场景,就必须上 PTP(IEEE 1588)把误差压到亚微秒~纳秒级。本文从 OC / BC / TC 三种节点、Delay_Req/Resp 与 Pdelay 两种时延测量、一步/两步时钟这些基础概念开始,按『硬件前提→linuxptp 全家桶→两台直连 OC 最小可跑 Demo→生产 GM+BC+OC 架构→phc2sys 绑 PHC 与系统时钟→每个配置字段翻译→pmc/ethtool/phc_ctl 命令→8 个高频坑→四大行业 Profile 选型表』一步步铺完,所有命令都在 Ubuntu 24.04 + Intel i210/XL710 实测可用。

PTP / IEEE 1588 高精度时间同步完全指南:linuxptp(ptp4l / phc2sys / pmc / ts2phc)部署、四大 Profile 对比、以及 8 个硬件/配置坑

适用:Ubuntu 22.04 / 24.04 LTS、Debian 12、RHEL 9 / Rocky 9; 推荐网卡:Intel i210/i225/i226 / XL710 / XXV710 / E810、Mellanox ConnectX-4 Lx 及以上、Broadcom BCM5750x / NetXtreme-E; 交换机:Mellanox SN2010 / SN2410(Spectrum ASIC 支持 TC/BC)、Cisco Nexus 9300-EX/FX、HPE Aruba 6300M、华为 CE6865/CE8850 等明确写了”IEEE 1588 BC/TC 支持”的型号。


一. 前置概念:什么是 PTP、什么时候用 PTP、精度能到多少

0.1 PTP vs NTP 对比速表

维度NTPPTP (IEEE 1588)
典型精度局域网 100μs ~ 1ms,跨公网 1ms ~ 50ms带硬件时间戳 + BC/TC 交换机 → 亚 μs ~ 100ns;PPS/PTP Grandmaster 同源可到 <50ns;纯软件走 SW timestamp → 10~50μs(比 NTP 好一点但不到”真 PTP”)
通信协议UDP 123(单播为主)UDP 319(事件消息)/ 320(通用消息)+ 二层多播(01-1B-19-00-00-00)常见;消息类型里 Event Msg 才打 HW timestamp
同步算法客户端拉式 poll 模式 + slew主从周期性 Sync + 双向 delay 测量 + PI 控制器锁相环(servo)
谁负责消除中间节点延迟误差全靠客户端补偿,交换机排队 + 非对称路径误差无法消除节点类型里的 TC(透明时钟)会把”我停留了多少 ns”写进 CorrectionField;BC(边界时钟)重新发起下一跳 Sync,等于”每段重新同步”
适用部署规模几千~几万台(拉模式)几百~上千台(域内多播 224.0.1.129 / FF0X::181)
复杂度一条 server 指令完事需要网卡 HW 时间戳 + 交换机支持 BC/TC + BIOS 关省电 + 对 PHC/系统时钟二次同步

0.2 到底谁真的需要 PTP(别没事上 PTP,成本高)

行业场景要求精度上不上 PTP
一般后端业务 / 数据库 / etcd / ELK±100ms ~ ±1s不用,NTP/chrony 足够(别为了”看起来高端”硬上)
分布式链路追踪 / Prometheus 采集对齐±10ms不用,chrony + 局域网上游足够
高频交易 / 交易所订单匹配 / 期货撮合±1μs ~ ±10μs必须 PTP,甚至要 GPS PPS 同源 GM + TSC 时钟
5G O-RAN O-RU / O-DU / TDD 帧头对齐±1.5μs(ITU-T G.8271.1 Class C)必须 PTP(电信 G.8275.1 Profile)
广电 4K/8K IP 演播室 SMPTE ST 2110±1μs(SMPTE ST 2059-2 Genlock)必须 PTP(SMPTE 2059-2 Profile)
TSN 工业以太网 / 汽车自动驾驶多 ECU 同步±100ns ~ ±1μs(IEEE 802.1AS)必须 PTP(gPTP Profile)
多通道高速 ADC/DAQ 数据采集、雷达同步采样±100ns必须 PTP 或直接 PPS 硬触发
电力 PMU / 行波测距 / 变电站±1μs必须 IEEE 1588 + IEC 61850-9-3

0.3 PTP 核心概念一张图 + 术语小抄

flowchart TB
  G["GNSS 接收机(GPS / 北斗)"]
  GM["Grand Master(GM)<br/>OC 角色=master;priority1 最低;BMCA 选出的全局时间基准<br/>网卡带 PHC(PTP Hardware Clock)"]
  BC["Boundary Clock(BC)交换机<br/>收上游 Sync → 本地 PHY 打时间戳 → 锁本地 PHC → 再给下游发新 Sync<br/>每跳重新计时,不累积误差;也可旁挂 TC 交换机"]
  OC1["OC Slave(Ordinary Clock)<br/>带应用的服务器 / 5G DU<br/>程序读 CLOCK_REALTIME 或 CLOCK_TAI"]
  OC2["OC Slave<br/>摄像机 / 麦克风<br/>SMPTE2110 Sender"]
  TC["TC(Transparent Clock)<br/>只转发、把驻留时间写进 CorrectionField<br/>不参与 BMCA,不改 sync"]
  OC3["OC Slave<br/>PLC / 采集卡<br/>TSN 端点"]
  G -->|"PPS / 1PPS / ToD 串口或 NMEA"| GM
  GM -->|"Sync / Follow_Up<br/>每 125ms / 250ms / 1s 发"| BC
  BC -->|"下游 Sync"| OC1
  BC --> OC2
  BC --> TC
  BC --> OC3

术语小抄(每条都是你看配置文件会反复出现的):

术语一句话常见值/注意
OCOrdinary Clock 普通时钟只有一个 PTP 端口;要么当 Master 要么当 Slave;我们大多数服务器就是 OC Slave
BCBoundary Clock 边界时钟多个 PTP 端口,上游 Slave、下游 Master,逐段重新同步
TCTransparent Clock 透明时钟(有 E2E TC / P2P TC)不改 Sync 内容,只把”我这台交换机排队滞留了多少 ns”写到 CorrectionField 里
GM / GrandmasterBMCA 算法选出来的全局时间基准源(老大)priority1/priority2 越小越优先
BMCABest Master Clock Algorithm 最佳主时钟选举看 priority1→class→accuracy→variance→priority2→UUID,两步走
Domain Number (Domain)同一链路上可以跑多组互不干扰的 PTP0~127;G.8275.1 常用 domain 24;SMPTE 常用 domain 128;两边不一样永远收不到消息
Sync / Follow_Up / Delay_Req / Delay_RespPTP 四个核心事件/通用消息详见 §0.4
Pdelay_Req / Pdelay_Resp / Resp_Follow_UpP2P(点到点延迟测量)用的一组(per link)整条链路所有 TC 都必须支持 P2P 才能用
One-step(一步时钟)/ Two-step(两步时钟)One-step:Sync 帧里就带精确 TX 时间戳(硬件立刻改帧内容);Two-step:Sync 先发、随后再发 Follow_Up 补真实 TX 时间戳(现在多数网卡是 Two-step,ptp4l 会自动判断 Support)网卡手册写着 1588 One-step / support follow_up
Correction FieldPTP 头里 64 位 ns 字段,TC 把排队驻留时间加上,从端用它修正 offset越大说明路径抖动越大
PHCPTP Hardware Clock:网卡芯片上独立的 64 位 ns 计数器(和主机系统时钟独立!)/dev/ptp0、/dev/ptp1 字符设备,由驱动注册
meanPathDelay单向平均链路延迟(从 master→slave 的 ns 值)由 delay_meas 算出来,每几秒更新一次
offsetFromMasterslave 当前比 master 偏了多少 ns(正=我比它快,负=我慢)这个值压到 ±100ns 就是健康的 PTP
Servo / PI controllerptp4l 内部用比例积分控制器把 offset 压向 0,类似锁相环配置 pi_proportional_const / pi_integral_const
Sync interval(logSyncInterval)每 2^n 秒发一次 Sync,写 log2-3=每 125ms 发一次(电信/广电常见)、0=每 1s(default profile)

0.4 一次同步的四个报文(E2E 两步时钟时序,最通用的模式)

sequenceDiagram
  participant M as Master
  participant S as Slave
  M->>S: Sync(t1 还不知道,等 Follow_Up 补)
  Note over S: Slave 收到记 t2(RX 硬件时间戳)
  M->>S: Follow_Up(携带真实 t1 = Master TX 硬件时间)
  S->>M: Delay_Req(t3 = Slave TX 硬件时间)
  Note over M: Master 收到记 t4(RX 硬件时间戳)
  M->>S: Delay_Resp(携带真实 t4)
  Note over S: meanPathDelay = ((t2-t1) + (t4-t3)) / 2
  Note over S: offsetFromMaster = (t2-t1) - meanPathDelay
  Note over S: 然后用 PI servo 把 offset 慢慢调到 0

如果是 P2P:在 Delay_Req/Resp 那步换成 Pdelay_Req/Pdelay_Resp,并且每一对直连邻居单独算 path delay,不再依赖 GM 的回程时间;P2P TC 会把自己驻留+链路延迟都写 CorrectionField 里。电信 G.8275.1 要求 P2P。


二. PTP 版本与四大行业 Profile(决定你怎么写 ptp4l.conf)

先选 Profile 再搭环境,不要一股脑用 default,行业设备互不兼容会白折腾。

Profile对应标准领域Domain Number 默认TransportDelay 测量Sync Interval硬件要求
Default Profile ⭐(实验室先跑通用这个)IEEE 1588-2008 Annex J / 1588-2019通用 PTP 教学、普通高精度服务器0(推荐改)UDP IPv4/v6 或 L2E2ElogSyncInterval=0 (1s)任意支持 HW TS 的网卡即可,不要求交换机 TC/BC
G.8275.1 (PTP 电信相位/时间同步 Profile)ITU-T G.8275.1 (2022)5G O-RAN / 电信传输 / 基站 ToD24(业界默认)L2 Ethernet(不封装 IP/UDP)P2P(强制)logSyncInterval=-3 (125ms)T-BC/T-T-TSC 全链路 BC/TC;普通服务器做不了 GM,要专用 GM 设备
G.8265.1 (PTP 频率 Profile)ITU-T G.8265.1同步网频率(不关心墙上时间,只要频率稳)4UDP/IPE2E16 包/秒支持 SyncE 最佳
SMPTE ST 2059-2SMPTE广电 IP 演播室 2110 / Genlock128(SMPTE 约定)UDP/IPE2E 或 P2P125ms ~ 1s要求 SMPTE 2059-2 Profile 交换机 BC
IEEE 802.1AS / gPTPIEEE 802.1AS-2020TSN 工业/汽车自动驾驶/AVB 音视频0L2P2P(强制)125ms ~ 8s全链路必须 802.1AS-capable;普通网卡不行,车上用汽车级以太网 PHY

本文后面的”两台直连 Demo”用 Default Profile,生产”GM + BC 架构”以 Default/G.8275.1 混合举例。


三. 硬件前提(PTP 最容易踩坑的部分:硬件不满足,调一个月也出不来亚微秒)

2.1 网卡:必须带 PHC(PTP Hardware Clock)+ HW timestamping

先查你机器网卡到底支不支持,别瞎调:

# 查 PCI 网卡型号
lspci | grep -i ether
lshw -C network | grep -E 'product|vendor|serial|bus info'

# === 最关键的一条命令:ethtool -T ===
sudo ethtool -T eth0

能跑”真 PTP”的 ethtool 输出(i210 / ConnectX-6 Dx 典型):

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)  ✅ 必须(= 暴露 /dev/ptpX)
PTP Hardware Clock: 0                                            ✅ 会在 /dev/ptp0 看到
Hardware Transmit Timestamp Modes:
        HWTSTAMP_TX_ON                                          ✅ 单包开启 HW 打戳
        HWTSTAMP_TX_ONESTEP_SYNC                                ✅ One-step 同步帧
Hardware Receive Filter Modes:
        HWTSTAMP_FILTER_NONE
        HWTSTAMP_FILTER_ALL
        HWTSTAMP_FILTER_PTP_V2_L4_EVENT
        HWTSTAMP_FILTER_PTP_V2_L2_EVENT
        HWTSTAMP_FILTER_PTP_V2_L4_SYNC
        HWTSTAMP_FILTER_PTP_V2_L2_SYNC

常见合格网卡速查表:

厂商型号PHY 时间戳 One-step典型用途
Inteli210 / i210-IS(带 i210 驱动 igb)支持入门 PTP 首选;便宜、驱动稳
Inteli225/i226 / TSN 版 i226-LM支持新 2.5G 工业小机
IntelXL710 / XXV710 (i40e)支持25G SFP28 机房主流
IntelE810-C / E810-XXVDA4 (ice)One-step Sync10G~100G,4G/5G 基站回传
Mellanox/NVIDIAConnectX-4 Lx / 5 / 6 / 7 Dx支持,Follow_Up 模式常见10G~400G 全场景,mlx5_core 驱动自带 ts
BroadcomBCM57414 / BCM57504 / NetXtreme-E支持HPE/Dell 板载

常见不合格的坑:

  • Realtek RTL8111H/RTL8125:基本都是 SW Timestamp,别试
  • VMWare VMXNET3 / KVM Virtio-NIC:完全没有 HW TS,虚拟机上跑 PTP 意义不大(SW Timestamp 10μs 顶天)

2.2 交换机:必须支持 802.1AS / BC / TC,不要用”傻交换机”

  • 合格:写了”IEEE 1588v2 BC / End-to-End Transparent Clock / Peer-to-Peer TC”的交换机
  • 不合格:普通千兆无管理交换机、一般园区接入交换机(会把几百 ns~几 μs 的排队抖动直接吃进 path delay)
  • 偷懒技巧:两台机器网线直连,没有中间交换机就不用考虑 TC/BC,是入门最稳的

2.3 服务器 BIOS:关省电、开性能模式

  • CPU C-state / C1E / Intel SpeedStep / AMD PowerNow → Disable(PC 省电会让 TSC 跳)
  • PCIe ASPM (L0s / L1) → Disable(ASPM 进入低功耗会让 PHY 时钟漂移几十 ns)
  • Memory power saving / DRAM refresh partial self-refresh → Performance
  • SR-IOV 无关时关

2.4 布线 / 物理层

  • 铜缆:Cat6a 屏蔽(UTP 够了,别用 Cat5e),长度尽量一致(左右 <10m 差),减少路径非对称性
  • 光模块:单模 1310nm LR、多模 850nm SR 都行,主从尽量用同一型号光模块(RX/TX 延迟对称性好)
  • 不要走 NAT / 多跳 / 路由器跨 VLAN(PTP 默认走二层多播;走三层要静态 IP Multicast Routing + PIM 加组)

四. Linux PTP 栈:linuxptp 全家桶安装与字符设备

PTP 不是一个程序搞定的,是一个组合拳,分工如下:

程序职责类比 NTP 什么角色
ptp4l运行 IEEE 1588 状态机:BMCA 选 GM、发/收 Sync/FollowUp/DelayReq,算 offset,用 PI 伺服器调整 PHC 时钟相当于 chronyd,但是调的是网卡 PHC,不是系统时钟
phc2sysPHC ↔ CLOCK_REALTIME(系统时钟)双向同步:把 ptp4l 锁好的 PHC 同步给系统时钟,或从 GPS PPS 得到的系统时钟往 PHC 刷chrony 的 rtcsync 对应,只不过是 PHC 和系统时钟之间的胶水
ts2phc外部 1PPS / GPS NMEA / 10MHz → 写入网卡 PHC(GM 机专用,把 GPS 接收机的秒脉冲喂给 PHC 成为 Grandmaster)相当于 ntpd 里的 server 127.127.x.* PPS refclock
pmcPTP Management Client:向 ptp4l 发管理查询,读 offsetFromMaster / meanPathDelay / GM 信息相当于 chronyc(但只读多)
phc_ctl调试用:直接读 /dev/ptpX,两个 PHC 对差、手动 step、频率校准相当于 hwclock,但比 hwclock 精细到 ns
hwstamp_ctl对网卡开启/关闭 TX/RX 硬件时间戳(一般 ptp4l 自动做)底层工具
testptp内核源码 sample 工具:打 PPS、读 PHC 周期、PTP 外设自检验证驱动用

3.1 安装 linuxptp + 确认 /dev/ptp* 存在

# ===== Ubuntu 22.04 / 24.04 / Debian 12 =====
sudo apt update
sudo apt install -y linuxptp ethtool pps-tools
# 验证
which ptp4l phc2sys pmc ts2phc phc_ctl hwstamp_ctl
# → /usr/sbin/ptp4l  /usr/sbin/phc2sys ... 齐了
ls -la /dev/ptp*
# → crw-rw-rw- 1 root root 248, 0 Aug 27 09:00 /dev/ptp0   ✅ 这就是网卡 PHC
#    多 PTP 网卡会有 /dev/ptp1  etc.

# ===== RHEL 9 / Rocky 9 =====
sudo dnf install -y linuxptp ethtool pps-tools

看哪个网卡对应哪个 /dev/ptpX:

# 方法 A:ethtool -T eth0 里写了 PTP Hardware Clock: 0 → 对应 /dev/ptp0
# 方法 B:sysfs 一条命令搞定
for d in /sys/class/net/*; do
  echo "$(basename $d) -> $(readlink -f $d/device/ptp/ptp* 2>/dev/null || echo NONE)"
done

五. 最小可跑 Demo:两台机器网线直连 + Default Profile + 硬件时间戳(10 分钟入门)

两台完全一样的机器最好,网卡同型号(路径非对称最小化)。两台都按 §2 做过 ethtool 检查,都有 /dev/ptp0。

角色IP(二层多播其实不要 IP,只是 SSH 管理用)网卡名
Master(未来 GM 候选)192.168.99.1/24enp1s0
Slave192.168.99.2/24enp1s0

4.1 两台都先做:关掉 NetworkManager 的”自动改时间”,网卡 up

sudo systemctl disable --now chrony ntp systemd-timesyncd 2>/dev/null || true
sudo ip link set enp1s0 up
sudo ip addr add 192.168.99.1/24 dev enp1s0   # Master 执行;Slave 写 2

4.2 两台共用一份 /etc/linuxptp/ptp4l.default.conf(直接抄)

mkdir -p /etc/linuxptp
cat | sudo tee /etc/linuxptp/ptp4l.default.conf > /dev/null <<'EOF'
# ============ Default Profile (Demo 专用,生产要改) ============
[global]
# 我当从机吗? slaveOnly=1 强制当 Slave,不参与 BMCA
# 两台都先设 0(默认参加 BMCA,priority1 小的会被选为 GM)
slaveOnly               0

# GM 选举优先级,越小越优先(Master 写 128,Slave 可以在启动参数覆盖成 255)
priority1               128
priority2               128

# PTP Domain:0~127,两边必须一样!
domainNumber            0

# 传输层:UDP over IPv4 (1);L2 Ethernet 用 0;G.8275.1 必须 L2
network_transport       UDPv4

# 延迟测量:E2E(0) = Delay_Req;P2P(1) = Pdelay_Req
delay_mechanism         E2E

# 时钟伺服:PI (比例积分,默认) 或 linreg
clock_servo             pi

# 一步/两步:0 = 自动检测 follow_up;1 = 强制一步;通常保持 0 自动
twoStepFlag             0

# 首次上线误差 > 200ns 时允许一次性 step(对齐后就用 PI 慢慢拉)
first_step_threshold    0.0000002
# 正常运行中,单次 offset 超过多少才允许 step(0=永远不 step,只 slew)
step_threshold          0

# 频率调整上限(ppb,默认 900M=90%,小网卡晶振差可放宽到接近 1e9=100%)
max_frequency           900000000

# Sync/Announce/Delay_Req 的间隔 (log2 秒):0 = 1s;-3 = 125ms;-4 = 62.5ms
logSyncInterval         0
logAnnounceInterval     1
logMinDelayReqInterval  0
# 宣告超时 = announceReceiptTimeout × 2^logAnnounceInterval = 5 × 2s = 10s,收不到 Announce 就进入 BMCA 重选
announceReceiptTimeout  5

# PI 伺服参数(Default Profile 默认,G.8275.1 有推荐值)
pi_proportional_const   0.700
pi_integral_const       0.010

# TX timestamp 超时:等不到 TX 硬件时间戳回复就丢包重打
tx_timestamp_timeout    10

# 网卡驱动名(DPDK/特殊驱动需要;普通 igb/mlx5_core 留空)
# network_transport ... 上面已写

# 每个接口参数(可覆盖 global)
[enp1s0]
# 单独指定该网卡用 HW timestamp(默认 AUTO);想强制软时间戳做对比可以写 software
# time_stamping hardware
EOF

4.3 Master 启动(前台 + verbose,观察现象)

# 开 1 号终端,前台跑(生产后续改 systemd service)
sudo ptp4l -f /etc/linuxptp/ptp4l.default.conf -i enp1s0 -m -q -l 6 \
          --priority1=128
# -m = 输出到 stdout;-q = 不打 syslog;-l 6 = INFO;--priority1 覆盖配置文件里的

理想输出(30s 后):

ptp4l[12345]: selected /dev/ptp0 as PTP clock
ptp4l[12345]: port 1: INITIALIZING to LISTENING on INIT_COMPLETE
ptp4l[12345]: port 0: INITIALIZING to LISTENING on INIT_COMPLETE
ptp4l[12345]: port 1: new foreign master ...
ptp4l[12345]: selected best master clock 0x001b21.fffe.000001
ptp4l[12345]: assuming the grand master role   ✅ 因为 priority1 最小 + 没别人,我当 GM

4.4 Slave 启动(另一台机器,前台 verbose)

# Slave 用更大的 priority1=255,让 BMCA 一定选 Master 当 GM
sudo ptp4l -f /etc/linuxptp/ptp4l.default.conf -i enp1s0 -m -q -l 6 \
          --priority1=255

Slave 端理想输出(~5 秒后开始 lock):

ptp4l[20001]: master offset   123456 s0 freq   +890 path delay   450
ptp4l[20001]: master offset    98765 s1 freq  +1020 path delay   451
ptp4l[20001]: master offset       42 s2 freq   +998 path delay   450   ✅ s2 = 进入 PHASE_LOCKED 了
ptp4l[20001]: master offset       -8 s2 freq   +991 path delay   450

s0 / s1 / s2 三状态:s0 = 初始化没对齐;s1 = 刚 step 过一次/frequency lock;s2 = PHASE LOCKED,offset 稳定到几十 ns,才算成功。

4.5 用 pmc 正式查 offset(比看日志靠谱,可脚本化)

# 本机查(Slave 上执行,读 Current / Parent / TimeStatus 三个数据集)
sudo pmc -u -b 0 -f /etc/linuxptp/ptp4l.default.conf \
    'GET CURRENT_DATA_SET' \
    'GET PARENT_DATA_SET'  \
    'GET TIME_STATUS_NP'

期望结果关键字段:

offsetFromMaster                          :: -12.0  ✅ 正负 50ns 内都很好
meanPathDelay                             :: 448    ✅ 双向时延均值 ns
parentPortIdentity                        :: 001b21.fffe.000001-1  ✅ 指向 Master MAC 生成的 ID
gmIdentity                                :: 001b21.fffe.000001     ✅ 和 Master ID 同
gmPresent                                 :: true
gmTimeBaseIndicator                       :: 0
lastGmPhaseChange                         :: 0x0000
leap61 / leap59 / currentUtcOffsetValid   :: false/false/true
timeTraceable / frequencyTraceable        :: true/true

4.6 把 PHC 同步给系统时钟(这样 date / CLOCK_REALTIME 读的时间才是对的!)

ptp4l 只调 PHC(/dev/ptp0),不碰系统时钟,一定要再跑一个 phc2sys 做胶水:

# Slave 机器上:以 /dev/ptp0(ptp4l 锁好的网卡硬件时钟)为源,去同步 CLOCK_REALTIME(系统时钟)
sudo phc2sys -s /dev/ptp0 -c CLOCK_REALTIME -w -m -q -O 0 -l 6
#  -s = source clock
#  -c = destination clock
#  -w = 等 ptp4l 进入 s2 PHASE_LOCKED 再干活(安全!不会拿错的 PHC 刷系统时间)
#  -O 0 = 不额外加固定 TAI/UTC offset(有闰秒时按 TAI 偏移修正,一般 0 就行)
#  -n <domain> 可以通过 domain number 自动找 ptp4l 用的网卡,不用手动写 /dev/ptpX

phc2sys 理想输出:

phc2sys[...]: offset     -34 s2 freq  +1234 delay   12345   ✅ offset < ±1μs 正常

⚠️ 反过来 GM 端如果 GPS 给的是系统时钟,要把 CLOCK_REALTIME 刷到 PHC:phc2sys -s CLOCK_REALTIME -c /dev/ptp0 -w -m。


六. 生产级架构:Grand Master(接 GPS)→ BC 交换机 → 几十台 OC Slave

5.1 GM 机器选型 & GPS 接收机

  • 建议 GM 机:Intel i3 N100 小主机 + i210 网卡 + GPS 接收机(串口/USB PPS) 或专业 GPSDO(Trimble Resolution T、u-blox ZED-F9T、Leica 等)
  • GM 机需要把 GPS 的 1PPS(秒脉冲物理信号+NMEA RMC/GGA 报文+ToD) 结合,得到一个”准到 20ns 以内的 UTC 时间”喂给 PHC
  • linuxptp 自带 ts2phc:把外部 PPS 信号(接另一个 i210 的 SDP 引脚)或串口 10MHz 对齐到 PHC

5.2 ts2phc 把 GPS PPS → 写入 PHC(GM 专用)

典型接线:GPS 接收机的 1PPS TTL 引脚 → i210 的 SDP0(通用引脚,驱动可做外部触发);NMEA 串口 → /dev/ttyS0 用 chrony/NMEA 先粗略对齐。

cat | sudo tee /etc/linuxptp/ts2phc.conf > /dev/null <<'EOF'
[global]
leapfile /usr/share/zoneinfo/leap-seconds.list
# 全局 TS2PHC 模式:每收到一个外部 PPS,用它校正 PHC
ts2phc.pulsewidth 100000000
ts2phc.tty          /dev/ttyUSB0            # NMEA 串口,可选
ts2phc.message_id   GGA RMC                 # NMEA 语句
# pin 映射:网卡 enp1s0 (PHC index 0) 的 SDP0 作为 PPS in
[enp1s0:ts2phc]
ts2phc.extts_polarity rising
ts2phc.channel 0
ts2phc.pin 0
EOF

sudo ts2phc -f /etc/linuxptp/ts2phc.conf -c /dev/ptp0 -m -l 6

如果嫌接线麻烦,直接让 GM 的 chrony 先通过 PPS refclock 锁到 UTC ±1μs,再 phc2sys 把系统时钟写进 PHC。效果差不多(200ns 内),但简单很多。

5.3 GM / BC 交换机 / Slave 角色各自的典型 ptp4l.conf 片段

GM(priority1=1,强制不 slaveOnly,接 PPS 后就是全局老大):

[global]
slaveOnly                   0
priority1                   1
priority2                   1
domainNumber                24
# 如果是电信 G.8275.1,下面三行必须
# network_transport         L2
# delay_mechanism           P2P
# G.8275.1 电信 domainNumber=24
# SMPTE 2059-2 一般 domainNumber=128
clockClass                  6        # GM 被 GPS 锁到 =6;没锁=248
clockAccuracy               0x21     # 25ns~100ns(u-blox F9T 常见等级)
offsetScaledLogVariance     0x1000
# Announce/Sync 要密集
logSyncInterval            -3        # 125ms
logAnnounceInterval         0        # 1s 一条宣告
first_step_threshold        0.0000001
step_threshold              0
tx_timestamp_timeout        20
kernel_leap                 1

Slave OC(普通业务机):

[global]
slaveOnly                   1       # 不参与选举,我就是来当从机的,省 BMCA 计算
priority1                   255
domainNumber                24               # 跟 GM 一样!可选 0/24/128
delay_mechanism             E2E              # 跟链路上 TC 模式一致!可选 E2E/P2P
clock_servo                 pi
first_step_threshold        0.0000002
step_threshold              0.000000050      # 正常运行中最多 step 50ns,否则只 slew
pi_proportional_const       0.300
pi_integral_const           0.003
sanity_freq_limit           200000           # 频率疯了(>200ppm)就停下来,防止跳时
tx_timestamp_timeout        10
# 用 phc2sys -n <domain> 自动找这个 slave 的 PHC

5.4 systemd 持久化(生产一定要写成 service,不要前台跑)

Ubuntu 24.04 带的 linuxptp 包可能已经有模板,我们覆盖成自己的:

# ---- ptp4l@.service:按网卡名启用,比如 systemctl enable --now ptp4l@enp1s0 ----
cat | sudo tee /etc/systemd/system/ptp4l@.service > /dev/null <<'EOF'
[Unit]
Description=Precision Time Protocol (PTP) service for %I
Documentation=man:ptp4l
After=network-online.target
Wants=network-online.target
Requires=network.target

[Service]
Type=simple
ExecStart=/usr/sbin/ptp4l -f /etc/linuxptp/ptp4l.%i.conf -i %I -l 6 -q
Restart=on-failure
RestartSec=3
AmbientCapabilities=CAP_SYS_TIME CAP_NET_ADMIN CAP_NET_RAW

[Install]
WantedBy=multi-user.target
EOF

# ---- phc2sys@.service:按 domain 启用,比如 phc2sys@0 ----
cat | sudo tee /etc/systemd/system/phc2sys@.service > /dev/null <<'EOF'
[Unit]
Description=Synchronize PTP Hardware Clock and System Clock (domain %i)
Documentation=man:phc2sys
After=ptp4l.target

[Service]
Type=simple
ExecStart=/usr/sbin/phc2sys -n %i -w -l 6 -q -O 0
Restart=on-failure
RestartSec=3
AmbientCapabilities=CAP_SYS_TIME

[Install]
WantedBy=multi-user.target
EOF

# ---- ts2phc@.service:GPS 串口转 PTP 硬件时钟 ----
cat | sudo tee /etc/systemd/system/ts2phc@.service > /dev/null <<'EOF'
[Unit]
Description=GPS to PTP Hardware Clock (%i)
Documentation=man:ts2phc
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/sbin/ts2phc -f /etc/linuxptp/ts2phc.%i.conf -l 6 -q
Restart=on-failure
RestartSec=3
AmbientCapabilities=CAP_SYS_TIME

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
# Slave 机启动
sudo systemctl enable --now ptp4l@enp1s0 phc2sys@0
# GM 机(domain 24)
sudo systemctl enable --now ts2phc@enp1s0 ptp4l@enp1s0 phc2sys@24

5.5 锁状态/监控怎么看(生产脚本化)

# 1. 看 ptp4l 锁状态(0=s0 FAILED, 1=s1 FREQ, 2=s2 PHASE)
sudo pmc -u -b 0 'GET TIME_STATUS_NP' | awk '/phaseState/{print $NF}'
# 脚本健康检查:必须输出 "LOCKED" 或数字 2

# 2. 看 offsetFromMaster 绝对值(必须 < 250ns warning / < 1000ns critical)
sudo pmc -u -b 0 'GET CURRENT_DATA_SET' | awk '/offsetFromMaster/{o=$NF;if(o<0)o=-o;print o}'

# 3. 读两台机 PHC 绝对差(同一台机上没法读两台的,用 phc_ctl 读本台+日志比对;最准的是共用 PPS 进示波器)
sudo phc_ctl /dev/ptp0 get

# 4. phc2sys 日志看"是否在稳定同步"
journalctl -u phc2sys@0 -n 50

Prometheus 监控接入(可选,推荐):ptp_exporter 或 linuxptp_exporter,告警:

  • ptp_phase_state != 2 → critical
  • abs(ptp_offset_from_master_ns) > 250 → warning;>1000 → critical
  • ptp_mean_path_delay_ns 突变 → warning(链路换了/中间 TC 下线)
  • phc2sys abs(offset) > 2000ns → warning

七. ptp4l.conf 常用字段速查(含 Default / G.8275.1 推荐值)

字段含义Default 推荐G.8275.1 电信推荐SMPTE 2059-2 推荐
slaveOnly1=强制当 Slave 不参选 GMSlave 机写 1OC Slave 写 1OC Slave 写 1
priority1 / priority2GM 选举权重GM=128,Slave=255GM=1~10GM=100
domainNumber域号024128
network_transportUDPv4 / UDPv6 / L2UDPv4L2UDPv4
delay_mechanismE2E / P2PE2EP2PE2E 常见
twoStepFlag一步/两步0 自动0 自动0 自动
first_step_threshold首次 step 阈值(秒)0.0000002 (200ns)1μs1μs
step_threshold稳态 step 阈值(0=永不 step)0050ns
max_frequency频率调整上限(ppb)900M200M200M
logSyncIntervalSync 间隔 log2s0 (1s)-3 (125ms)-3 ~ -1
logAnnounceIntervalAnnounce 间隔1 (2s)0 (1s)0 (1s)
announceReceiptTimeout宣告超时 = t × 2^logAnnounceInterval5 (10s)3 (3s)3 (3s)
clock_servopi / linreg / nullfpipipi
pi_proportional_const比例项(越大反应越快但容易抖)0.7000.3000.150
pi_integral_const积分项(越大频率修正越重)0.0100.0030.0015
tx_timestamp_timeout等 TX 硬件时间戳的 ms 超时102010
sanity_freq_limit频率超了自动停下(ppb)0=关200000 (200ppm)100000 (100ppm)
leapfile闰秒表路径/usr/share/zoneinfo/leap-seconds.list同同
kernel_leap闰秒前要不要给 kernel 发 announce111
uds_addresspmc 通信本地 socket/var/run/ptp4l同同

八. 常用命令速查(linuxptp + 调试工具)

#命令作用典型场景
1ethtool -T eth0查网卡 HW/SW TS 能力 + 对应 /dev/ptpX接新机第一条查
2ls /dev/ptp* && cat /sys/class/net/eth0/device/ptp/ptp*/clock_name网卡↔PHC 对应多 PTP 网卡
3sudo ptp4l -f conf -i eth0 -m -q -l 6 --priority1=N前台调试跑 ptp4lDemo/排障
4sudo pmc -u -b 0 'GET CURRENT_DATA_SET'offsetFromMaster / meanPathDelay健康检查最常用
5sudo pmc -u -b 0 'GET PARENT_DATA_SET'gmIdentity / parentStats确认跟着谁走
6sudo pmc -u -b 0 'GET TIME_STATUS_NP'gmPresent / phaseState s0-s2 / leap有没有 LOCKED
7sudo pmc -u -b 0 'GET PORT_DATA_SET'portState / tlv / version本机角色
8sudo pmc -u -b 0 'GET DEFAULT_DATA_SET'priority 1/2 / numberPorts / clockIdentityBMCA 选举调试
9sudo phc2sys -s /dev/ptp0 -c CLOCK_REALTIME -w -mPHC → 系统时钟同步Slave 必跑
10sudo phc2sys -s CLOCK_REALTIME -c /dev/ptp0 -w -m系统时钟(GPS 锁好的)→ PHCGM 配合 GPS chrony PPS
11sudo phc2sys -n 0 -w -m自动按 domain 找 ptp4l 开的 PHC,同步到系统时钟脚本友好,不用写 /dev/ptpX
12sudo ts2phc -f conf -c /dev/ptp0 -m外部 PPS/NMEA → PHC做 GM
13sudo phc_ctl /dev/ptp0 get直接读 PHC 时间戳(ns)对比两台 GM 的 PHC
14sudo phc_ctl /dev/ptp0 cmpPHC 和 CLOCK_REALTIME 的当前差phc2sys 有没有干活
15sudo hwstamp_ctl -i eth0 -r 1 -t 1手动开 RX/TX HW timestampptp4l 没自动开时
16sudo testptp -d /dev/ptp0 -T 10连续读 10 次 PHC 看漂移驱动调试
17ppscheck /dev/pps0看 GPS PPS 引脚是否收到稳定的每秒上升沿GM 接 GPS 验收
18journalctl -u ptp4l@enp1s0 -n 50 --no-pager看 ptp4l 日志出问题首查
19sudo pmc -u -b 0 -d 24 'GET CURRENT_DATA_SET'指定 domain=24 的管理查询G.8275.1
20sudo systemctl status ptp4l@enp1s0 phc2sys@0 ts2phc@enp1s0三件套 systemd 状态日常巡检

九. 8 个高频坑(按出现率排序,每个都能卡一周)

🐞 1. 以为在跑 PTP,实际只是软件时间戳,精度 10μs~100μs 就上不去

排查:ethtool -T 看 SOF_TIMESTAMPING_TX_HARDWARE / RX_HARDWARE / RAW_HARDWARE 三项有没有 ✅;没有就是 SW。ptp4l 启动日志里也写:

selected /dev/ptp0 as PTP clock   ✅ 硬件模式
using clockid CLOCK_REALTIME      ❌ 软件模式!拿不到 HW TS

修:换网卡 / 更新网卡固件 / 加 time_stamping hardware 到 ptp4l.conf interface 段。

🐞 2. domainNumber / delay_mechanism / network_transport 三边有一边不一致

现象:Slave 永远 s0 INITIALIZING,pmc GET PARENT_DATA_SET gmIdentity = 全 0,meanPathDelay 空。 排查:Master 和 Slave 分别开 -l 7 抓日志看收不收得到 Sync。

  • G.8275.1 写 L2,不是 UDPv4
  • G.8275.1 写 P2P,不是 E2E
  • domain 一边 0 一边 24 → 永远收不到

🐞 3. 普通交换机不支持 TC/BC → 排队延迟把 offset 顶到几 μs~几十 μs

现象:meanPathDelay 每次波动很大(> ±200ns),offsetFromMaster 抖得收不住。 修:

  • Demo 两机直连(最省事)
  • 生产换写了”IEEE 1588 TC/BC”的交换机,开启 TC 模式;或者整链路 BC

🐞 4. priority1 搞反 GM 乱选

现象:gmIdentity 每隔 30s 换一个机器,每次换 GM offset 会跳一下(BMCA 重新算)。 修:

  • GM 的 priority1 写 1 / 2 / 3,绝对不要 128
  • 备用 GM priority1 写 10~20,priority2 区分
  • 普通 OC slave:slaveOnly=1(不参选,彻底避免意外当 GM)

🐞 5. BIOS C-state / ASPM / CPU 调频导致 TSC 漂移、PHC 跟着抖

现象:晚上没人用服务器进入 C6 省电,早上唤醒 offset 一跳一跳;或者网卡 RX 延迟一跳一跳 jitter 很大。 修:BIOS 按 §2.3 全关省电;内核加 processor.max_cstate=1 idle=poll intel_idle.max_cstate=0;服务器性能 governor。

🐞 6. phc2sys 没跑 → 程序读的 CLOCK_REALTIME 还是不准

ptp4l 只调 PHC(网卡自己的小钟)。Java / Python / Go / C clock_gettime(CLOCK_REALTIME) 读的全是系统时钟。必须再 phc2sys 把 PHC → 系统时钟! 排查:sudo phc_ctl /dev/ptp0 cmp,两台机 PHC 差 100ns,但 date +%s%N 差几毫秒 → phc2sys 没起或没进 s2。

🐞 7. 两步时钟网卡配置成 One-step → Follow_Up 里根本没有 preciseOriginTimestamp

现象:ptp4l 报 received sync without follow up 警告;offset 永远大。 修:ptp4l.conf 里 twoStepFlag 保持默认 0(自动探测),不要强置 1。

🐞 8. 路径非对称:A→B 延迟 450ns,B→A 延迟 470ns,PTP 取平均就会自带 10ns 偏

场景:光纤主从距离不同 / 光模块型号不一致 / 网卡 TX/RX PHY 延迟有偏差。 修:

  • 尽量同型号网卡+同批次光模块+等长布线
  • PHC 校准:用示波器/Time Interval Counter 测两台机 PPS 差值,加 phc2sys -O <offset_ns> 手动修
  • 使用 G.8275.1 / SMPTE 2059-2 自带”非对称校准 TLV” 的专业交换机/网卡,自动补偿

附录 A:行业 Profile 快速选法

你的行业选哪个 Profiledomain 默认示例交换机 BC 配置方向
实验室/通用服务器高精度Default Profile0普通交换机可不配(直连);配 TC 效果更好
5G / O-RAN / 移动传输G.8275.1 + SyncE 频率同步24华为 CE6865 / Nokia 7250 / Cisco NCS 540 开启 T-BC + P2P + telecom profile
广电 SMPTE 2110 / IP 演播室SMPTE ST 2059-2128Evertz / Imagine / Arista 7130P + SMPTE profile
汽车自动驾驶 / 工业 TSN / 专业音视频 AVBIEEE 802.1AS (gPTP)0车载 TSN 交换机 / NXP S32G 时间网关;必须全链路 gPTP-aware

附录 B:新部署 PTP 自检 7 条清单

  • ethtool -T eth0 三项 HW 打戳 + /dev/ptpX 全有
  • 两台直连或链路上 BC/TC 已开(P2P TC 链路 domain / delay_mechanism 全局一致)
  • GM ptp4l 日志里 assuming the grand master role + priority1 < 10
  • Slave pmc 能读到 phaseState=LOCKED (s2) 连续稳定 5 分钟
  • Slave pmc offsetFromMaster 稳定 ±250ns 内(100ns 以下为优秀)
  • phc2sys 已经 systemd enable + 运行;phc_ctl /dev/ptp0 cmp 差 < ±500ns
  • 接入 Prometheus 监控告警:offset > 1μs / phaseState != 2 立即告警

延伸:如果你已经把 PTP 跑到 <100ns,接下来的”极致派”路径是:(1) 把 GPSDO OCXO 换成铷钟 Rb(月漂移 <1e-11,抗短时间 GNSS 遮挡);(2) 全链路 One-step Sync + 对称布线 + 非对称补偿 TLV;(3) 应用层直接读 CLOCK_TAI / /dev/ptpX ioctl(PTP_SYS_OFFSET_PRECISE) 不要走系统时钟的任何中间层,这样金融交易/雷达采集就能跑进 ±20ns 级别。

问问 AI