diff --git a/.gitignore b/.gitignore index fe3d107..f1e68d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -SOURCES/clknetsim-5d1dc0.tar.gz -SOURCES/linuxptp-4.2.tgz -SOURCES/linuxptp-testsuite-bf8ead.tar.gz +clknetsim-64df92.tar.gz +linuxptp-4.4.tgz +linuxptp-testsuite-d27dbd.tar.gz diff --git a/SOURCES/linuxptp-deprecated.patch b/SOURCES/linuxptp-deprecated.patch deleted file mode 100644 index ae3e4c1..0000000 --- a/SOURCES/linuxptp-deprecated.patch +++ /dev/null @@ -1,23 +0,0 @@ -commit 99603cf0ab2413d59ae91101429b18d9ced6f88f -Author: Miroslav Lichvar -Date: Thu Jan 11 11:29:34 2024 +0100 - - config: Disable warnings about deprecated options. - - Signed-off-by: Miroslav Lichvar - -diff --git a/config.c b/config.c -index ad675c8..398b420 100644 ---- a/config.c -+++ b/config.c -@@ -750,8 +750,10 @@ static void check_deprecated_options(const char **option) - } - - if (new_option) { -+#if 0 - fprintf(stderr, "option %s is deprecated, please use %s instead\n", - *option, new_option); -+#endif - *option = new_option; - } - } diff --git a/SOURCES/linuxptp-lstab.patch b/SOURCES/linuxptp-lstab.patch deleted file mode 100644 index b5c5465..0000000 --- a/SOURCES/linuxptp-lstab.patch +++ /dev/null @@ -1,75 +0,0 @@ -commit bbfaa1e253b889aeea97702bbbc87e731e0caf87 -Author: Miroslav Lichvar -Date: Thu Feb 22 13:51:59 2024 +0100 - - lstab: Limit number of parsed leap seconds. - - The lstab structure has a fixed-size array for leap seconds - (currently 28 + 200). Don't read more leap seconds from the leapfile to - avoid corrupting memory. - - Signed-off-by: Miroslav Lichvar - -diff --git a/lstab.c b/lstab.c -index 24add26..8e35504 100644 ---- a/lstab.c -+++ b/lstab.c -@@ -137,7 +137,7 @@ static int lstab_read(struct lstab *lstab, const char *name) - fprintf(stderr, "failed to open '%s' for reading: %m\n", name); - return -1; - } -- while (1) { -+ while (index < N_LEAPS) { - if (!fgets(buf, sizeof(buf), fp)) { - break; - } - -commit 90ad2efc74b0f348fb6b417565b3ada7d161641b -Author: Miroslav Lichvar -Date: Thu Feb 22 13:56:53 2024 +0100 - - lstab: Don't free lstab on update. - - The modification timestamp of the leapfile is checked with every - call of lstab_utc2tai(). If the file is modified, the provided lstab - structure is freed and a new one is allocated from the updated leapfile. - But the new lstab is not returned to the caller as the function doesn't - accept a pointer to the pointer to lstab. This causes reading from the - freed memory and leak of the newly allocated memory. - - Modify update_leapsecond_table() to read the updated leapfile into the - existing lstab structure instead of the reallocation. - - Signed-off-by: Miroslav Lichvar - -diff --git a/lstab.c b/lstab.c -index 8e35504..357ed27 100644 ---- a/lstab.c -+++ b/lstab.c -@@ -195,7 +195,6 @@ struct lstab *lstab_create(const char *filename) - - int update_leapsecond_table(struct lstab *lstab) - { -- const char* leapfile; - struct stat statbuf; - int err; - -@@ -212,14 +211,14 @@ int update_leapsecond_table(struct lstab *lstab) - return 0; - } - printf("updating leap seconds file\n"); -- leapfile = lstab->leapfile; -- lstab_destroy(lstab); - -- lstab = lstab_create(leapfile); -- if (!lstab) { -+ if (lstab_read(lstab, lstab->leapfile)) { -+ lstab->length = 0; - return -1; - } - -+ lstab->lsfile_mtime = statbuf.st_mtim.tv_sec; -+ - return 0; - } - diff --git a/SOURCES/linuxptp-nmeadelay.patch b/SOURCES/linuxptp-nmeadelay.patch deleted file mode 100644 index b06c7c1..0000000 --- a/SOURCES/linuxptp-nmeadelay.patch +++ /dev/null @@ -1,29 +0,0 @@ -commit 0404c1924254c9162222dd5000a140165d21250c -Author: Miroslav Lichvar -Date: Thu Jan 25 15:23:44 2024 +0100 - - ts2phc: Fix offset for NMEA delays over 0.5 seconds. - - The current code of ts2phc assumes that the NMEA RMC message is received - within 0.5 seconds of the pulse the timestamp in the message is refering - to. However, with most receivers NMEA messages are referenced to the - previous pulse. This causes a 1-second error in the measured offset for - receivers with delays over 0.5 seconds. - - Add a 0.5 second correction to map the whole interval between pulses to - the preceding pulse. - - Signed-off-by: Miroslav Lichvar - -diff --git a/ts2phc_nmea_pps_source.c b/ts2phc_nmea_pps_source.c -index 3a4267d..274b70a 100644 ---- a/ts2phc_nmea_pps_source.c -+++ b/ts2phc_nmea_pps_source.c -@@ -191,6 +191,7 @@ static int ts2phc_nmea_pps_source_getppstime(struct ts2phc_pps_source *src, - return -1; - } - rmc = tmv_add(rmc, duration_since_rmc); -+ rmc = tmv_add(rmc, nanoseconds_to_tmv(500000000)); - utc_time = tmv_to_nanoseconds(rmc); - utc_time /= (int64_t) 1000000000; - *ts = tmv_to_timespec(rmc); diff --git a/SOURCES/linuxptp-ptpver.patch b/SOURCES/linuxptp-ptpver.patch deleted file mode 100644 index ca7bad7..0000000 --- a/SOURCES/linuxptp-ptpver.patch +++ /dev/null @@ -1,60 +0,0 @@ -commit 6e480c9572925a4ea8aac45a10a306e0c4e509a9 -Author: Miroslav Lichvar -Date: Thu Jan 11 11:33:54 2024 +0100 - - Revert default PTP version to 2.0 for better compatibility. - - Signed-off-by: Miroslav Lichvar - -diff --git a/config.c b/config.c -index 398b420..d7775c0 100644 ---- a/config.c -+++ b/config.c -@@ -319,7 +319,7 @@ struct config_item config_tab[] = { - GLOB_ITEM_STR("productDescription", ";;"), - PORT_ITEM_STR("ptp_dst_mac", "01:1B:19:00:00:00"), - PORT_ITEM_STR("p2p_dst_mac", "01:80:C2:00:00:0E"), -- GLOB_ITEM_INT("ptp_minor_version", 1, 0, 1), -+ GLOB_ITEM_INT("ptp_minor_version", 0, 0, 1), - GLOB_ITEM_STR("refclock_sock_address", "/var/run/refclock.ptp.sock"), - GLOB_ITEM_STR("revisionData", ";;"), - GLOB_ITEM_INT("sanity_freq_limit", 200000000, 0, INT_MAX), -diff --git a/configs/default.cfg b/configs/default.cfg -index 0c7661c..8f94c16 100644 ---- a/configs/default.cfg -+++ b/configs/default.cfg -@@ -46,7 +46,7 @@ power_profile.2011.networkTimeInaccuracy -1 - power_profile.2017.totalTimeInaccuracy -1 - power_profile.grandmasterID 0 - power_profile.version none --ptp_minor_version 1 -+ptp_minor_version 0 - # - # Run time options - # -diff --git a/msg.h b/msg.h -index 9c80f45..786ddc7 100644 ---- a/msg.h -+++ b/msg.h -@@ -32,7 +32,7 @@ - - /* Version definition for IEEE 1588-2019 */ - #define PTP_MAJOR_VERSION 2 --#define PTP_MINOR_VERSION 1 -+#define PTP_MINOR_VERSION 0 - #define PTP_VERSION (PTP_MINOR_VERSION << 4 | PTP_MAJOR_VERSION) - - #define MAJOR_VERSION_MASK 0x0f -diff --git a/ptp4l.8 b/ptp4l.8 -index 4cb9adb..c59b0b4 100644 ---- a/ptp4l.8 -+++ b/ptp4l.8 -@@ -813,7 +813,7 @@ The default is 128. - .TP - .B ptp_minor_version - This option sets the minorVersionPTP in the common PTP message header. --The default is 1. -+The default (specific to the installed linuxptp package) is 0. - - .TP - .B refclock_sock_address diff --git a/SOURCES/linuxptp-subscribe.patch b/SOURCES/linuxptp-subscribe.patch deleted file mode 100644 index 2bdf033..0000000 --- a/SOURCES/linuxptp-subscribe.patch +++ /dev/null @@ -1,26 +0,0 @@ -commit b421a4c66ce636adff150dd1aa8eafa981c2693d -Author: Miroslav Lichvar -Date: Wed Jan 3 14:45:51 2024 +0100 - - pmc: Allow missing values in SUBSCRIBE_EVENTS_NP command. - - Don't require all supported notifications to be specified in the command - for compatibility with older scripts. - - Signed-off-by: Miroslav Lichvar - -diff --git a/pmc_common.c b/pmc_common.c -index 62e34a6..b88cfc2 100644 ---- a/pmc_common.c -+++ b/pmc_common.c -@@ -310,8 +310,8 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str) - onoff_port_state, - onoff_time_status, - onoff_parent_data_set); -- if (cnt != 4) { -- fprintf(stderr, "%s SET needs 4 values\n", -+ if (cnt < 2) { -+ fprintf(stderr, "%s SET needs at least 2 values\n", - idtab[index].name); - break; - } diff --git a/SOURCES/phc2sys.service b/SOURCES/phc2sys.service deleted file mode 100644 index ff2f77e..0000000 --- a/SOURCES/phc2sys.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=Synchronize system clock or PTP hardware clock (PHC) -After=ntpdate.service ptp4l.service - -[Service] -Type=simple -EnvironmentFile=-/etc/sysconfig/phc2sys -ExecStart=/usr/sbin/phc2sys $OPTIONS - -[Install] -WantedBy=multi-user.target diff --git a/SOURCES/ptp4l.service b/SOURCES/ptp4l.service deleted file mode 100644 index fbb26d1..0000000 --- a/SOURCES/ptp4l.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Precision Time Protocol (PTP) service -After=network-online.target -Wants=network-online.target - -[Service] -Type=simple -EnvironmentFile=-/etc/sysconfig/ptp4l -ExecStart=/usr/sbin/ptp4l $OPTIONS - -[Install] -WantedBy=multi-user.target diff --git a/SOURCES/timemaster.service b/SOURCES/timemaster.service deleted file mode 100644 index a6bda33..0000000 --- a/SOURCES/timemaster.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Synchronize system clock to NTP and PTP time sources -After=chronyd.service ntpd.service ntpdate.service sntp.service network-online.target -Conflicts=chronyd.service ntpd.service phc2sys.service ptp4l.service -Wants=network-online.target - -[Service] -Type=simple -ExecStart=/usr/sbin/timemaster -f /etc/timemaster.conf - -[Install] -WantedBy=multi-user.target diff --git a/SPECS/linuxptp.spec b/SPECS/linuxptp.spec deleted file mode 100644 index f0229ed..0000000 --- a/SPECS/linuxptp.spec +++ /dev/null @@ -1,255 +0,0 @@ -%global _hardened_build 1 -%global testsuite_ver bf8ead -%global clknetsim_ver 5d1dc0 - -Name: linuxptp -Version: 4.2 -Release: 1%{?dist} -Summary: PTP implementation for Linux - -Group: System Environment/Base -License: GPLv2+ -URL: http://linuxptp.sourceforge.net/ - -Source0: https://downloads.sourceforge.net/%{name}/%{name}-%{version}.tgz -Source1: phc2sys.service -Source2: ptp4l.service -Source3: timemaster.service -Source4: timemaster.conf -# external test suite -Source10: https://github.com/mlichvar/linuxptp-testsuite/archive/%{testsuite_ver}/linuxptp-testsuite-%{testsuite_ver}.tar.gz -# simulator for test suite -Source11: https://github.com/mlichvar/clknetsim/archive/%{clknetsim_ver}/clknetsim-%{clknetsim_ver}.tar.gz - -# allow old syntax of SET SUBSCRIBE_EVENTS_NP command -Patch1: linuxptp-subscribe.patch -# disable warning messages about deprecated options -Patch2: linuxptp-deprecated.patch -# revert default PTP version to 2.0 for better compatibility -Patch3: linuxptp-ptpver.patch -# limit unicast message rate per address and grant duration -Patch4: linuxptp-ucastrate.patch -# fix ts2phc to handle large NMEA delay -Patch5: linuxptp-nmeadelay.patch -# fix loading and reloading of leapfile -Patch6: linuxptp-lstab.patch - -BuildRequires: kernel-headers > 4.18.0-87 -BuildRequires: systemd - -%{?systemd_requires} - -%description -This software is an implementation of the Precision Time Protocol (PTP) -according to IEEE standard 1588 for Linux. The dual design goals are to provide -a robust implementation of the standard and to use the most relevant and modern -Application Programming Interfaces (API) offered by the Linux kernel. -Supporting legacy APIs and other platforms is not a goal. - -%prep -%setup -q -a 10 -a 11 -n %{name}-%{!?gitfullver:%{version}}%{?gitfullver} -%autopatch -p1 -mv linuxptp-testsuite-%{testsuite_ver}* testsuite -mv clknetsim-%{clknetsim_ver}* testsuite/clknetsim - -%build -make %{?_smp_mflags} \ - EXTRA_CFLAGS="$RPM_OPT_FLAGS" \ - EXTRA_LDFLAGS="$RPM_LD_FLAGS" - -%install -%makeinstall - -mkdir -p $RPM_BUILD_ROOT{%{_sysconfdir}/sysconfig,%{_unitdir},%{_mandir}/man5} -install -m 644 -p configs/default.cfg $RPM_BUILD_ROOT%{_sysconfdir}/ptp4l.conf -install -m 644 -p %{SOURCE1} %{SOURCE2} %{SOURCE3} $RPM_BUILD_ROOT%{_unitdir} -install -m 644 -p %{SOURCE4} $RPM_BUILD_ROOT%{_sysconfdir} - -echo 'OPTIONS="-f /etc/ptp4l.conf -i eth0"' > \ - $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/ptp4l -echo 'OPTIONS="-a -r"' > $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/phc2sys - -echo '.so man8/ptp4l.8' > $RPM_BUILD_ROOT%{_mandir}/man5/ptp4l.conf.5 -echo '.so man8/timemaster.8' > $RPM_BUILD_ROOT%{_mandir}/man5/timemaster.conf.5 - -# Remove patch backup files and non-linuxptp configuration -find configs -type f ! -name '*.cfg' -delete - -%check -cd testsuite -# set random seed to get deterministic results -export CLKNETSIM_RANDOM_SEED=26743 -make %{?_smp_mflags} -C clknetsim -PATH=..:$PATH ./run - -%post -%systemd_post phc2sys.service ptp4l.service timemaster.service - -%preun -%systemd_preun phc2sys.service ptp4l.service timemaster.service - -%postun -%systemd_postun_with_restart phc2sys.service ptp4l.service timemaster.service - -%files -%doc COPYING README.org configs -%config(noreplace) %{_sysconfdir}/ptp4l.conf -%config(noreplace) %{_sysconfdir}/sysconfig/phc2sys -%config(noreplace) %{_sysconfdir}/sysconfig/ptp4l -%config(noreplace) %{_sysconfdir}/timemaster.conf -%{_unitdir}/phc2sys.service -%{_unitdir}/ptp4l.service -%{_unitdir}/timemaster.service -%{_sbindir}/hwstamp_ctl -%{_sbindir}/nsm -%{_sbindir}/phc2sys -%{_sbindir}/phc_ctl -%{_sbindir}/pmc -%{_sbindir}/ptp4l -%{_sbindir}/timemaster -%{_sbindir}/ts2phc -%{_sbindir}/tz2alt -%{_mandir}/man5/*.5* -%{_mandir}/man8/*.8* - -%changelog -* Thu Feb 22 2024 Miroslav Lichvar 4.2-1 -- update to 4.2 (RHEL-21326 RHEL-21328 RHEL-21329) -- fix ts2phc to handle large NMEA delay (RHEL-23278) -- fix loading and reloading of leapfile - -* Wed May 03 2023 Miroslav Lichvar 3.1.1-6 -- clear pending errors on sockets (#2192560) - -* Wed Apr 12 2023 Miroslav Lichvar 3.1.1-5 -- handle EINTR when waiting for transmit timestamp (#2123224) - -* Mon Mar 20 2023 Miroslav Lichvar 3.1.1-4 -- don't re-arm fault clearing timer on unrelated netlink events (#2174900) - -* Wed Jun 29 2022 Miroslav Lichvar 3.1.1-3 -- handle PHC read failing with EBUSY in phc2sys (#2079129) - -* Mon Nov 01 2021 Miroslav Lichvar 3.1.1-2 -- make sanity clock check more reliable (#2007281) - -* Mon Jul 26 2021 Miroslav Lichvar 3.1.1-1 -- update to 3.1.1 (#1895005 CVE-2021-3571) -- add read-only UDS port (#1929797) -- add option to set clockClass threshold (#1980386) -- don't repeat some log messages in multi-port configuration (#1980377) -- increase default TX timestamp timeout to 10 ms (#1977136) - -* Thu Jun 24 2021 Miroslav Lichvar 2.0-5.el8_4.1 -- validate length of forwarded messages (CVE-2021-3570) - -* Mon Apr 27 2020 Miroslav Lichvar 2.0-5 -- fix sample timestamps when synchronizing PHC to system clock (#1787376) -- fix handling of zero-length messages (#1827275) - -* Thu May 16 2019 Miroslav Lichvar 2.0-4 -- rebuild with enabled gating (#1680888) - -* Wed May 15 2019 Miroslav Lichvar 2.0-3 -- add support for active-backup team interface (#1685467) -- add support for more accurate synchronization to phc2sys (#1677217) -- add hwts_filter option to ptp4l (#1708554) -- limit unicast message rate per address and grant duration (#1707395) -- fix comparing of unicast addresses (#1707395) -- fix building with new kernel headers (#1707395) -- update testsuite (#1707395) -- don't leak memory when allocation fails (#1707395) - -* Tue Nov 13 2018 Miroslav Lichvar 2.0-2 -- start ptp4l, timemaster and phc2sys after network-online target (#1632282) - -* Mon Aug 13 2018 Miroslav Lichvar 2.0-1 -- update to 2.0 (#1614300) - -* Mon Apr 09 2018 Miroslav Lichvar 1.9.2-1 -- update to 1.9.2 - -* Wed Feb 07 2018 Fedora Release Engineering - 1.8-7.20180101git303b08 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild - -* Tue Jan 30 2018 Miroslav Lichvar 1.8-6.20180101git303b08 -- use macro for systemd scriptlet dependencies - -* Thu Jan 11 2018 Miroslav Lichvar 1.8-5.20180101git303b08 -- update to 20180101git303b08 - -* Thu Aug 03 2017 Fedora Release Engineering - 1.8-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild - -* Wed Jul 26 2017 Fedora Release Engineering - 1.8-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild - -* Fri Feb 10 2017 Fedora Release Engineering - 1.8-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild - -* Mon Nov 07 2016 Miroslav Lichvar 1.8-1 -- update to 1.8 - -* Fri Jul 22 2016 Miroslav Lichvar 1.7-1 -- update to 1.7 -- add delay option to default timemaster.conf - -* Thu Feb 04 2016 Fedora Release Engineering - 1.6-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild - -* Tue Sep 22 2015 Miroslav Lichvar 1.6-1 -- update to 1.6 -- set random seed in testing to get deterministic results -- remove trailing whitespace in default timemaster.conf - -* Wed Jun 17 2015 Fedora Release Engineering - 1.5-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild - -* Mon Jan 05 2015 Miroslav Lichvar 1.5-1 -- update to 1.5 - -* Sun Aug 17 2014 Fedora Release Engineering - 1.4-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild - -* Sat Jun 07 2014 Fedora Release Engineering - 1.4-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild - -* Fri Feb 21 2014 Miroslav Lichvar 1.4-1 -- update to 1.4 -- replace hardening build flags with _hardened_build -- include test suite - -* Fri Aug 02 2013 Miroslav Lichvar 1.3-1 -- update to 1.3 - -* Tue Jul 30 2013 Miroslav Lichvar 1.2-3.20130730git7789f0 -- update to 20130730git7789f0 - -* Fri Jul 19 2013 Miroslav Lichvar 1.2-2.20130719git46db40 -- update to 20130719git46db40 -- drop old systemd scriptlets -- add man page link for ptp4l.conf - -* Mon Apr 22 2013 Miroslav Lichvar 1.2-1 -- update to 1.2 - -* Mon Feb 18 2013 Miroslav Lichvar 1.1-1 -- update to 1.1 -- log phc2sys output - -* Thu Feb 14 2013 Fedora Release Engineering - 1.0-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild - -* Thu Dec 13 2012 Miroslav Lichvar 1.0-1 -- update to 1.0 - -* Fri Nov 09 2012 Miroslav Lichvar 0-0.3.20121109git4e8107 -- update to 20121109git4e8107 -- install unchanged default.cfg as ptp4l.conf -- drop conflicts from phc2sys service - -* Fri Sep 21 2012 Miroslav Lichvar 0-0.2.20120920git6ce135 -- fix issues found in package review (#859193) - -* Thu Sep 20 2012 Miroslav Lichvar 0-0.1.20120920git6ce135 -- initial release diff --git a/linuxptp-externalgm.patch b/linuxptp-externalgm.patch new file mode 100644 index 0000000..938310d --- /dev/null +++ b/linuxptp-externalgm.patch @@ -0,0 +1,275 @@ +commit 120e46985e5176bc908866b76ef5be6c9abf00be +Author: Miroslav Lichvar +Date: Thu Jan 16 15:04:04 2025 +0100 + + clock: Add variables for external grandmaster. + + When ptp4l is configured to run as the server part of a bridge between + different domains, or a boundary clock split into multiple instances + (using one or two clocks), it announces its own clock identity as + grandmasterIdentity and stepsRemoved of 0. The clients of the server + don't see the true identity and distance, which can impact the result of + BMCA if there are multiple bridges/paths to the grandmaster. In the + worst case it could cause synchronization loops. + + Add new variables to the clock that will override the grandmaster + identity and stepsRemoved values included in announce messages to make + it possible to pass them from the source domain as if the bridge/BC was + a single PTP instance. The variables will be used only when in the + grandmaster state and when not zero. + + Runtime configuration over the UDS port will follow. + + Signed-off-by: Miroslav Lichvar + +diff --git a/clock.c b/clock.c +index 863e9d8..fb33ac0 100644 +--- a/clock.c ++++ b/clock.c +@@ -148,6 +148,8 @@ struct clock { + int step_window_counter; + int step_window; + struct time_zone tz[MAX_TIME_ZONES]; ++ struct ClockIdentity ext_gm_identity; ++ int ext_gm_steps_removed; + }; + + struct clock the_clock; +@@ -830,13 +832,22 @@ static int clock_compare_pds(struct parentDS *pds1, struct parentDS *pds2) + static void clock_update_grandmaster(struct clock *c) + { + struct parentDS *pds = &c->dad.pds, old_pds = *pds; ++ struct ClockIdentity gm_identity, nul_identity; ++ ++ memset(&nul_identity, 0, sizeof(nul_identity)); + memset(&c->cur, 0, sizeof(c->cur)); + memset(c->ptl, 0, sizeof(c->ptl)); + ++ if (!cid_eq(&nul_identity, &c->ext_gm_identity)) ++ gm_identity = c->ext_gm_identity; ++ else ++ gm_identity = c->dds.clockIdentity; ++ ++ c->cur.stepsRemoved = c->ext_gm_steps_removed; + pds->parentPortIdentity.clockIdentity = c->dds.clockIdentity; + /* Follow IEEE 1588 Table 30: Updates for state decision code M1 and M2 */ + pds->parentPortIdentity.portNumber = 0; +- pds->grandmasterIdentity = c->dds.clockIdentity; ++ pds->grandmasterIdentity = gm_identity; + pds->grandmasterClockQuality = c->dds.clockQuality; + pds->grandmasterPriority1 = c->dds.priority1; + pds->grandmasterPriority2 = c->dds.priority2; + +commit dfd52bff9d1b25b291aae6343154b38fb8fede4e +Author: Miroslav Lichvar +Date: Thu Jan 16 15:04:05 2025 +0100 + + Add management message for external grandmaster properties. + + Add EXTERNAL_GRANDMASTER_PROPERTIES_NP management message to get and set + the new external grandmasterIdentity and stepsRemoved variables of the + clock. Together with the GRANDMASTER_SETTINGS_NP message all + grandmaster-specific values in announce messages can be now set. + + Signed-off-by: Miroslav Lichvar + +diff --git a/clock.c b/clock.c +index fb33ac0..7c30066 100644 +--- a/clock.c ++++ b/clock.c +@@ -422,6 +422,7 @@ static int clock_management_fill_response(struct clock *c, struct port *p, + struct ptp_message *req, + struct ptp_message *rsp, int id) + { ++ struct external_grandmaster_properties_np *egpn; + struct alternate_time_offset_properties *atop; + struct alternate_time_offset_name *aton; + struct grandmaster_settings_np *gsn; +@@ -582,6 +583,12 @@ static int clock_management_fill_response(struct clock *c, struct port *p, + mtd->val = c->local_sync_uncertain; + datalen = sizeof(*mtd); + break; ++ case MID_EXTERNAL_GRANDMASTER_PROPERTIES_NP: ++ egpn = (struct external_grandmaster_properties_np *) tlv->data; ++ egpn->gmIdentity = c->ext_gm_identity; ++ egpn->stepsRemoved = c->ext_gm_steps_removed; ++ datalen = sizeof(*egpn); ++ break; + default: + /* The caller should *not* respond to this message. */ + tlv_extra_recycle(extra); +@@ -620,6 +627,7 @@ static int clock_management_get_response(struct clock *c, struct port *p, + static int clock_management_set(struct clock *c, struct port *p, + int id, struct ptp_message *req, int *changed) + { ++ struct external_grandmaster_properties_np *egpn; + struct alternate_time_offset_properties *atop; + struct alternate_time_offset_name *aton; + struct grandmaster_settings_np *gsn; +@@ -710,6 +718,13 @@ static int clock_management_set(struct clock *c, struct port *p, + break; + } + break; ++ case MID_EXTERNAL_GRANDMASTER_PROPERTIES_NP: ++ egpn = (struct external_grandmaster_properties_np *) tlv->data; ++ c->ext_gm_identity = egpn->gmIdentity; ++ c->ext_gm_steps_removed = egpn->stepsRemoved; ++ *changed = 1; ++ respond = 1; ++ break; + } + if (respond && !clock_management_get_response(c, p, id, req)) + pr_err("failed to send management set response"); +diff --git a/pmc.c b/pmc.c +index 0b61da4..6a6a94e 100644 +--- a/pmc.c ++++ b/pmc.c +@@ -158,6 +158,7 @@ static void pmc_show_signaling(struct ptp_message *msg, FILE *fp) + + static void pmc_show(struct ptp_message *msg, FILE *fp) + { ++ struct external_grandmaster_properties_np *egpn; + struct alternate_time_offset_properties *atop; + struct alternate_time_offset_name *aton; + struct ieee_c37_238_settings_np *pwr; +@@ -475,6 +476,14 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) + fprintf(fp, "SYNCHRONIZATION_UNCERTAIN_NP " + IFMT "uncertain %hhu", mtd->val); + break; ++ case MID_EXTERNAL_GRANDMASTER_PROPERTIES_NP: ++ egpn = (struct external_grandmaster_properties_np *) mgt->data; ++ fprintf(fp, "EXTERNAL_GRANDMASTER_PROPERTIES_NP " ++ IFMT "gmIdentity %s" ++ IFMT "stepsRemoved %hu", ++ cid2str(&egpn->gmIdentity), ++ egpn->stepsRemoved); ++ break; + case MID_PORT_DATA_SET: + p = (struct portDS *) mgt->data; + if (p->portState > PS_SLAVE) { +diff --git a/pmc_common.c b/pmc_common.c +index 7c77a10..b55e7ec 100644 +--- a/pmc_common.c ++++ b/pmc_common.c +@@ -132,6 +132,7 @@ struct management_id idtab[] = { + { "GRANDMASTER_SETTINGS_NP", MID_GRANDMASTER_SETTINGS_NP, do_set_action }, + { "SUBSCRIBE_EVENTS_NP", MID_SUBSCRIBE_EVENTS_NP, do_set_action }, + { "SYNCHRONIZATION_UNCERTAIN_NP", MID_SYNCHRONIZATION_UNCERTAIN_NP, do_set_action }, ++ { "EXTERNAL_GRANDMASTER_PROPERTIES_NP", MID_EXTERNAL_GRANDMASTER_PROPERTIES_NP, do_set_action }, + /* Port management ID values */ + { "NULL_MANAGEMENT", MID_NULL_MANAGEMENT, null_management }, + { "CLOCK_DESCRIPTION", MID_CLOCK_DESCRIPTION, do_get_action }, +@@ -172,6 +173,7 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str) + { + int cnt, code = idtab[index].code, freq_traceable, leap_59, leap_61, + ptp_timescale, time_traceable, utc_off_valid; ++ struct external_grandmaster_properties_np egpn; + struct alternate_time_offset_properties atop; + struct ieee_c37_238_settings_np pwr; + struct grandmaster_settings_np gsn; +@@ -183,6 +185,7 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str) + char onoff_parent_data_set[4] = "off"; + char onoff_cmlds[4] = "off"; + char display_name[11] = {0}; ++ char identity[19]; + uint64_t jump; + uint8_t key; + int enable; +@@ -400,6 +403,19 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str) + IEEE_C37_238_VERSION_2017); + } + break; ++ case MID_EXTERNAL_GRANDMASTER_PROPERTIES_NP: ++ cnt = sscanf(str, " %*s %*s " ++ "gmIdentity %18s " ++ "stepsRemoved %hu ", ++ identity, ++ &egpn.stepsRemoved); ++ if (cnt != 2 || str2cid(identity, &egpn.gmIdentity)) { ++ fprintf(stderr, "%s SET needs 2 values\n", ++ idtab[index].name); ++ break; ++ } ++ pmc_send_set_action(pmc, code, &egpn, sizeof(egpn)); ++ break; + } + } + +@@ -704,6 +720,9 @@ static int pmc_tlv_datalen(struct pmc *pmc, int id) + case MID_POWER_PROFILE_SETTINGS_NP: + len += sizeof(struct ieee_c37_238_settings_np); + break; ++ case MID_EXTERNAL_GRANDMASTER_PROPERTIES_NP: ++ len += sizeof(struct external_grandmaster_properties_np); ++ break; + case MID_LOG_ANNOUNCE_INTERVAL: + case MID_ANNOUNCE_RECEIPT_TIMEOUT: + case MID_LOG_SYNC_INTERVAL: +diff --git a/tlv.c b/tlv.c +index b22277c..0639a71 100644 +--- a/tlv.c ++++ b/tlv.c +@@ -164,6 +164,7 @@ static void alttime_offset_pre_send(struct tlv_extra *extra) + static int mgt_post_recv(struct management_tlv *m, uint16_t data_len, + struct tlv_extra *extra) + { ++ struct external_grandmaster_properties_np *egpn; + struct alternate_time_offset_properties *atop; + struct alternate_time_offset_name *aton; + struct ieee_c37_238_settings_np *pwr; +@@ -490,6 +491,12 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len, + NTOHL(cmlds->scaledNeighborRateRatio); + NTOHL(cmlds->as_capable); + break; ++ case MID_EXTERNAL_GRANDMASTER_PROPERTIES_NP: ++ if (data_len != sizeof(struct external_grandmaster_properties_np)) ++ goto bad_length; ++ egpn = (struct external_grandmaster_properties_np *) m->data; ++ NTOHS(egpn->stepsRemoved); ++ break; + case MID_SAVE_IN_NON_VOLATILE_STORAGE: + case MID_RESET_NON_VOLATILE_STORAGE: + case MID_INITIALIZE: +@@ -513,6 +520,7 @@ bad_length: + + static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra) + { ++ struct external_grandmaster_properties_np *egpn; + struct alternate_time_offset_properties *atop; + struct ieee_c37_238_settings_np *pwr; + struct unicast_master_table_np *umtn; +@@ -688,6 +696,10 @@ static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra) + HTONL(cmlds->scaledNeighborRateRatio); + HTONL(cmlds->as_capable); + break; ++ case MID_EXTERNAL_GRANDMASTER_PROPERTIES_NP: ++ egpn = (struct external_grandmaster_properties_np *)m->data; ++ HTONS(egpn->stepsRemoved); ++ break; + } + } + +diff --git a/tlv.h b/tlv.h +index 1b464f3..f0c47ce 100644 +--- a/tlv.h ++++ b/tlv.h +@@ -100,6 +100,7 @@ enum management_action { + #define MID_GRANDMASTER_SETTINGS_NP 0xC001 + #define MID_SUBSCRIBE_EVENTS_NP 0xC003 + #define MID_SYNCHRONIZATION_UNCERTAIN_NP 0xC006 ++#define MID_EXTERNAL_GRANDMASTER_PROPERTIES_NP 0xC00D + + /* Port management ID values */ + #define MID_NULL_MANAGEMENT 0x0000 +@@ -489,6 +490,11 @@ struct msg_interface_rate_tlv { + UInteger16 numberOfBitsAfterTimestamp; + } PACKED; + ++struct external_grandmaster_properties_np { ++ struct ClockIdentity gmIdentity; ++ UInteger16 stepsRemoved; ++} PACKED; ++ + /** + * Allocates a new tlv_extra structure. + * @return Pointer to a new structure on success or NULL otherwise. diff --git a/linuxptp-externalpps.patch b/linuxptp-externalpps.patch new file mode 100644 index 0000000..b8f1cb8 --- /dev/null +++ b/linuxptp-externalpps.patch @@ -0,0 +1,149 @@ +commit f20e568cb2bf3b0ea6105e5624409f02fb9aa2bc +Author: Miroslav Lichvar +Date: Thu Jan 9 15:46:05 2025 +0100 + + ts2phc: Add option for external reference in automatic mode. + + ts2phc running in the automatic mode assumes that the PPS source is one + of the PHCs used by ptp4l. That doesn't always have to be the case. Add + "external_pps" option to use the non-automatic-mode reading of the + source timestamp and don't mark sink clocks as targets if they are + synchronized by ptp4l. + + The use case is holdover with an externally controlled stabilized clock. + The clock is synchronized by an external process to the PHC when it's + synchronized by ptp4l and the PHC is synchronized to the external clock + by ts2phc when not synchronized by ptp4l. Multiple PHCs can be connected + to the external clock to make a JBOD boundary clock. + + Don't require the PHC that is synchronized by ptp4l to be receiving the + PPS signal (providing timestamps) to make it possible to switch the PPS + direction to synchronize the external clock if there is only one + usable channel. + + (This is a RHEL-specific downstream patch using "ts2phc.rh_external_pps" + name for the option to make it clear it's considered experimental.) + + Signed-off-by: Miroslav Lichvar + +diff --git a/config.c b/config.c +index cbff976..fedc3a0 100644 +--- a/config.c ++++ b/config.c +@@ -368,6 +368,7 @@ struct config_item config_tab[] = { + GLOB_ITEM_ENU("time_stamping", TS_HARDWARE, timestamping_enu), + PORT_ITEM_INT("transportSpecific", 0, 0, 0x0F), + PORT_ITEM_INT("ts2phc.channel", 0, 0, INT_MAX), ++ GLOB_ITEM_INT("ts2phc.rh_external_pps", 0, 0, 1), + PORT_ITEM_INT("ts2phc.extts_correction", 0, INT_MIN, INT_MAX), + PORT_ITEM_ENU("ts2phc.extts_polarity", PTP_RISING_EDGE, extts_polarity_enu), + PORT_ITEM_INT("ts2phc.holdover", 0, 0, INT_MAX), +diff --git a/ts2phc.8 b/ts2phc.8 +index f17ed71..d57402c 100644 +--- a/ts2phc.8 ++++ b/ts2phc.8 +@@ -287,6 +287,20 @@ the SERVO_LOCKED_STABLE state. The servo state needs be enabled by the + \fB-a\fP option and when \fBts2phc.extts_polarity\fP is set to \fIboth\fP. + The default is 0 (disabled). + ++.TP ++.B ts2phc.rh_external_pps ++This is a RHEL-specific experimental option which can be renamed, ++removed, or the functionality changed, in a future minor update. ++ ++It enables an external reference with the \fB-a\fP option. If set to 1, ts2phc ++will assume the source of the PPS signal is a different clock from the PHCs ++used by ptp4l (configured with the \fBboundary_clock_jbod\fP option). The use ++case is a holdover using an externally controlled stabilized clock, which is ++expected to be synchronized to the PHC that is synchronized by ptp4l, and ++running free when ptp4l is not synchronizing any of the PHCs. Note that it is a ++different holdover than the one enabled by the \fBts2phc.holdover\fP option ++below. The default is 0 (disabled). ++ + .TP + .B ts2phc.nmea_delay + Specifies the minimum expected delay of NMEA RMC messages in nanoseconds. +diff --git a/ts2phc.c b/ts2phc.c +index 39d31b6..5448496 100644 +--- a/ts2phc.c ++++ b/ts2phc.c +@@ -348,18 +348,26 @@ static void ts2phc_reconfigure(struct ts2phc_private *priv) + } + num_target_clocks++; + break; +- case PS_UNCALIBRATED: +- num_ref_clocks++; +- break; + case PS_SLAVE: + ref_clk = c; ++ /* Fall through */ ++ case PS_UNCALIBRATED: + num_ref_clocks++; ++ if (priv->external_pps && c->is_target) { ++ pr_info("unselecting %s for synchronization", ++ c->name); ++ c->is_target = false; ++ } + break; + default: + break; + } + last = c; + } ++ if (priv->external_pps) { ++ pr_info("assuming external reference clock"); ++ return; ++ } + if (num_target_clocks >= 1 && !ref_clk) { + priv->ref_clock = last; + priv->ref_clock->is_target = false; +@@ -447,7 +455,7 @@ static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg) + struct ts2phc_clock *c; + int holdover, valid; + +- if (autocfg) { ++ if (autocfg && !priv->external_pps) { + if (!priv->ref_clock) { + pr_debug("no reference clock, skipping"); + return; +@@ -787,6 +795,8 @@ int main(int argc, char *argv[]) + return -1; + } + ++ priv.external_pps = config_get_int(cfg, NULL, "ts2phc.rh_external_pps"); ++ + priv.holdover_length = config_get_int(cfg, NULL, "ts2phc.holdover"); + priv.holdover_start = 0; + +diff --git a/ts2phc.h b/ts2phc.h +index 5dbde9b..63e6122 100644 +--- a/ts2phc.h ++++ b/ts2phc.h +@@ -52,6 +52,7 @@ struct ts2phc_private { + struct config *cfg; + struct pmc_agent *agent; + struct ts2phc_clock *ref_clock; ++ bool external_pps; + bool state_changed; + LIST_HEAD(port_head, ts2phc_port) ports; + LIST_HEAD(clock_head, ts2phc_clock) clocks; +diff --git a/ts2phc_pps_sink.c b/ts2phc_pps_sink.c +index af34e39..9076de9 100644 +--- a/ts2phc_pps_sink.c ++++ b/ts2phc_pps_sink.c +@@ -441,6 +441,15 @@ int ts2phc_pps_sink_poll(struct ts2phc_private *priv) + all_sinks_have_events = true; + + for (i = 0; i < priv->n_sinks; i++) { ++ /* ++ * In the external PPS mode don't require non-target ++ * clocks to be receiving PPS to allow switching the ++ * PPS direction to synchronize the external clock. ++ */ ++ if (priv->external_pps && ++ !polling_array->sink[i]->clock->is_target) ++ continue; ++ + if (!polling_array->collected_events[i]) { + all_sinks_have_events = false; + break; diff --git a/linuxptp-nowait.patch b/linuxptp-nowait.patch new file mode 100644 index 0000000..d62f87d --- /dev/null +++ b/linuxptp-nowait.patch @@ -0,0 +1,150 @@ +commit 2f5dd7261f2fc167ea1c8ef4154888fda0cf7db3 +Author: Miroslav Lichvar +Date: Tue Nov 26 15:10:32 2024 +0100 + + pmc_agent: Use longer update interval when not subscribed. + + When phc2sys is started with the -w option, the pmc agent is not + subscribed to events by the pmc_agent_subscribe() function, which also + sets the update interval. The update interval in this case is zero, + which means the pmc agent is trying to update the currentUtcOffset value + on every call of pmc_agent_update(), i.e. on every clock update in + phc2sys. + + Set a default update interval of 60 seconds to reduce the rate of + pmc requests. + + Fixes: e3ca7ea90a9e ("pmc_agent: Make update interval configurable.") + Signed-off-by: Miroslav Lichvar + Reviewed-by: Jacob Keller + +diff --git a/pmc_agent.c b/pmc_agent.c +index d1a3367..663adc0 100644 +--- a/pmc_agent.c ++++ b/pmc_agent.c +@@ -33,6 +33,9 @@ + #define UPDATES_PER_SUBSCRIPTION 3 + #define MIN_UPDATE_INTERVAL 10 + ++/* Update interval if the agent not subscribed, just polling the UTC offset */ ++#define DEFAULT_UPDATE_INTERVAL 60 ++ + struct pmc_agent { + struct pmc *pmc; + uint64_t pmc_last_update; +@@ -253,6 +256,7 @@ int init_pmc_node(struct config *cfg, struct pmc_agent *node, const char *uds, + } + node->recv_subscribed = recv_subscribed; + node->recv_context = context; ++ node->update_interval = DEFAULT_UPDATE_INTERVAL * NS_PER_SEC; + + return 0; + } + +commit b46f1bda3b13d17a67ffc9d0f9af76e2fc1af80a +Author: Miroslav Lichvar +Date: Tue Nov 26 15:10:33 2024 +0100 + + phc2sys: Don't disable pmc agent with -s -d -w options. + + When phc2sys is started with -s and -d options to combine a PPS device + and PHC device as a time source, but without an offset specified by + the -O option, the pmc agent is disabled after waiting for ptp4l to have + a port in a synchronized state. This prevents phc2sys from following + changes in the currentUtcOffset value. + + Disable the pmc agent only if no PHC device is specified by the -s + option, i.e. there are no PHC readings to which the UTC offset could be + applied. + + Fixes: 5f1b419c4102 ("phc2sys: Replace magical test with a proper test.") + Signed-off-by: Miroslav Lichvar + Reviewed-by: Jacob Keller + +diff --git a/phc2sys.c b/phc2sys.c +index d09cb53..c98ecec 100644 +--- a/phc2sys.c ++++ b/phc2sys.c +@@ -1594,7 +1594,7 @@ int main(int argc, char *argv[]) + + if (domains[0].forced_sync_offset || + !phc2sys_using_systemclock(&domains[0]) || +- hardpps_configured(pps_fd)) { ++ (hardpps_configured(pps_fd) && !src_name)) { + pmc_agent_disable(domains[0].agent); + } + } + +commit 8bd0ee2f65c72fb45f95aca8e907514092fc9cd1 +Author: Miroslav Lichvar +Date: Tue Nov 26 15:10:34 2024 +0100 + + phc2sys: Don't require -O option without -a and -w. + + Allow phc2sys to be started in the static mode without the -O option, + meaning it should fetch the UTC offset from ptp4l, even if the -w option + is not included on the command line to wait for ptp4l to have a port in + the master or slave state. + + This is useful when the PHC is synchronized by ts2phc or other + application and the system clock needs to be synchronized to the PHC + even when ptp4l has all ports in the faulty state (e.g. all network + links are down). + + It's the responsibility of the user to start phc2sys when ptp4l is + already running. phc2sys will exit with an error message if it cannot + get a response with the 1-second timeout. + + Signed-off-by: Miroslav Lichvar + +diff --git a/phc2sys.8 b/phc2sys.8 +index 762a1b1..3246c8f 100644 +--- a/phc2sys.8 ++++ b/phc2sys.8 +@@ -164,7 +164,10 @@ minimize the error caused by random delays in scheduling and bus utilization. + The default is 5. + .TP + .BI \-O " offset" +-Specify the offset between the sink and source times in seconds. Not ++Specify the offset between the sink and source times in seconds. If not ++specified, the offset will be set according to the currentUtcOffset value ++obtained from ptp4l and the direction of synchronization, assuming the system ++clock is keeping time in UTC and all used PHCs keep time in TAI. Not + compatible with the + .B \-a + option. See +diff --git a/phc2sys.c b/phc2sys.c +index c98ecec..ddd0a6a 100644 +--- a/phc2sys.c ++++ b/phc2sys.c +@@ -1452,12 +1452,6 @@ int main(int argc, char *argv[]) + goto bad_usage; + } + +- if (!autocfg && !wait_sync && !settings.forced_sync_offset) { +- fprintf(stderr, +- "time offset must be specified using -w or -O\n"); +- goto bad_usage; +- } +- + if (hardpps_configured(pps_fd) && (dst_cnt != 1 || + strcmp(dst_names[0], "CLOCK_REALTIME"))) { + fprintf(stderr, +@@ -1559,7 +1553,7 @@ int main(int argc, char *argv[]) + + r = -1; + +- if (wait_sync) { ++ if (wait_sync || !domains[0].forced_sync_offset) { + snprintf(uds_local, sizeof(uds_local), + "/var/run/phc2sys.%d", getpid()); + +@@ -1574,7 +1568,7 @@ int main(int argc, char *argv[]) + phc2sys_recv_subscribed, &domains[0])) + goto end; + +- while (is_running()) { ++ while (wait_sync && is_running()) { + r = run_pmc_wait_sync(domains[0].agent, 1000); + if (r < 0) + goto end; diff --git a/linuxptp-ppsmiss.patch b/linuxptp-ppsmiss.patch new file mode 100644 index 0000000..d11d916 --- /dev/null +++ b/linuxptp-ppsmiss.patch @@ -0,0 +1,79 @@ +commit 5d735c810c8f9fd9916a3eb87398f5f9d6b1d278 +Author: Miroslav Lichvar +Date: Thu Aug 28 15:14:01 2025 +0200 + + ts2phc: Better handle missing pulses with multiple sinks. + + The ts2phc_pps_sink_poll() function waits until it has collected pulses + for all active sinks, or a timeout of 2 seconds between events is + reached. + + If a sink missed a pulse (e.g. after a port state change and switching + PPS signal direction in the external PPS mode) and the next pulse of + that sink came before pulses of the other sinks, it was mixed with + events of the previous pulse and the measured offset had an error of + 1/rate seconds. + + To avoid mixing events corresponding to different pulses, adjust the + poll() timeout so that it waits only up to a third of the pulse period + after the first received event. + + (Rebased to 4.4) + + Reviewed-by: Jacob Keller + Signed-off-by: Miroslav Lichvar + +diff --git a/ts2phc_pps_sink.c b/ts2phc_pps_sink.c +index 9076de9..72d8ea4 100644 +--- a/ts2phc_pps_sink.c ++++ b/ts2phc_pps_sink.c +@@ -381,10 +381,11 @@ void ts2phc_pps_sink_cleanup(struct ts2phc_private *priv) + int ts2phc_pps_sink_poll(struct ts2phc_private *priv) + { + struct ts2phc_sink_array *polling_array = priv->polling_array; ++ bool first_poll = true, ignore_any = false; + bool all_sinks_have_events = false; +- bool ignore_any = false; ++ struct timespec first_ts = {0}, ts; ++ int cnt, timeout; + unsigned int i; +- int cnt; + + for (i = 0; i < priv->n_sinks; i++) + polling_array->collected_events[i] = 0; +@@ -395,7 +396,22 @@ int ts2phc_pps_sink_poll(struct ts2phc_private *priv) + if (!is_running()) + return 0; + +- cnt = poll(polling_array->pfd, priv->n_sinks, 2000); ++ /* ++ * Collect only events within a third of the pulse period to ++ * avoid mixing events corresponding to different pulses. ++ */ ++ if (first_poll) { ++ timeout = 2000; ++ } else { ++ clock_gettime(CLOCK_MONOTONIC, &ts); ++ timeout = 333; ++ timeout -= (ts.tv_sec - first_ts.tv_sec) * 1000 + ++ (ts.tv_nsec - first_ts.tv_nsec) / 1000000; ++ if (timeout < 0) ++ timeout = 0; ++ } ++ ++ cnt = poll(polling_array->pfd, priv->n_sinks, timeout); + if (cnt < 0) { + if (errno == EINTR) { + return 0; +@@ -408,6 +424,11 @@ int ts2phc_pps_sink_poll(struct ts2phc_private *priv) + return 0; + } + ++ if (first_poll) { ++ clock_gettime(CLOCK_MONOTONIC, &first_ts); ++ first_poll = false; ++ } ++ + for (i = 0; i < priv->n_sinks; i++) { + if (polling_array->pfd[i].revents & POLLERR) { + sink = polling_array->sink[i]; diff --git a/linuxptp-rtnlinit.patch b/linuxptp-rtnlinit.patch new file mode 100644 index 0000000..60e011d --- /dev/null +++ b/linuxptp-rtnlinit.patch @@ -0,0 +1,75 @@ +commit 01de33e91f9717d0cbae5af6eee2beb45deee219 +Author: Miroslav Lichvar +Date: Tue Mar 4 15:53:37 2025 +0100 + + port: Refresh link status on faults. + + ptp4l gets the ENOBUFS error on the netlink socket when the kernel has + to drop messages due to full socket buffer. If ptp4l has a port in the + faulty state waiting for the link to go up and that event corresponds + to one of the dropped netlink messages, the port will be stuck in the + faulty state until the link goes down and up again. + + To prevent the port from getting stuck, request the current link status + when dispatching the EV_FAULT_DETECTED event. Also, reopen the socket to + get rid of the buffered messages when handling the fault and again when + reinitializing the port. + + Signed-off-by: Miroslav Lichvar + Reviewed-by: Jacob Keller + +diff --git a/port.c b/port.c +index 7f945ac..1bb407c 100644 +--- a/port.c ++++ b/port.c +@@ -1975,6 +1975,20 @@ static int port_cmlds_initialize(struct port *p) + return port_cmlds_renew(p, now.tv_sec); + } + ++static void port_rtnl_initialize(struct port *p) ++{ ++ /* Reopen the socket to get rid of buffered messages */ ++ if (p->fda.fd[FD_RTNL] >= 0) { ++ rtnl_close(p->fda.fd[FD_RTNL]); ++ } ++ p->fda.fd[FD_RTNL] = rtnl_open(); ++ if (p->fda.fd[FD_RTNL] >= 0) { ++ rtnl_link_query(p->fda.fd[FD_RTNL], interface_name(p->iface)); ++ } ++ ++ clock_fda_changed(p->clock); ++} ++ + void port_disable(struct port *p) + { + int i; +@@ -2087,13 +2101,8 @@ int port_initialize(struct port *p) + if (p->bmca == BMCA_NOOP) { + port_set_delay_tmo(p); + } +- if (p->fda.fd[FD_RTNL] == -1) { +- p->fda.fd[FD_RTNL] = rtnl_open(); +- } +- if (p->fda.fd[FD_RTNL] >= 0) { +- const char *ifname = interface_name(p->iface); +- rtnl_link_query(p->fda.fd[FD_RTNL], ifname); +- } ++ ++ port_rtnl_initialize(p); + } + + port_nrate_initialize(p); +@@ -3768,6 +3777,13 @@ int port_state_update(struct port *p, enum fsm_event event, int mdiff) + if (port_link_status_get(p) && clear_fault_asap(&i)) { + pr_notice("%s: clearing fault immediately", p->log_name); + next = p->state_machine(next, EV_FAULT_CLEARED, 0); ++ } else if (event == EV_FAULT_DETECTED) { ++ /* ++ * Reopen the netlink socket and refresh the link ++ * status in case the fault was triggered by a missed ++ * netlink message (ENOBUFS). ++ */ ++ port_rtnl_initialize(p); + } + } + diff --git a/linuxptp-staticauto.patch b/linuxptp-staticauto.patch new file mode 100644 index 0000000..0bc4f4f --- /dev/null +++ b/linuxptp-staticauto.patch @@ -0,0 +1,302 @@ +commit e57fe1786ed17e8f0a37d9319bde53c9985ed656 +Author: Miroslav Lichvar +Date: Thu Oct 17 15:05:21 2024 +0200 + + pmc: Avoid race conditions in agent update. + + The pmc_agent_update() function updates the subscription to + notifications and also the current UTC offset. It uses a timeout of 0 + to avoid blocking. When the pmc client sends the first request, the + response from ptp4l may not come quickly enough to be received in the + same run_pmc() call. It then sends the other request and checks for the + response. If it is the response to the first request, it will be ignored. + The update works correctly only if both responses are quick enough to be + received in the same call, or are both slow enough that they are + received in the next call of the pmc_agent_update() function. + + The function needs to be called a random number of times in order to + finish one update. If the mismatch between requests and responses + happened consistently, the agent would never reach the up-to-date state + and phc2sys would not enter the main synchronization loop. + + Split the update into two phases, where only one thing is updated at a + time. The function now needs to be called at most 3 times to update both + the subscription and UTC offset, assuming it is not interrupted by + another request outside of the agent's update. + + Signed-off-by: Miroslav Lichvar + Reviewed-by: Jacob Keller + +diff --git a/pmc_agent.c b/pmc_agent.c +index 86b6ee6..d1a3367 100644 +--- a/pmc_agent.c ++++ b/pmc_agent.c +@@ -37,6 +37,7 @@ struct pmc_agent { + struct pmc *pmc; + uint64_t pmc_last_update; + uint64_t update_interval; ++ int update_phase; + + struct defaultDS dds; + bool dds_valid; +@@ -427,16 +428,27 @@ int pmc_agent_update(struct pmc_agent *node) + ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec; + + if (ts - node->pmc_last_update >= node->update_interval) { +- if (node->stay_subscribed) { +- renew_subscription(node, 0); +- } +- if (!pmc_agent_query_utc_offset(node, 0)) { ++ switch (node->update_phase) { ++ case 0: ++ if (node->stay_subscribed && ++ renew_subscription(node, 0)) ++ break; ++ node->update_phase++; ++ /* Fall through */ ++ case 1: ++ if (pmc_agent_query_utc_offset(node, 0)) ++ break; ++ node->update_phase++; ++ /* Fall through */ ++ default: + node->pmc_last_update = ts; ++ node->update_phase = 0; ++ break; + } ++ } else { ++ run_pmc(node, 0, -1, &msg); + } + +- run_pmc(node, 0, -1, &msg); +- + return 0; + } + + +commit 341cdd74c1623cdf97c519abec7312ac11baea4d +Author: Miroslav Lichvar +Date: Thu Oct 17 15:05:22 2024 +0200 + + phc2sys: Wait until pmc agent is subscribed. + + When phc2sys is configured with multiple domains, different domains may + have their pmc agent subscribed after different number of calls of the + pmc_agent_update() function depending on how quickly responses from + ptp4l are received. If one domain triggers reconfiguration and the other + domain does not have its agent subscribed yet, it will not have any of + its clocks synchronized until a port changes state and triggers another + reconfiguration of the domain. + + To avoid this problem, wait for each domain to have its agent subscribed + before entering the main synchronization loop. Use a 10ms update + interval to speed up the start of phc2sys. + + Signed-off-by: Miroslav Lichvar + Reviewed-by: Jacob Keller + +diff --git a/phc2sys.c b/phc2sys.c +index 6113539..47e896e 100644 +--- a/phc2sys.c ++++ b/phc2sys.c +@@ -962,6 +962,12 @@ static int auto_init_ports(struct domain *domain) + return -1; + } + ++ while (!pmc_agent_is_subscribed(domain->agent)) { ++ usleep(10000); ++ if (pmc_agent_update(domain->agent) < 0) ++ return -1; ++ } ++ + for (i = 1; i <= number_ports; i++) { + err = pmc_agent_query_port_properties(domain->agent, 1000, i, + &state, ×tamping, + +commit a6cab9f888f88edab28e90d57a5368bbb83f6702 +Author: Miroslav Lichvar +Date: Thu Oct 24 15:24:07 2024 +0200 + + phc2sys: Keep clocks in command-line or ptp4l order. + + When adding a new clock to the domain, add it to the end of the list to + keep them in the same order as specified on the command line or the port + order of ptp4l. + + This will be needed by new code in the domain reconfiguration expecting + the order of reinitialized clocks to be the same as in which they were + added to the domain. + + Signed-off-by: Miroslav Lichvar + Reviewed-by: Jacob Keller + +diff --git a/phc2sys.c b/phc2sys.c +index 47e896e..bf36c38 100644 +--- a/phc2sys.c ++++ b/phc2sys.c +@@ -161,7 +161,7 @@ static struct servo *servo_add(struct domain *domain, + static struct clock *clock_add(struct domain *domain, const char *device, + int phc_index) + { +- struct clock *c; ++ struct clock *c, *c2; + clockid_t clkid = CLOCK_INVALID; + char phc_device[19]; + +@@ -217,7 +217,19 @@ static struct clock *clock_add(struct domain *domain, const char *device, + c->sysoff_method = sysoff_probe(CLOCKID_TO_FD(clkid), + domain->phc_readings); + +- LIST_INSERT_HEAD(&domain->clocks, c, list); ++ /* Add the clock to the end of the list to keep them in the ++ command-line or ptp4l order */ ++ if (LIST_EMPTY(&domain->clocks)) { ++ LIST_INSERT_HEAD(&domain->clocks, c, list); ++ } else { ++ LIST_FOREACH(c2, &domain->clocks, list) { ++ if (LIST_NEXT(c2, list)) ++ continue; ++ LIST_INSERT_AFTER(c2, c, list); ++ break; ++ } ++ } ++ + return c; + } + + +commit 5d2aeb54054453570014715be4445da80da57101 +Author: Miroslav Lichvar +Date: Thu Oct 24 15:24:08 2024 +0200 + + phc2sys: Allow static sink clocks in automatic mode. + + Allow the -c option to be used together with the -a option. Add the + specified clocks to the first domain, where they will stay in the master + state and be synchronized when a source is available in the same domain + or other domains. + + Mark the clocks added by -c as static and skip them in the domain + reconfiguration if they duplicate a clock following a ptp4l port. + + A use case is synchronization of clocks of backup interfaces in an + active-backup bond to minimize the observed offset when the active + interface is switched. ptp4l tracks the active interface, which is + followed by the automatic mode of phc2sys. All interfaces included in + the bond are specified by the -c option to keep them all synchronized to + the same source. The interface which duplicates the current active + interface provided by ptp4l is skipped. + + Signed-off-by: Miroslav Lichvar + +diff --git a/phc2sys.8 b/phc2sys.8 +index dd97a70..762a1b1 100644 +--- a/phc2sys.8 ++++ b/phc2sys.8 +@@ -117,10 +117,13 @@ should no longer be used. + .TP + .BI \-c " device" + Specify the time sink by device (e.g. /dev/ptp1) or interface (e.g. eth1) or +-by name. The default is CLOCK_REALTIME (the system clock). Not compatible +-with the ++by name. If used together with the + .B \-a +-option. This option may be given up to 128 times. ++option, it is an additional sink clock added to the clocks provided by the ++first ptp4l instance (if ++.B \-z ++is specified multiple times). Duplicated clocks are allowed. The default is ++CLOCK_REALTIME (the system clock). This option may be given up to 128 times. + .TP + .BI \-E " servo" + Specify which clock servo should be used. Valid values are pi for a PI +diff --git a/phc2sys.c b/phc2sys.c +index bf36c38..d09cb53 100644 +--- a/phc2sys.c ++++ b/phc2sys.c +@@ -79,6 +79,7 @@ struct clock { + int dest_only; + int state; + int new_state; ++ int static_state; + int sync_offset; + int leap_set; + int utc_offset_set; +@@ -391,6 +392,18 @@ static struct clock *find_dst_clock(struct domain *domain, + return c; + } + ++static struct clock *find_nonstatic_clock(struct domain *domain, ++ int phc_index) ++{ ++ struct clock *c = NULL; ++ LIST_FOREACH(c, &domain->clocks, list) { ++ if (!c->static_state && c->phc_index == phc_index) { ++ break; ++ } ++ } ++ return c; ++} ++ + static int reconfigure_domain(struct domain *domain) + { + struct clock *c, *src = NULL, *dup = NULL; +@@ -422,6 +435,17 @@ static int reconfigure_domain(struct domain *domain) + c->new_state = 0; + } + ++ /* Ignore the clock if its state is not following ptp4l and has ++ the same PHC index as a clock that is following ptp4l */ ++ if (c->static_state) { ++ dup = find_nonstatic_clock(domain, c->phc_index); ++ if (dup) { ++ pr_info("skipping static %s: %s has the same clock", ++ c->device, dup->device); ++ continue; ++ } ++ } ++ + switch (c->state) { + case PS_FAULTY: + case PS_DISABLED: +@@ -436,6 +460,8 @@ static int reconfigure_domain(struct domain *domain) + dst_cnt++; + LIST_INSERT_HEAD(&domain->dst_clocks, + c, dst_list); ++ if (c->sanity_check) ++ clockcheck_reset(c->sanity_check); + } else { + pr_info("skipping %s: %s has the same clock " + "and is already selected", +@@ -1128,6 +1154,7 @@ static int phc2sys_static_dst_configuration(struct domain *domain, + return -1; + } + dst->state = PS_MASTER; ++ dst->static_state = 1; + LIST_INSERT_HEAD(&domain->dst_clocks, dst, dst_list); + + return 0; +@@ -1407,7 +1434,7 @@ int main(int argc, char *argv[]) + dst_names[dst_cnt++] = "CLOCK_REALTIME"; + } + +- if (autocfg && (src_name || dst_cnt > 0 || hardpps_configured(pps_fd) || ++ if (autocfg && (src_name || hardpps_configured(pps_fd) || + wait_sync || settings.forced_sync_offset)) { + fprintf(stderr, + "autoconfiguration cannot be mixed with manual config options.\n"); +@@ -1506,6 +1533,14 @@ int main(int argc, char *argv[]) + if (auto_init_ports(&domains[i]) < 0) + goto end; + } ++ ++ for (i = 0; i < dst_cnt; i++) { ++ r = phc2sys_static_dst_configuration(&domains[0], ++ dst_names[i]); ++ if (r) ++ goto end; ++ } ++ + r = do_loop(domains, n_domains); + goto end; + } diff --git a/SOURCES/linuxptp-ucastrate.patch b/linuxptp-ucastrate.patch similarity index 100% rename from SOURCES/linuxptp-ucastrate.patch rename to linuxptp-ucastrate.patch diff --git a/linuxptp-udpaddr.patch b/linuxptp-udpaddr.patch new file mode 100644 index 0000000..d4804b3 --- /dev/null +++ b/linuxptp-udpaddr.patch @@ -0,0 +1,85 @@ +commit 77504ea63484dbc0c78b1ef58b29f06ced517223 +Author: Miroslav Lichvar +Date: Wed Sep 25 14:16:16 2024 +0200 + + udp: Fix port-specific ptp/p2p_dst_ipv4 configuration. + + If different ports are configured with a different ptp_dst_ipv4 or + p2p_dst_ipv4 address, only the last port in the configuration works + correctly. This is caused by a global variable holding the + destination address for all ports using the udp transport. + + Move the address to the udp structure to avoid the conflict between + different ports, same as when port-specific scope in udp6 was fixed + in commit a48666bee3dd ("udp6: Make mc6_addr transport-local"). + + Fixes: 8a26c94cc88e ("udp+udp6: Make IP addresses configurable.") + Signed-off-by: Miroslav Lichvar + +diff --git a/udp.c b/udp.c +index 38d0ec4..c9b5f39 100644 +--- a/udp.c ++++ b/udp.c +@@ -44,6 +44,7 @@ struct udp { + struct transport t; + struct address ip; + struct address mac; ++ struct in_addr mcast_addr[2]; + }; + + static int mcast_bind(int fd, int index) +@@ -146,8 +147,6 @@ no_socket: + + enum { MC_PRIMARY, MC_PDELAY }; + +-static struct in_addr mcast_addr[2]; +- + static int udp_open(struct transport *t, struct interface *iface, + struct fdarray *fda, enum timestamp_type ts_type) + { +@@ -165,22 +164,22 @@ static int udp_open(struct transport *t, struct interface *iface, + sk_interface_addr(name, AF_INET, &udp->ip); + + str = config_get_string(t->cfg, name, "ptp_dst_ipv4"); +- if (!inet_aton(str, &mcast_addr[MC_PRIMARY])) { ++ if (!inet_aton(str, &udp->mcast_addr[MC_PRIMARY])) { + pr_err("invalid ptp_dst_ipv4 %s", str); + return -1; + } + + str = config_get_string(t->cfg, name, "p2p_dst_ipv4"); +- if (!inet_aton(str, &mcast_addr[MC_PDELAY])) { ++ if (!inet_aton(str, &udp->mcast_addr[MC_PDELAY])) { + pr_err("invalid p2p_dst_ipv4 %s", str); + return -1; + } + +- efd = open_socket(name, mcast_addr, EVENT_PORT, ttl); ++ efd = open_socket(name, udp->mcast_addr, EVENT_PORT, ttl); + if (efd < 0) + goto no_event; + +- gfd = open_socket(name, mcast_addr, GENERAL_PORT, ttl); ++ gfd = open_socket(name, udp->mcast_addr, GENERAL_PORT, ttl); + if (gfd < 0) + goto no_general; + +@@ -223,6 +222,7 @@ static int udp_send(struct transport *t, struct fdarray *fda, + enum transport_event event, int peer, void *buf, int len, + struct address *addr, struct hw_timestamp *hwts) + { ++ struct udp *udp = container_of(t, struct udp, t); + struct address addr_buf; + unsigned char junk[1600]; + ssize_t cnt; +@@ -243,8 +243,8 @@ static int udp_send(struct transport *t, struct fdarray *fda, + if (!addr) { + memset(&addr_buf, 0, sizeof(addr_buf)); + addr_buf.sin.sin_family = AF_INET; +- addr_buf.sin.sin_addr = peer ? mcast_addr[MC_PDELAY] : +- mcast_addr[MC_PRIMARY]; ++ addr_buf.sin.sin_addr = peer ? udp->mcast_addr[MC_PDELAY] : ++ udp->mcast_addr[MC_PRIMARY]; + addr_buf.len = sizeof(addr_buf.sin); + addr = &addr_buf; + } diff --git a/linuxptp-unirecover.patch b/linuxptp-unirecover.patch new file mode 100644 index 0000000..f3f2bf7 --- /dev/null +++ b/linuxptp-unirecover.patch @@ -0,0 +1,104 @@ +commit 71241f3fdcff59b35ad5de0b8b37cb07a4b677bd +Author: Vincent Cheng +Date: Tue Sep 17 15:23:54 2024 -0400 + + port: Fix unicast negotiation doesn't recover after FAULT_DETECTED + + _Problem_ + After a port link down/up or a tx_timestamp timeout issue, a port acting + as unicast master does not issue ANNC messages after granting unicast + request for ANNC. + + _Analysis_ + When a port FAULT occurs, the port transitions to FAULTY on FAULT_DETECTED + and subsequently port_disable(p) and port_initialize(p) are called on port recovery. + + A port acting as a unicast master, stores clients in p->unicast_service->queue. + + When a port receives a unicast request, unicast_service_add() is called. + + In unicast_service_add(), if the request does not match an entry in + p->unicast_service->queue, FD_UNICAST_SRV_TIMER is started via + unicast_service_rearm_timer(). + + If the unicast request matches an existing p->unicast_service->queue entry + the request is considered an extension and FD_UNICAST_SRV_TIMER must + already be running. + + port_disable() clears FD_UNICAST_SRV_TIMER, ie. stops FD_UNICAST_SRV_TIMER. + However, port_disable() does not clear p->unicast_service->queue. + When the port is restarted, the port retains the previous client data. + + After port recovery, when the client attempts to restart the unicast + service, the request matches an existing entry in p->unicast_service->queue, + and so FD_UNICAST_SRV_TIMER is not started because the port expected + that the FD_UNICAST_SRV_TIMER is already running. + + _Fix_ + This patch clears the unicast client data in port_disable() so + that upon recovery, the initial unicast request will be considered + a new request and trigger the start of the FD_UNICAST_SRV_TIMER. + + v2: + - Add missing sign-off + - Send to develop-request instead of users list + + Signed-off-by: Vincent Cheng + +diff --git a/port.c b/port.c +index 1bb407c..90b0860 100644 +--- a/port.c ++++ b/port.c +@@ -1999,6 +1999,7 @@ void port_disable(struct port *p) + flush_peer_delay(p); + + p->best = NULL; ++ unicast_service_clear_clients(p); + free_foreign_masters(p); + transport_close(p->trp, &p->fda); + +diff --git a/unicast_service.c b/unicast_service.c +index 2fc2fbe..cee6691 100644 +--- a/unicast_service.c ++++ b/unicast_service.c +@@ -583,3 +583,24 @@ int unicast_service_timer(struct port *p) + } + return err; + } ++ ++void unicast_service_clear_clients(struct port *p) ++{ ++ struct unicast_client_address *client, *temp; ++ struct unicast_service_interval *interval; ++ ++ if (!p->unicast_service) { ++ return; ++ } ++ ++ while ((interval = pqueue_extract(p->unicast_service->queue)) != NULL) { ++ ++ LIST_REMOVE(interval, list); ++ ++ LIST_FOREACH_SAFE(client, &interval->clients, list, temp) { ++ LIST_REMOVE(client, list); ++ free(client); ++ } ++ free(interval); ++ } ++} +\ No newline at end of file +diff --git a/unicast_service.h b/unicast_service.h +index f0d6487..8ea1a59 100644 +--- a/unicast_service.h ++++ b/unicast_service.h +@@ -87,4 +87,10 @@ void unicast_service_remove(struct port *p, struct ptp_message *m, + */ + int unicast_service_timer(struct port *p); + ++/** ++ * Clears unicast clients on a given port. ++ * @param p The port in question. ++ */ ++void unicast_service_clear_clients(struct port *p); ++ + #endif diff --git a/linuxptp.fc b/linuxptp.fc new file mode 100644 index 0000000..c0a31f6 --- /dev/null +++ b/linuxptp.fc @@ -0,0 +1,11 @@ +/usr/lib/systemd/system/phc2sys.* -- gen_context(system_u:object_r:phc2sys_unit_file_t,s0) + +/usr/lib/systemd/system/ptp4l.* -- gen_context(system_u:object_r:ptp4l_unit_file_t,s0) + +/usr/lib/systemd/system/timemaster.* -- gen_context(system_u:object_r:timemaster_unit_file_t,s0) + +/usr/sbin/ptp4l -- gen_context(system_u:object_r:ptp4l_exec_t,s0) +/usr/sbin/phc2sys -- gen_context(system_u:object_r:phc2sys_exec_t,s0) +/usr/sbin/timemaster -- gen_context(system_u:object_r:timemaster_exec_t,s0) + +/run/timemaster(/.*)? gen_context(system_u:object_r:timemaster_var_run_t,s0) diff --git a/linuxptp.if b/linuxptp.if new file mode 100644 index 0000000..ab8cda5 --- /dev/null +++ b/linuxptp.if @@ -0,0 +1,178 @@ +## implementation of the Precision Time Protocol (PTP) according to IEEE standard 1588 for Linux. + +######################################## +## +## Execute domain in the phc2sys domain. +## +## +## +## Domain allowed to transition. +## +## +# +interface(`linuxptp_domtrans_phc2sys',` + gen_require(` + type phc2sys_t, phc2sys_exec_t; + ') + + corecmd_search_bin($1) + domtrans_pattern($1, phc2sys_exec_t, phc2sys_t) +') + +######################################## +## +## Execute domain in the phc2sys domain. +## +## +## +## Domain allowed to transition. +## +## +# +interface(`linuxptp_domtrans_ptp4l',` + gen_require(` + type ptp4l_t, ptp4l_exec_t; + ') + + corecmd_search_bin($1) + domtrans_pattern($1, ptp4l_exec_t, ptp4l_t) +') +###################################### +## +## Connect to timemaster using a unix +## domain stream socket. +## +## +## +## Domain allowed access. +## +## +# +interface(`timemaster_stream_connect',` + gen_require(` + type timemaster_t, timemaster_var_run_t; + ') + + files_search_pids($1) + stream_connect_pattern($1, timemaster_var_run_t, timemaster_var_run_t, timemaster_t) +') + +######################################## +## +## Read timemaster conf files. +## +## +## +## Domain allowed access. +## +## +# +interface(`timemaster_read_pid_files',` + gen_require(` + type timemaster_var_run_t; + ') + + read_files_pattern($1, timemaster_var_run_t, timemaster_var_run_t) +') + +######################################## +## +## Manage timemaster pid files. +## +## +## +## Domain allowed access. +## +## +# +interface(`timemaster_manage_pid_sock_files',` + gen_require(` + type timemaster_var_run_t; + ') + + manage_sock_files_pattern($1, timemaster_var_run_t, timemaster_var_run_t) +') + +######################################## +## +## Read and write timemaster shared memory. +## +## +## +## Domain allowed access. +## +## +# +interface(`timemaster_rw_shm',` + gen_require(` + type timemaster_t, timemaster_tmpfs_t; + ') + + allow $1 timemaster_t:shm rw_shm_perms; + list_dirs_pattern($1, timemaster_tmpfs_t, timemaster_tmpfs_t) + rw_files_pattern($1, timemaster_tmpfs_t, timemaster_tmpfs_t) + read_lnk_files_pattern($1, timemaster_tmpfs_t, timemaster_tmpfs_t) + fs_search_tmpfs($1) +') + +######################################## +## +## Read and write ptp4l_t shared memory. +## +## +## +## Domain allowed access. +## +## +# +interface(`ptp4l_rw_shm',` + gen_require(` + type ptp4l_t, timemaster_tmpfs_t; + ') + + allow $1 ptp4l_t:shm rw_shm_perms; + list_dirs_pattern($1, timemaster_tmpfs_t, timemaster_tmpfs_t) + rw_files_pattern($1, timemaster_tmpfs_t, timemaster_tmpfs_t) + read_lnk_files_pattern($1, timemaster_tmpfs_t, timemaster_tmpfs_t) + fs_search_tmpfs($1) +') + +######################################## +## +## Read and write phc2sys_t shared memory. +## +## +## +## Domain allowed access. +## +## +# +interface(`phc2sys_rw_shm',` + gen_require(` + type phc2sys_t, timemaster_tmpfs_t; + ') + + allow $1 phc2sys_t:shm rw_shm_perms; + list_dirs_pattern($1, timemaster_tmpfs_t, timemaster_tmpfs_t) + rw_files_pattern($1, timemaster_tmpfs_t, timemaster_tmpfs_t) + read_lnk_files_pattern($1, timemaster_tmpfs_t, timemaster_tmpfs_t) + fs_search_tmpfs($1) +') + +####################################### +## +## Get timemaster services status +## +## +## +## Domain allowed to transition. +## +## +# +interface(`timemaster_service_status',` + gen_require(` + type timemaster_unit_file_t; + ') + + allow $1 timemaster_unit_file_t:service status; +') diff --git a/linuxptp.spec b/linuxptp.spec new file mode 100644 index 0000000..00bf264 --- /dev/null +++ b/linuxptp.spec @@ -0,0 +1,414 @@ +%global _hardened_build 1 +%global testsuite_ver d27dbd +%global clknetsim_ver 64df92 +%global selinuxtype targeted +%bcond_without selinux + +Name: linuxptp +Version: 4.4 +Release: 5%{?dist} +Summary: PTP implementation for Linux + +License: GPL-2.0-or-later +URL: https://www.linuxptp.org/ + +Source0: https://downloads.nwtime.org/%{name}/%{name}-%{version}.tgz +Source1: phc2sys.service +Source2: ptp4l.service +Source3: timemaster.service +Source4: timemaster.conf +Source5: ptp4l.conf +# external test suite +Source10: https://github.com/mlichvar/linuxptp-testsuite/archive/%{testsuite_ver}/linuxptp-testsuite-%{testsuite_ver}.tar.gz +# simulator for test suite +Source11: https://github.com/mlichvar/clknetsim/archive/%{clknetsim_ver}/clknetsim-%{clknetsim_ver}.tar.gz +# selinux policy +Source20: linuxptp.fc +Source21: linuxptp.if +Source22: linuxptp.te + +# limit unicast message rate per address and grant duration +Patch1: linuxptp-ucastrate.patch +# fix port-specific ptp/p2p_dst_ipv4 configuration +Patch2: linuxptp-udpaddr.patch +# support static sink clocks in phc2sys automatic mode +Patch3: linuxptp-staticauto.patch +# don't require -O option without -a and -w in phc2sys +Patch4: linuxptp-nowait.patch +# add experimental option for external PPS in ts2phc automatic mode +Patch8: linuxptp-externalpps.patch +# add command to set external grandmaster properties +Patch9: linuxptp-externalgm.patch +# refresh link status on faults +Patch10: linuxptp-rtnlinit.patch +# fix unicast server to recover after port fault +Patch11: linuxptp-unirecover.patch +# handle missing pulses in ts2phc +Patch13: linuxptp-ppsmiss.patch + +BuildRequires: gcc gcc-c++ gnutls-devel make systemd + +%{?systemd_requires} + +%if 0%{?with_selinux} +Requires: (%{name}-selinux if selinux-policy-%{selinuxtype}) +%endif + +%description +This software is an implementation of the Precision Time Protocol (PTP) +according to IEEE standard 1588 for Linux. The dual design goals are to provide +a robust implementation of the standard and to use the most relevant and modern +Application Programming Interfaces (API) offered by the Linux kernel. +Supporting legacy APIs and other platforms is not a goal. + +%if 0%{?with_selinux} +%package selinux +Summary: linuxptp SELinux policy +BuildArch: noarch +Requires: selinux-policy-%{selinuxtype} +Requires(post): selinux-policy-%{selinuxtype} +BuildRequires: selinux-policy-devel +%{?selinux_requires} + +%description selinux +linuxptp SELinux policy module + +%endif + +%prep +%autosetup -N +# autosetup doesn't accept multiple -a options +%__rpmuncompress -x %{SOURCE10} +%__rpmuncompress -x %{SOURCE11} +%autopatch -p1 + +# disable nettle support in favor of gnutls +sed -i 's|find .*"nettle"|true|' incdefs.sh + +mv linuxptp-testsuite-%{testsuite_ver}* testsuite +mv clknetsim-%{clknetsim_ver}* testsuite/clknetsim + +pushd testsuite/clknetsim +popd + +mkdir selinux +cp -p %{SOURCE20} %{SOURCE21} %{SOURCE22} selinux + +%build +%{make_build} \ + EXTRA_CFLAGS="$RPM_OPT_FLAGS" \ + EXTRA_LDFLAGS="$RPM_LD_FLAGS" + +%if 0%{?with_selinux} +make -C selinux -f %{_datadir}/selinux/devel/Makefile linuxptp.pp +bzip2 -9 selinux/linuxptp.pp +%endif + +%install +%makeinstall + +mkdir -p $RPM_BUILD_ROOT{%{_sysconfdir}/sysconfig,%{_unitdir},%{_mandir}/man5} +install -m 644 -p %{SOURCE1} %{SOURCE2} %{SOURCE3} $RPM_BUILD_ROOT%{_unitdir} +install -m 644 -p %{SOURCE4} %{SOURCE5} $RPM_BUILD_ROOT%{_sysconfdir} + +echo 'OPTIONS="-f /etc/ptp4l.conf"' > \ + $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/ptp4l +echo 'OPTIONS="-a -r"' > $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/phc2sys + +echo '.so man8/ptp4l.8' > $RPM_BUILD_ROOT%{_mandir}/man5/ptp4l.conf.5 +echo '.so man8/timemaster.8' > $RPM_BUILD_ROOT%{_mandir}/man5/timemaster.conf.5 + +%if 0%{?with_selinux} +install -D -m 0644 selinux/linuxptp.pp.bz2 \ + $RPM_BUILD_ROOT%{_datadir}/selinux/packages/%{selinuxtype}/linuxptp.pp.bz2 +install -D -p -m 0644 selinux/linuxptp.if \ + $RPM_BUILD_ROOT%{_datadir}/selinux/devel/include/distributed/linuxptp.if +%endif + +%check +cd testsuite +# set random seed to get deterministic results +export CLKNETSIM_RANDOM_SEED=26743 +%{make_build} -C clknetsim +PATH=..:$PATH ./run + +%post +%systemd_post phc2sys.service ptp4l.service timemaster.service + +%preun +%systemd_preun phc2sys.service ptp4l.service timemaster.service + +%postun +%systemd_postun_with_restart phc2sys.service ptp4l.service timemaster.service + +%if 0%{?with_selinux} +%pre selinux +%selinux_relabel_pre -s %{selinuxtype} + +%post selinux +%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/linuxptp.pp.bz2 +%selinux_relabel_post -s %{selinuxtype} + +%postun selinux +if [ $1 -eq 0 ]; then + %selinux_modules_uninstall -s %{selinuxtype} linuxptp + %selinux_relabel_post -s %{selinuxtype} +fi + +%files selinux +%{_datadir}/selinux/packages/%{selinuxtype}/linuxptp.pp.* +%{_datadir}/selinux/devel/include/distributed/linuxptp.if +%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/linuxptp + +%endif + +%files +%doc COPYING README.org configs +%config(noreplace) %{_sysconfdir}/ptp4l.conf +%config(noreplace) %{_sysconfdir}/sysconfig/phc2sys +%config(noreplace) %{_sysconfdir}/sysconfig/ptp4l +%config(noreplace) %{_sysconfdir}/timemaster.conf +%{_unitdir}/phc2sys.service +%{_unitdir}/ptp4l.service +%{_unitdir}/timemaster.service +%{_sbindir}/hwstamp_ctl +%{_sbindir}/nsm +%{_sbindir}/phc2sys +%{_sbindir}/phc_ctl +%{_sbindir}/pmc +%{_sbindir}/ptp4l +%{_sbindir}/timemaster +%{_sbindir}/ts2phc +%{_sbindir}/tz2alt +%{_mandir}/man5/*.5* +%{_mandir}/man8/*.8* + +%changelog +* Tue Sep 23 2025 Miroslav Lichvar 4.4-5 +- handle missing pulses in ts2phc (RHEL-112344) + +* Wed May 28 2025 Miroslav Lichvar 4.4-4 +- fix unicast server to recover after port fault (RHEL-93497) + +* Wed May 14 2025 Miroslav Lichvar 4.4-3 +- add experimental option for external PPS in ts2phc automatic mode + (RHEL-89605) +- add command to set external grandmaster properties (RHEL-91310) +- refresh link status on faults (RHEL-89811) + +* Thu Jan 30 2025 Miroslav Lichvar 4.4-2 +- update selinux policy (RHEL-76786) +- harden systemd services (RHEL-76760) + +* Tue Dec 03 2024 Miroslav Lichvar 4.4-1 +- update to 4.4 (RHEL-58210) +- fix port-specific ptp/p2p_dst_ipv4 configuration (RHEL-60055) +- support static sink clocks in phc2sys automatic mode (RHEL-69145) +- don't require -O option without -a and -w in phc2sys (RHEL-69699) + +* Tue Oct 29 2024 Troy Dawson - 4.3-2 +- Bump release for October 2024 mass rebuild: + Resolves: RHEL-64018 + +* Mon Aug 19 2024 Miroslav Lichvar 4.3-1 +- update to 4.3 (RHEL-54718) +- add holdover support to ts2phc (RHEL-54716) +- rework NMEA delay patch to fix PPS edge rejection (RHEL-54719) +- fix ts2phc to reset NMEA parser after RMC message (RHEL-54724) +- fix ts2phc to correctly handle leap seconds (RHEL-54721) + +* Mon Jun 24 2024 Troy Dawson - 4.2-7 +- Bump release for June 2024 mass rebuild + +* Tue Apr 16 2024 Miroslav Lichvar 4.2-6 +- disable mode verification of selinux module directory (RHEL-32904) + +* Wed Mar 20 2024 Miroslav Lichvar 4.2-5 +- rebuild + +* Wed Mar 20 2024 Miroslav Lichvar 4.2-4 +- update selinux policy (RHEL-29728) +- limit unicast message rate per address and grant duration (RHEL-29738) +- allow old syntax of SET SUBSCRIBE_EVENTS_NP command (RHEL-29738) +- fix loading and reloading of leapfile (RHEL-29738) +- fix ts2phc to handle large NMEA delay (RHEL-29737) + +* Thu Jan 25 2024 Fedora Release Engineering - 4.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Sun Jan 21 2024 Fedora Release Engineering - 4.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Tue Jan 02 2024 Miroslav Lichvar 4.2-1 +- update to 4.2 +- update default ptp4l.conf + +* Wed Sep 06 2023 Miroslav Lichvar 4.1-1 +- update to 4.1 + +* Thu Jul 20 2023 Fedora Release Engineering - 4.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + +* Mon Jun 12 2023 Miroslav Lichvar 4.0-1 +- update to 4.0 +- convert license tag to SPDX +- update URL to https + +* Thu Jan 19 2023 Fedora Release Engineering - 3.1.1-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + +* Wed Jan 11 2023 Miroslav Lichvar 3.1.1-6 +- update selinux policy (#2159919) + +* Thu Jul 21 2022 Fedora Release Engineering - 3.1.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild + +* Tue Apr 26 2022 Miroslav Lichvar 3.1.1-4 +- fix tests on ppc64le (#2046706) + +* Thu Jan 20 2022 Fedora Release Engineering - 3.1.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + +* Thu Jul 22 2021 Miroslav Lichvar 3.1.1-2 +- package selinux policy + +* Wed Jul 07 2021 Miroslav Lichvar 3.1.1-1 +- update to 3.1.1 (CVE-2021-3570, CVE-2021-3571) + +* Tue Mar 02 2021 Zbigniew JÄ™drzejewski-Szmek - 3.1-4 +- Rebuilt for updated systemd-rpm-macros + See https://pagure.io/fesco/issue/2583. + +* Thu Feb 25 2021 Miroslav Lichvar 3.1-3 +- fix handling of zero-length messages +- minimize default configuration +- remove obsolete build requirement + +* Tue Jan 26 2021 Fedora Release Engineering - 3.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Tue Sep 29 2020 Miroslav Lichvar 3.1-1 +- update to 3.1 + +* Mon Jul 27 2020 Miroslav Lichvar 3.0-1 +- update to 3.0 + +* Mon Feb 03 2020 Miroslav Lichvar 2.0-7.20191225gite05809 +- update to 20191225gite05809 +- fix testing with new glibc + +* Wed Jan 29 2020 Fedora Release Engineering - 2.0-6.20190912git48e605 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Wed Sep 25 2019 Miroslav Lichvar 2.0-5.20190912git48e605 +- update to 20190912git48e605 + +* Thu Jul 25 2019 Fedora Release Engineering - 2.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Fri Feb 01 2019 Fedora Release Engineering - 2.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Tue Nov 13 2018 Miroslav Lichvar 2.0-2 +- start ptp4l, timemaster and phc2sys after network-online target +- fix building with new kernel headers + +* Mon Aug 13 2018 Miroslav Lichvar 2.0-1 +- update to 2.0 + +* Thu Aug 09 2018 Miroslav Lichvar 2.0-0.1.20180805gita27407 +- update to 20180805gita27407 + +* Mon Jul 16 2018 Miroslav Lichvar 1.9.2-3 +- add gcc and gcc-c++ to build requirements + +* Fri Jul 13 2018 Fedora Release Engineering - 1.9.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Mon Apr 09 2018 Miroslav Lichvar 1.9.2-1 +- update to 1.9.2 + +* Wed Feb 07 2018 Fedora Release Engineering - 1.8-7.20180101git303b08 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Tue Jan 30 2018 Miroslav Lichvar 1.8-6.20180101git303b08 +- use macro for systemd scriptlet dependencies + +* Thu Jan 11 2018 Miroslav Lichvar 1.8-5.20180101git303b08 +- update to 20180101git303b08 + +* Thu Aug 03 2017 Fedora Release Engineering - 1.8-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 1.8-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Fri Feb 10 2017 Fedora Release Engineering - 1.8-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Mon Nov 07 2016 Miroslav Lichvar 1.8-1 +- update to 1.8 + +* Fri Jul 22 2016 Miroslav Lichvar 1.7-1 +- update to 1.7 +- add delay option to default timemaster.conf + +* Thu Feb 04 2016 Fedora Release Engineering - 1.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Tue Sep 22 2015 Miroslav Lichvar 1.6-1 +- update to 1.6 +- set random seed in testing to get deterministic results +- remove trailing whitespace in default timemaster.conf + +* Wed Jun 17 2015 Fedora Release Engineering - 1.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Mon Jan 05 2015 Miroslav Lichvar 1.5-1 +- update to 1.5 + +* Sun Aug 17 2014 Fedora Release Engineering - 1.4-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Sat Jun 07 2014 Fedora Release Engineering - 1.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Fri Feb 21 2014 Miroslav Lichvar 1.4-1 +- update to 1.4 +- replace hardening build flags with _hardened_build +- include test suite + +* Fri Aug 02 2013 Miroslav Lichvar 1.3-1 +- update to 1.3 + +* Tue Jul 30 2013 Miroslav Lichvar 1.2-3.20130730git7789f0 +- update to 20130730git7789f0 + +* Fri Jul 19 2013 Miroslav Lichvar 1.2-2.20130719git46db40 +- update to 20130719git46db40 +- drop old systemd scriptlets +- add man page link for ptp4l.conf + +* Mon Apr 22 2013 Miroslav Lichvar 1.2-1 +- update to 1.2 + +* Mon Feb 18 2013 Miroslav Lichvar 1.1-1 +- update to 1.1 +- log phc2sys output + +* Thu Feb 14 2013 Fedora Release Engineering - 1.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Thu Dec 13 2012 Miroslav Lichvar 1.0-1 +- update to 1.0 + +* Fri Nov 09 2012 Miroslav Lichvar 0-0.3.20121109git4e8107 +- update to 20121109git4e8107 +- install unchanged default.cfg as ptp4l.conf +- drop conflicts from phc2sys service + +* Fri Sep 21 2012 Miroslav Lichvar 0-0.2.20120920git6ce135 +- fix issues found in package review (#859193) + +* Thu Sep 20 2012 Miroslav Lichvar 0-0.1.20120920git6ce135 +- initial release diff --git a/linuxptp.te b/linuxptp.te new file mode 100644 index 0000000..fc8c2f2 --- /dev/null +++ b/linuxptp.te @@ -0,0 +1,201 @@ +policy_module(linuxptp, 1.0.0) + + +######################################## +# +# Declarations +# + +type timemaster_t; +type timemaster_exec_t; +init_daemon_domain(timemaster_t, timemaster_exec_t) + +type timemaster_var_run_t; +files_pid_file(timemaster_var_run_t) + +type timemaster_tmpfs_t; +files_tmpfs_file(timemaster_tmpfs_t) + +type timemaster_unit_file_t; +systemd_unit_file(timemaster_unit_file_t) + +type phc2sys_t; +type phc2sys_exec_t; +init_daemon_domain(phc2sys_t, phc2sys_exec_t) + +type phc2sys_unit_file_t; +systemd_unit_file(phc2sys_unit_file_t) + +type ptp4l_t; +type ptp4l_exec_t; +init_daemon_domain(ptp4l_t, ptp4l_exec_t) + +type ptp4l_unit_file_t; +systemd_unit_file(ptp4l_unit_file_t) + +######################################## +# +# timemaster local policy +# + +allow timemaster_t self:process { signal_perms setcap}; +allow timemaster_t self:fifo_file rw_fifo_file_perms; +allow timemaster_t self:capability { setuid sys_time kill setgid }; +allow timemaster_t self:unix_stream_socket create_stream_socket_perms; +allow timemaster_t self:shm create_shm_perms; +allow timemaster_t self:udp_socket create_socket_perms; + +allow timemaster_t ptp4l_t:process signal; +allow timemaster_t phc2sys_t:process signal; + +allow timemaster_t ptp4l_t:shm rw_shm_perms; + +manage_dirs_pattern(timemaster_t, timemaster_var_run_t, timemaster_var_run_t) +manage_files_pattern(timemaster_t, timemaster_var_run_t, timemaster_var_run_t) +manage_sock_files_pattern(timemaster_t, timemaster_var_run_t, timemaster_var_run_t) +files_pid_filetrans(timemaster_t, timemaster_var_run_t, { dir file sock_file }) + +manage_dirs_pattern(timemaster_t, timemaster_tmpfs_t, timemaster_tmpfs_t) +manage_files_pattern(timemaster_t, timemaster_tmpfs_t, timemaster_tmpfs_t) +fs_tmpfs_filetrans(timemaster_t, timemaster_tmpfs_t, { dir file }) + +kernel_read_network_state(timemaster_t) + +auth_use_nsswitch(timemaster_t) + +corenet_udp_bind_generic_node(timemaster_t) +corenet_udp_bind_ntp_port(timemaster_t) + +dev_read_urand(timemaster_t) +dev_list_sysfs(timemaster_t) +#dev_write_sysfs(timemaster_t) +write_files_pattern(timemaster_t, sysfs_t, sysfs_t) +read_lnk_files_pattern(timemaster_t, sysfs_t, sysfs_t) + +logging_send_syslog_msg(timemaster_t) + +sysnet_read_config(timemaster_t) + +optional_policy(` + ntp_domtrans(timemaster_t) + ntp_signal(timemaster_t) +') + +optional_policy(` + chronyd_dgram_send(timemaster_t) + chronyd_domtrans(timemaster_t) + chronyd_rw_shm(timemaster_t) +') + +optional_policy(` + gpsd_rw_shm(timemaster_t) +') + + +optional_policy(` + chronyd_signal(timemaster_t) +') + + +optional_policy(` + linuxptp_domtrans_ptp4l(timemaster_t) +') + +optional_policy(` + linuxptp_domtrans_phc2sys(timemaster_t) +') + +######################################## +# +# phc2sys local policy +# + +allow phc2sys_t self:capability sys_time; +allow phc2sys_t self:fifo_file rw_fifo_file_perms; +allow phc2sys_t self:unix_stream_socket create_stream_socket_perms; +allow phc2sys_t self:shm create_shm_perms; +allow phc2sys_t self:udp_socket create_socket_perms; + +allow phc2sys_t ptp4l_t:unix_dgram_socket sendto; + +allow phc2sys_t timemaster_t:shm rw_shm_perms; + +manage_dirs_pattern(phc2sys_t, timemaster_var_run_t, timemaster_var_run_t) +manage_files_pattern(phc2sys_t, timemaster_var_run_t, timemaster_var_run_t) +manage_sock_files_pattern(phc2sys_t, timemaster_var_run_t, timemaster_var_run_t) +files_pid_filetrans(phc2sys_t, timemaster_var_run_t, { dir file sock_file }) + +manage_dirs_pattern(phc2sys_t, timemaster_tmpfs_t, timemaster_tmpfs_t) +manage_files_pattern(phc2sys_t, timemaster_tmpfs_t, timemaster_tmpfs_t) +fs_tmpfs_filetrans(phc2sys_t, timemaster_tmpfs_t, { dir file }) + +dev_rw_realtime_clock(phc2sys_t) + +logging_send_syslog_msg(phc2sys_t) + +optional_policy(` + chronyd_dgram_send(phc2sys_t) + chronyd_rw_shm(phc2sys_t) +') + +optional_policy(` + gpsd_rw_shm(phc2sys_t) +') + +optional_policy(` + ntp_rw_shm(phc2sys_t) +') + +optional_policy(` + ptp4l_rw_shm(phc2sys_t) +') + +######################################## +# +# ptp4l local policy +# + +allow ptp4l_t self:fifo_file rw_fifo_file_perms; +allow ptp4l_t self:netlink_generic_socket create_socket_perms; +allow ptp4l_t self:packet_socket create_socket_perms; +allow ptp4l_t self:unix_stream_socket create_stream_socket_perms; +allow ptp4l_t self:shm create_shm_perms; +allow ptp4l_t self:udp_socket create_socket_perms; +allow ptp4l_t self:capability { net_admin net_raw sys_admin sys_time }; +allow ptp4l_t self:capability2 { bpf wake_alarm }; +allow ptp4l_t self:netlink_route_socket rw_netlink_socket_perms; + +allow ptp4l_t phc2sys_t:unix_dgram_socket sendto; + +manage_dirs_pattern(ptp4l_t, timemaster_var_run_t, timemaster_var_run_t) +manage_files_pattern(ptp4l_t, timemaster_var_run_t, timemaster_var_run_t) +manage_sock_files_pattern(ptp4l_t, timemaster_var_run_t, timemaster_var_run_t) +files_pid_filetrans(ptp4l_t, timemaster_var_run_t, { dir file sock_file }) + +manage_dirs_pattern(ptp4l_t, timemaster_tmpfs_t, timemaster_tmpfs_t) +manage_files_pattern(ptp4l_t, timemaster_tmpfs_t, timemaster_tmpfs_t) +fs_tmpfs_filetrans(ptp4l_t, timemaster_tmpfs_t, { dir file }) + +corenet_udp_bind_generic_node(ptp4l_t) +corenet_udp_bind_ptp_event_port(ptp4l_t) +corenet_udp_bind_reserved_port(ptp4l_t) + +kernel_read_network_state(ptp4l_t) +kernel_request_load_module(ptp4l_t) + +dev_rw_realtime_clock(ptp4l_t) + +files_write_generic_pid_sockets(ptp4l_t) + +logging_send_syslog_msg(ptp4l_t) + +userdom_users_dgram_send(ptp4l_t) + +optional_policy(` + chronyd_dgram_send(ptp4l_t) + chronyd_rw_shm(ptp4l_t) +') + +optional_policy(` + gpsd_rw_shm(ptp4l_t) +') diff --git a/phc2sys.service b/phc2sys.service new file mode 100644 index 0000000..eadc258 --- /dev/null +++ b/phc2sys.service @@ -0,0 +1,36 @@ +[Unit] +Description=Synchronize system clock or PTP hardware clock (PHC) +After=ntpdate.service ptp4l.service + +[Service] +Type=simple +EnvironmentFile=-/etc/sysconfig/phc2sys +ExecStart=/usr/sbin/phc2sys $OPTIONS + +CapabilityBoundingSet=CAP_SYS_TIME +DeviceAllow=char-pps rw +DeviceAllow=char-ptp rw +DevicePolicy=closed +LockPersonality=yes +MemoryDenyWriteExecute=yes +# This does not work with selinux +#NoNewPrivileges=yes +PrivateTmp=yes +ProtectControlGroups=yes +ProtectHome=yes +ProtectHostname=yes +ProtectKernelLogs=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +ProtectProc=invisible +ProtectSystem=strict +ReadWritePaths=/run +RestrictAddressFamilies=AF_UNIX +RestrictNamespaces=yes +RestrictSUIDSGID=yes +SystemCallArchitectures=native +SystemCallFilter=~@cpu-emulation @debug @module @mount @obsolete @raw-io +SystemCallFilter=~@reboot @resources @swap + +[Install] +WantedBy=multi-user.target diff --git a/ptp4l.conf b/ptp4l.conf new file mode 100644 index 0000000..ef5e0b0 --- /dev/null +++ b/ptp4l.conf @@ -0,0 +1,13 @@ +# For more information about this file, see the ptp4l(8) man page. +# Examples are available in /usr/share/doc/linuxptp/configs. + +[global] +domainNumber 0 +clientOnly 1 +time_stamping hardware +logging_level 6 +summary_interval 0 + +[eth0] +network_transport UDPv4 +hybrid_e2e 0 diff --git a/ptp4l.service b/ptp4l.service new file mode 100644 index 0000000..5b08e3d --- /dev/null +++ b/ptp4l.service @@ -0,0 +1,38 @@ +[Unit] +Description=Precision Time Protocol (PTP) service +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +EnvironmentFile=-/etc/sysconfig/ptp4l +ExecStart=/usr/sbin/ptp4l $OPTIONS + +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW +CapabilityBoundingSet=CAP_SYS_ADMIN CAP_SYS_TIME +DeviceAllow=char-pps rw +DeviceAllow=char-ptp rw +DevicePolicy=closed +LockPersonality=yes +MemoryDenyWriteExecute=yes +# This does not work with selinux +#NoNewPrivileges=yes +PrivateTmp=yes +ProtectControlGroups=yes +ProtectHome=yes +ProtectHostname=yes +ProtectKernelLogs=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +ProtectProc=invisible +ProtectSystem=strict +ReadWritePaths=/run +RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_PACKET AF_UNIX +RestrictNamespaces=yes +RestrictSUIDSGID=yes +SystemCallArchitectures=native +SystemCallFilter=~@cpu-emulation @debug @module @mount @obsolete @raw-io +SystemCallFilter=~@reboot @resources @swap + +[Install] +WantedBy=multi-user.target diff --git a/sources b/sources new file mode 100644 index 0000000..b6d648c --- /dev/null +++ b/sources @@ -0,0 +1,3 @@ +SHA512 (clknetsim-64df92.tar.gz) = 91b7a9c9d4e8eaa8903f1f612cdaa2865d094e1c3531e039da9ad75595f4f4cd6fdbce9afdb0dafa18573d8afcb33a0e101170fc02c6585a231133a10b0890ff +SHA512 (linuxptp-4.4.tgz) = f9c8ac0c812d9829b3bc4595412afbeea0cade4937c46efbe47789d0ced38894a65f38a174a65a59c51b4d85a7bbf970b5d575ae1389c504fbd36eb7f96bd282 +SHA512 (linuxptp-testsuite-d27dbd.tar.gz) = e289f63d522eaac3deb1db81442805fb602ae5423c02afb2200e59518e9c3db8dcaa00e42a57f0d81d51bb2e7cbd4b82c1d3522abbb5e5569cfd795ba403d659 diff --git a/SOURCES/timemaster.conf b/timemaster.conf similarity index 78% rename from SOURCES/timemaster.conf rename to timemaster.conf index fd8e77e..1476209 100644 --- a/SOURCES/timemaster.conf +++ b/timemaster.conf @@ -14,18 +14,11 @@ ntp_program chronyd [chrony.conf] include /etc/chrony.conf -[ntp.conf] -includefile /etc/ntp.conf - [ptp4l.conf] [chronyd] path /usr/sbin/chronyd -[ntpd] -path /usr/sbin/ntpd -options -u ntp:ntp -g - [phc2sys] path /usr/sbin/phc2sys diff --git a/timemaster.service b/timemaster.service new file mode 100644 index 0000000..5b722fc --- /dev/null +++ b/timemaster.service @@ -0,0 +1,40 @@ +[Unit] +Description=Synchronize system clock to NTP and PTP time sources +After=chronyd.service ntpd.service ntpdate.service sntp.service network-online.target +Conflicts=chronyd.service ntpd.service phc2sys.service ptp4l.service +Wants=network-online.target + +[Service] +Type=simple +ExecStart=/usr/sbin/timemaster -f /etc/timemaster.conf +RuntimeDirectory=timemaster + +CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE +CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_KILL CAP_LEASE CAP_LINUX_IMMUTABLE +CapabilityBoundingSet=~CAP_MAC_ADMIN CAP_MAC_OVERRIDE CAP_MKNOD +CapabilityBoundingSet=~CAP_SYS_BOOT CAP_SYS_CHROOT CAP_SYS_MODULE CAP_SYS_PACCT +CapabilityBoundingSet=~CAP_SYS_PTRACE CAP_SYS_RAWIO CAP_SYS_TTY_CONFIG CAP_WAKE_ALARM +DeviceAllow=char-pps rw +DeviceAllow=char-ptp rw +DeviceAllow=char-rtc rw +DevicePolicy=closed +LockPersonality=yes +MemoryDenyWriteExecute=yes +PrivateTmp=yes +ProtectControlGroups=yes +ProtectHome=yes +ProtectHostname=yes +ProtectKernelLogs=yes +ProtectKernelModules=yes +ProtectKernelTunables=yes +ProtectProc=invisible +ProtectSystem=strict +ReadWritePaths=/run/timemaster /var/lib/chrony -/var/log -/var/spool +RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_PACKET AF_UNIX +RestrictNamespaces=yes +RestrictSUIDSGID=yes +SystemCallArchitectures=native +SystemCallFilter=~@cpu-emulation @debug @module @mount @obsolete @raw-io @reboot @swap + +[Install] +WantedBy=multi-user.target