295 lines
7.0 KiB
Markdown
295 lines
7.0 KiB
Markdown
```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 server’s 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
|
||
```
|