7.0 KiB
eno4 upstream toward RPi5 grandmaster
enp4s0/enp4s0d1 downstream toward N9K
This design is:
RPi5 GM
-> ptp4l-client on eno4
-> eno4 PHC
-> phc2sys-client
-> CLOCK_REALTIME on WOLF-HUNTER
-> phc2sys-downstream
-> enp4s0/enp4s0d1 PHC
-> ptp4l-downstream
-> N9K / downstream clients
ptp4l can use multiple -i interfaces, clientOnly is the client/slave mode, and serverOnly prevents a port from becoming a client. phc2sys is the tool that syncs PHCs and CLOCK_REALTIME; -w waits for ptp4l, while -O 37 provides the UTC/TAI offset explicitly. ([Linux PTP Project][1])
1. Upstream PTP client config: eno4
Create:
sudo nano /etc/linuxptp/ptp4l-upstream-client.conf
[global]
verbose 1
time_stamping hardware
domainNumber 0
network_transport UDPv4
delay_mechanism E2E
# Upstream side: only act as a PTP client/slave
clientOnly 1
summary_interval 1
# Separate UDS socket so multiple ptp4l instances do not collide
uds_address /var/run/ptp4l-upstream
[eno4]
2. Downstream PTP server config: enp4s0/enp4s0d1
Create:
sudo nano /etc/linuxptp/ptp4l-downstream-server.conf
[global]
verbose 1
time_stamping hardware
domainNumber 0
network_transport UDPv4
delay_mechanism E2E
# Downstream side: serve time toward N9K/clients
serverOnly 1
# Make this preferred on the downstream PTP segment
priority1 128
priority2 128
# This host is fed by upstream PTP, not directly by GNSS
timeSource 0x40
# Conservative advertised quality for a PTP-fed downstream server.
# You can tune these later after measuring.
clockClass 6
clockAccuracy 0x23
offsetScaledLogVariance 0xFFFF
utc_offset 37
summary_interval 1
# Separate UDS socket
uds_address /var/run/ptp4l-downstream
[enp4s0]
[enp4s0d1]
Small caveat: this split-service design works, but it is not a “pure” PTP boundary clock because the upstream and downstream ptp4l instances are separate. A single ptp4l boundary clock preserves PTP parent/stepsRemoved behavior better, but your split design avoids the mixed-PHC/JBOD issue.
3. ptp4l upstream client service
Create:
sudo nano /etc/systemd/system/ptp4l-upstream-client.service
[Unit]
Description=PTP upstream client on eno4
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/sbin/ptp4l -i eno4 -f /etc/linuxptp/ptp4l-upstream-client.conf -m
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
4. phc2sys upstream: eno4 PHC -> CLOCK_REALTIME
This syncs the boundary server’s own Linux system clock.
Create:
sudo nano /etc/systemd/system/phc2sys-upstream-to-system.service
[Unit]
Description=Sync WOLF-HUNTER system clock from upstream eno4 PHC
After=ptp4l-upstream-client.service
Requires=ptp4l-upstream-client.service
[Service]
Type=simple
ExecStart=/usr/sbin/phc2sys -s eno4 -c CLOCK_REALTIME -w -z /var/run/ptp4l-upstream -m
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
5. phc2sys downstream: CLOCK_REALTIME -> enp4s0 PHC
First check whether enp4s0 and enp4s0d1 share the same PHC:
readlink -f /sys/class/net/enp4s0/device/ptp
readlink -f /sys/class/net/enp4s0d1/device/ptp
ethtool -T enp4s0 | grep 'Hardware timestamp provider'
ethtool -T enp4s0d1 | grep 'Hardware timestamp provider'
If both are the same PHC, one downstream phc2sys service is enough.
Create:
sudo nano /etc/systemd/system/phc2sys-system-to-downstream.service
[Unit]
Description=Sync downstream enp4s0 PHC from WOLF-HUNTER system clock
After=phc2sys-upstream-to-system.service ptp4l-downstream-server.service
Requires=phc2sys-upstream-to-system.service ptp4l-downstream-server.service
[Service]
Type=simple
ExecStart=/usr/sbin/phc2sys -s CLOCK_REALTIME -c enp4s0 -O 37 -m
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
If enp4s0d1 is on a different PHC from enp4s0, create a second downstream PHC sync service too:
sudo nano /etc/systemd/system/phc2sys-system-to-downstream-d1.service
[Unit]
Description=Sync downstream enp4s0d1 PHC from WOLF-HUNTER system clock
After=phc2sys-upstream-to-system.service ptp4l-downstream-server.service
Requires=phc2sys-upstream-to-system.service ptp4l-downstream-server.service
[Service]
Type=simple
ExecStart=/usr/sbin/phc2sys -s CLOCK_REALTIME -c enp4s0d1 -O 37 -m
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
6. ptp4l downstream server service
Create:
sudo nano /etc/systemd/system/ptp4l-downstream-server.service
[Unit]
Description=PTP downstream server on enp4s0 and enp4s0d1
After=network-online.target phc2sys-upstream-to-system.service
Wants=network-online.target
Requires=phc2sys-upstream-to-system.service
[Service]
Type=simple
ExecStart=/usr/sbin/ptp4l -i enp4s0 -i enp4s0d1 -f /etc/linuxptp/ptp4l-downstream-server.conf -m
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
7. Enable in order
sudo systemctl daemon-reload
sudo systemctl enable --now ptp4l-upstream-client.service
sudo systemctl enable --now phc2sys-upstream-to-system.service
sudo systemctl enable --now ptp4l-downstream-server.service
sudo systemctl enable --now phc2sys-system-to-downstream.service
Only enable this one if enp4s0d1 has a different PHC:
sudo systemctl enable --now phc2sys-system-to-downstream-d1.service
8. Disable other system-clock discipliners on WOLF-HUNTER
On this boundary host, do not let chrony/NTP/timesyncd also adjust CLOCK_REALTIME while phc2sys-upstream-to-system is doing it:
sudo systemctl disable --now chrony 2>/dev/null
sudo systemctl disable --now systemd-timesyncd 2>/dev/null
sudo systemctl disable --now ntp 2>/dev/null
9. Verify
systemctl status ptp4l-upstream-client.service
systemctl status phc2sys-upstream-to-system.service
systemctl status ptp4l-downstream-server.service
systemctl status phc2sys-system-to-downstream.service
Logs:
journalctl -u ptp4l-upstream-client.service -f
journalctl -u phc2sys-upstream-to-system.service -f
journalctl -u ptp4l-downstream-server.service -f
journalctl -u phc2sys-system-to-downstream.service -f
Expected behavior:
ptp4l-upstream-client:
eno4 should go SLAVE / UNCALIBRATED -> SLAVE
phc2sys-upstream-to-system:
CLOCK_REALTIME phc offset ... s2 ...
ptp4l-downstream-server:
enp4s0/enp4s0d1 should assume MASTER/server role
phc2sys-system-to-downstream:
enp4s0 sys offset ... s2 ...
Also useful:
pgrep -a ptp4l
pgrep -a phc2sys