Files
RPi5-PTP-server/boundaryClockAndClient.md
2026-09-07 00:27:05 +02:00

295 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
```text id="97dya4"
eno4 upstream toward RPi5 grandmaster
enp4s0/enp4s0d1 downstream toward N9K
```
This design is:
```text id="c1c9so"
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:
```bash id="o4uyiz"
sudo nano /etc/linuxptp/ptp4l-upstream-client.conf
```
```conf id="fxd4o4"
[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:
```bash id="zhy8l3"
sudo nano /etc/linuxptp/ptp4l-downstream-server.conf
```
```conf id="qqo3eb"
[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:
```bash id="l54yfe"
sudo nano /etc/systemd/system/ptp4l-upstream-client.service
```
```ini id="1pnwq3"
[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 servers own Linux system clock**.
Create:
```bash id="r430d0"
sudo nano /etc/systemd/system/phc2sys-upstream-to-system.service
```
```ini id="eplzh9"
[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:
```bash id="ha7hlv"
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:
```bash id="m3hpvj"
sudo nano /etc/systemd/system/phc2sys-system-to-downstream.service
```
```ini id="j9tgaw"
[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:
```bash id="tlsjdk"
sudo nano /etc/systemd/system/phc2sys-system-to-downstream-d1.service
```
```ini id="70k638"
[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:
```bash id="nl7f0c"
sudo nano /etc/systemd/system/ptp4l-downstream-server.service
```
```ini id="46l106"
[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
```bash id="ze5i6s"
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:
```bash id="e1i9bw"
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:
```bash id="zzbz88"
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
```bash id="j1o8oo"
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:
```bash id="s3klj9"
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:
```text id="a8sadn"
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:
```bash id="n0wowv"
pgrep -a ptp4l
pgrep -a phc2sys
```