```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 ```