From 615b7e880d115cb4d1f36c3bee0b8071cfee0728 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Wed, 25 Jun 2025 08:03:53 +0000 Subject: [PATCH] import OL linuxptp-4.4-1.el9_6.2 --- .gitignore | 6 +- .linuxptp.metadata | 6 +- SOURCES/linuxptp-addropts.patch | 176 -------------- SOURCES/linuxptp-externalgm.patch | 275 ++++++++++++++++++++++ SOURCES/linuxptp-externalpps.patch | 149 ++++++++++++ SOURCES/linuxptp-holdover.patch | 360 ---------------------------- SOURCES/linuxptp-lstab.patch | 75 ------ SOURCES/linuxptp-nmeadelay.patch | 365 ----------------------------- SOURCES/linuxptp-nmeadelay2.patch | 83 ------- SOURCES/linuxptp-nmealeap.patch | 76 ------ SOURCES/linuxptp-nmeareset.patch | 25 -- SOURCES/linuxptp-nowait.patch | 91 ++++++- SOURCES/linuxptp-ptpver.patch | 60 +++-- SOURCES/linuxptp-staticauto.patch | 302 ++++++++++++++++++++++++ SOURCES/linuxptp-subscribe.patch | 26 -- SOURCES/linuxptp-udpaddr.patch | 85 +++++++ SPECS/linuxptp.spec | 63 ++--- 17 files changed, 979 insertions(+), 1244 deletions(-) delete mode 100644 SOURCES/linuxptp-addropts.patch create mode 100644 SOURCES/linuxptp-externalgm.patch create mode 100644 SOURCES/linuxptp-externalpps.patch delete mode 100644 SOURCES/linuxptp-holdover.patch delete mode 100644 SOURCES/linuxptp-lstab.patch delete mode 100644 SOURCES/linuxptp-nmeadelay.patch delete mode 100644 SOURCES/linuxptp-nmeadelay2.patch delete mode 100644 SOURCES/linuxptp-nmealeap.patch delete mode 100644 SOURCES/linuxptp-nmeareset.patch create mode 100644 SOURCES/linuxptp-staticauto.patch delete mode 100644 SOURCES/linuxptp-subscribe.patch create mode 100644 SOURCES/linuxptp-udpaddr.patch diff --git a/.gitignore b/.gitignore index fe3d107..9e6c8f6 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 +SOURCES/clknetsim-64df92.tar.gz +SOURCES/linuxptp-4.4.tgz +SOURCES/linuxptp-testsuite-d27dbd.tar.gz diff --git a/.linuxptp.metadata b/.linuxptp.metadata index c9e495c..0eeb922 100644 --- a/.linuxptp.metadata +++ b/.linuxptp.metadata @@ -1,3 +1,3 @@ -3ae72eb0ddafd8d8aeea7eac382d6e4a958717ef SOURCES/clknetsim-5d1dc0.tar.gz -309e6ab1fa3f61b3deb1735c3082dc2070870be1 SOURCES/linuxptp-4.2.tgz -7594d0705a1a648d5f7380d476bb3afebff21f6c SOURCES/linuxptp-testsuite-bf8ead.tar.gz +acb5ea319dfe96edd43033b35f025b3557b5e8a7 SOURCES/clknetsim-64df92.tar.gz +f35d56a2471359856843f7e703e5e8c681a66f0d SOURCES/linuxptp-4.4.tgz +8db14fbc7bdde436f2e957e77319569614ccf625 SOURCES/linuxptp-testsuite-d27dbd.tar.gz diff --git a/SOURCES/linuxptp-addropts.patch b/SOURCES/linuxptp-addropts.patch deleted file mode 100644 index 65bd4ae..0000000 --- a/SOURCES/linuxptp-addropts.patch +++ /dev/null @@ -1,176 +0,0 @@ -commit 073faba77e8a82c54210941cee6023dc9e719329 -Author: Miroslav Lichvar -Date: Thu Apr 25 14:25:57 2024 +0200 - - udp+udp6: Make IP addresses configurable. - - Allow configuration of the multicast IPv4/IPv6 addresses, which can be - useful for testing. This complements the L2-specific ptp_dst_mac and - p2p_dst_mac options. - - [ RPC: removed unused #defines PTP_PRIMARY_MCAST_IPADDR and PTP_PDELAY_MCAST_IPADDR ] - - Signed-off-by: Miroslav Lichvar - Signed-off-by: Richard Cochran - -diff --git a/config.c b/config.c -index d7775c0..c220a3e 100644 ---- a/config.c -+++ b/config.c -@@ -299,6 +299,9 @@ struct config_item config_tab[] = { - GLOB_ITEM_INT("offsetScaledLogVariance", 0xffff, 0, UINT16_MAX), - PORT_ITEM_INT("operLogPdelayReqInterval", 0, INT8_MIN, INT8_MAX), - PORT_ITEM_INT("operLogSyncInterval", 0, INT8_MIN, INT8_MAX), -+ PORT_ITEM_STR("p2p_dst_ipv4", "224.0.0.107"), -+ PORT_ITEM_STR("p2p_dst_ipv6", "FF02:0:0:0:0:0:0:6B"), -+ PORT_ITEM_STR("p2p_dst_mac", "01:80:C2:00:00:0E"), - PORT_ITEM_INT("path_trace_enabled", 0, 0, 1), - PORT_ITEM_INT("phc_index", -1, -1, INT_MAX), - GLOB_ITEM_DBL("pi_integral_const", 0.0, 0.0, DBL_MAX), -@@ -317,8 +320,9 @@ struct config_item config_tab[] = { - GLOB_ITEM_INT("priority1", 128, 0, UINT8_MAX), - GLOB_ITEM_INT("priority2", 128, 0, UINT8_MAX), - GLOB_ITEM_STR("productDescription", ";;"), -+ PORT_ITEM_STR("ptp_dst_ipv4", "224.0.1.129"), -+ PORT_ITEM_STR("ptp_dst_ipv6", "FF0E:0:0:0:0:0:0:181"), - 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", 0, 0, 1), - GLOB_ITEM_STR("refclock_sock_address", "/var/run/refclock.ptp.sock"), - GLOB_ITEM_STR("revisionData", ";;"), -diff --git a/configs/default.cfg b/configs/default.cfg -index 8f94c16..54ce62a 100644 ---- a/configs/default.cfg -+++ b/configs/default.cfg -@@ -94,6 +94,10 @@ write_phase_mode 0 - # Transport options - # - transportSpecific 0x0 -+ptp_dst_ipv4 224.0.1.129 -+p2p_dst_ipv4 224.0.0.107 -+ptp_dst_ipv6 FF0E:0:0:0:0:0:0:181 -+p2p_dst_ipv6 FF02:0:0:0:0:0:0:6B - ptp_dst_mac 01:1B:19:00:00:00 - p2p_dst_mac 01:80:C2:00:00:0E - udp_ttl 1 -diff --git a/ptp4l.8 b/ptp4l.8 -index c59b0b4..a4eb603 100644 ---- a/ptp4l.8 -+++ b/ptp4l.8 -@@ -397,6 +397,27 @@ This value may be changed dynamically using the - POWER_PROFILE_SETTINGS_NP management message. - The default is "none". - -+.TP -+.B ptp_dst_ipv4 -+The IPv4 address to which PTP messages should be sent. -+Relevant only with UDPv4 transport. The default is 224.0.1.129. -+ -+.TP -+.B p2p_dst_ipv4 -+The IPv4 address to which peer delay messages should be sent. -+Relevant only with UDPv4 transport. The default is 224.0.0.107. -+ -+.TP -+.B ptp_dst_ipv6 -+The IPv6 address to which PTP messages should be sent. -+The second byte of the address is substituted with udp6_scope. -+Relevant only with UDPv6 transport. The default is FF0E:0:0:0:0:0:0:181. -+ -+.TP -+.B p2p_dst_ipv6 -+The IPv6 address to which peer delay messages should be sent. -+Relevant only with UDPv6 transport. The default is FF02:0:0:0:0:0:0:6B. -+ - .TP - .B ptp_dst_mac - The MAC address to which PTP messages should be sent. -diff --git a/udp.c b/udp.c -index 7c9402e..38d0ec4 100644 ---- a/udp.c -+++ b/udp.c -@@ -39,8 +39,6 @@ - - #define EVENT_PORT 319 - #define GENERAL_PORT 320 --#define PTP_PRIMARY_MCAST_IPADDR "224.0.1.129" --#define PTP_PDELAY_MCAST_IPADDR "224.0.0.107" - - struct udp { - struct transport t; -@@ -157,6 +155,7 @@ static int udp_open(struct transport *t, struct interface *iface, - const char *name = interface_name(iface); - uint8_t event_dscp, general_dscp; - int efd, gfd, ttl; -+ char *str; - - ttl = config_get_int(t->cfg, name, "udp_ttl"); - udp->mac.len = 0; -@@ -165,11 +164,17 @@ static int udp_open(struct transport *t, struct interface *iface, - udp->ip.len = 0; - sk_interface_addr(name, AF_INET, &udp->ip); - -- if (!inet_aton(PTP_PRIMARY_MCAST_IPADDR, &mcast_addr[MC_PRIMARY])) -+ str = config_get_string(t->cfg, name, "ptp_dst_ipv4"); -+ if (!inet_aton(str, &mcast_addr[MC_PRIMARY])) { -+ pr_err("invalid ptp_dst_ipv4 %s", str); - return -1; -+ } - -- if (!inet_aton(PTP_PDELAY_MCAST_IPADDR, &mcast_addr[MC_PDELAY])) -+ str = config_get_string(t->cfg, name, "p2p_dst_ipv4"); -+ if (!inet_aton(str, &mcast_addr[MC_PDELAY])) { -+ pr_err("invalid p2p_dst_ipv4 %s", str); - return -1; -+ } - - efd = open_socket(name, mcast_addr, EVENT_PORT, ttl); - if (efd < 0) -diff --git a/udp6.c b/udp6.c -index bde1710..188d20e 100644 ---- a/udp6.c -+++ b/udp6.c -@@ -40,10 +40,6 @@ - #define EVENT_PORT 319 - #define GENERAL_PORT 320 - --/* The 0x0e in second byte is substituted with udp6_scope at runtime. */ --#define PTP_PRIMARY_MCAST_IP6ADDR "FF0E:0:0:0:0:0:0:181" --#define PTP_PDELAY_MCAST_IP6ADDR "FF02:0:0:0:0:0:0:6B" -- - enum { MC_PRIMARY, MC_PDELAY }; - - struct udp6 { -@@ -167,6 +163,7 @@ static int udp6_open(struct transport *t, struct interface *iface, - const char *name = interface_name(iface); - uint8_t event_dscp, general_dscp; - int efd, gfd, hop_limit; -+ char *str; - - hop_limit = config_get_int(t->cfg, name, "udp_ttl"); - udp6->mac.len = 0; -@@ -175,16 +172,20 @@ static int udp6_open(struct transport *t, struct interface *iface, - udp6->ip.len = 0; - sk_interface_addr(name, AF_INET6, &udp6->ip); - -- if (1 != inet_pton(AF_INET6, PTP_PRIMARY_MCAST_IP6ADDR, -- &udp6->mc6_addr[MC_PRIMARY])) -+ str = config_get_string(t->cfg, name, "ptp_dst_ipv6"); -+ if (1 != inet_pton(AF_INET6, str, &udp6->mc6_addr[MC_PRIMARY])) { -+ pr_err("invalid ptp_dst_ipv6 %s", str); - return -1; -+ } - - udp6->mc6_addr[MC_PRIMARY].s6_addr[1] = config_get_int(t->cfg, name, - "udp6_scope"); - -- if (1 != inet_pton(AF_INET6, PTP_PDELAY_MCAST_IP6ADDR, -- &udp6->mc6_addr[MC_PDELAY])) -+ str = config_get_string(t->cfg, name, "p2p_dst_ipv6"); -+ if (1 != inet_pton(AF_INET6, str, &udp6->mc6_addr[MC_PDELAY])) { -+ pr_err("invalid p2p_dst_ipv6 %s", str); - return -1; -+ } - - efd = open_socket_ipv6(name, udp6->mc6_addr, EVENT_PORT, &udp6->index, - hop_limit); diff --git a/SOURCES/linuxptp-externalgm.patch b/SOURCES/linuxptp-externalgm.patch new file mode 100644 index 0000000..17719c8 --- /dev/null +++ b/SOURCES/linuxptp-externalgm.patch @@ -0,0 +1,275 @@ +commit a0fb624d9a2bb804d85f4597b1249123c7978fed +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 d76e19e4ed4a4c1892b98124ffb66dba354f76ac +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/SOURCES/linuxptp-externalpps.patch b/SOURCES/linuxptp-externalpps.patch new file mode 100644 index 0000000..b8f1cb8 --- /dev/null +++ b/SOURCES/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/SOURCES/linuxptp-holdover.patch b/SOURCES/linuxptp-holdover.patch deleted file mode 100644 index b6843d8..0000000 --- a/SOURCES/linuxptp-holdover.patch +++ /dev/null @@ -1,360 +0,0 @@ -commit c7acd4b5bdb95e45d93833ffaac9cac51dfe934b -Author: Miroslav Lichvar -Date: Thu May 16 15:52:48 2024 +0200 - - ts2phc: Avoid unnecessary call of getppstime(). - - Don't get the ToD timestamp for the pulse polarity detection if it won't - be needed (i.e. extts_polarity is not "both"). This allows PPS - timestamps to be saved even when the ToD source fails. - - Signed-off-by: Miroslav Lichvar - -diff --git a/ts2phc_pps_sink.c b/ts2phc_pps_sink.c -index 0d399b8..76912a2 100644 ---- a/ts2phc_pps_sink.c -+++ b/ts2phc_pps_sink.c -@@ -277,21 +277,22 @@ static enum extts_result ts2phc_pps_sink_event(struct ts2phc_private *priv, - goto out; - } - -- err = ts2phc_pps_source_getppstime(priv->src, &source_ts); -- if (err < 0) { -- pr_debug("source ts not valid"); -- return 0; -- } -- -- if (sink->polarity == (PTP_RISING_EDGE | PTP_FALLING_EDGE) && -- ts2phc_pps_sink_ignore(priv, sink, source_ts)) { -+ if (sink->polarity == (PTP_RISING_EDGE | PTP_FALLING_EDGE)) { -+ err = ts2phc_pps_source_getppstime(priv->src, &source_ts); -+ if (err < 0) { -+ pr_debug("source ts not valid"); -+ return 0; -+ } - -- pr_debug("%s SKIP extts index %u at %lld.%09u src %" PRIi64 ".%ld", -- sink->name, event.index, event.t.sec, event.t.nsec, -- (int64_t) source_ts.tv_sec, source_ts.tv_nsec); -+ if (ts2phc_pps_sink_ignore(priv, sink, source_ts)) { -+ pr_debug("%s SKIP extts index %u at %lld.%09u src %" PRIi64 ".%ld", -+ sink->name, event.index, event.t.sec, -+ event.t.nsec, (int64_t)source_ts.tv_sec, -+ source_ts.tv_nsec); - -- result = EXTTS_IGNORE; -- goto out; -+ result = EXTTS_IGNORE; -+ goto out; -+ } - } - - out: - -commit 9880cccc928351a42a3fa9e018949442aca7ddae -Author: Miroslav Lichvar -Date: Thu May 16 15:52:49 2024 +0200 - - ts2phc: Add holdover support. - - If the external PPS signal is generated by a clock with better long-term - stability than the clock synchronizing to it, it can work as a good time - source for some period of time after losing its own time source (e.g. - GPS receiver losing its signal). - - Add an option to specify a holdover interval where ts2phc can continue - synchronizing the clock without any ToD information. Allow that only in - the LOCKED_STABLE servo state, which needs to be enabled by the - servo_num_offset_values option. - - This is supported only in the non-automatic mode and when the pulse - polarity detection is disabled. - - Signed-off-by: Miroslav Lichvar - -diff --git a/config.c b/config.c -index c220a3e..58481db 100644 ---- a/config.c -+++ b/config.c -@@ -344,6 +344,7 @@ struct config_item config_tab[] = { - PORT_ITEM_INT("ts2phc.channel", 0, 0, INT_MAX), - 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), - PORT_ITEM_INT("ts2phc.master", 0, 0, 1), - PORT_ITEM_INT("ts2phc.nmea_baudrate", 9600, 300, INT_MAX), - GLOB_ITEM_STR("ts2phc.nmea_remote_host", ""), -diff --git a/ts2phc.8 b/ts2phc.8 -index 852a527..bcc6f61 100644 ---- a/ts2phc.8 -+++ b/ts2phc.8 -@@ -168,6 +168,16 @@ by changing the clock frequency instead of stepping the clock. When - set to 0.0, the servo will never step the clock except on start. - The default is 0.0. - -+.TP -+.B ts2phc.holdover -+The holdover interval, specified in seconds. When the ToD information stops -+working (e.g. GNSS receiver lost its fix), ts2phc is allowed for the specified -+interval to continue synchronizing the target clock as long as the servo is in -+the SERVO_LOCKED_STABLE state. The servo state needs be enabled by the -+\fBservo_num_offset_values\fP option. The holdover is not supported with the -+\fB-a\fP option and when \fBts2phc.extts_polarity\fP is set to \fIboth\fP. -+The default is 0 (disabled). -+ - .TP - .B ts2phc.nmea_remote_host, ts2phc.nmea_remote_port - Specifies the remote host providing ToD information when using the -diff --git a/ts2phc.c b/ts2phc.c -index 4817c85..d552e0f 100644 ---- a/ts2phc.c -+++ b/ts2phc.c -@@ -440,9 +440,10 @@ static int ts2phc_pps_source_implicit_tstamp(struct ts2phc_private *priv, - - static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg) - { -+ struct timespec source_ts, now; - tmv_t source_tmv; - struct ts2phc_clock *c; -- int valid, err; -+ int holdover, valid; - - if (autocfg) { - if (!priv->ref_clock) { -@@ -456,9 +457,20 @@ static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg) - return; - } - } else { -- err = ts2phc_pps_source_implicit_tstamp(priv, &source_tmv); -- if (err < 0) -+ valid = !ts2phc_pps_source_implicit_tstamp(priv, &source_tmv); -+ } -+ -+ if (valid) { -+ priv->holdover_start = 0; -+ holdover = 0; -+ } else { -+ clock_gettime(CLOCK_MONOTONIC, &now); -+ -+ if (!priv->holdover_start) -+ priv->holdover_start = now.tv_sec; -+ if (now.tv_sec >= priv->holdover_start + priv->holdover_length) - return; -+ holdover = 1; - } - - LIST_FOREACH(c, &priv->clocks, list) { -@@ -475,6 +487,16 @@ static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg) - continue; - } - -+ if (holdover) { -+ if (c->servo_state != SERVO_LOCKED_STABLE) -+ continue; -+ source_ts = tmv_to_timespec(ts); -+ if (source_ts.tv_nsec > NS_PER_SEC / 2) -+ source_ts.tv_sec++; -+ source_ts.tv_nsec = 0; -+ source_tmv = timespec_to_tmv(source_ts); -+ } -+ - offset = tmv_to_nanoseconds(tmv_sub(ts, source_tmv)); - - if (c->no_adj) { -@@ -486,8 +508,15 @@ static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg) - adj = servo_sample(c->servo, offset, tmv_to_nanoseconds(ts), - SAMPLE_WEIGHT, &c->servo_state); - -- pr_info("%s offset %10" PRId64 " s%d freq %+7.0f", -- c->name, offset, c->servo_state, adj); -+ if (holdover && c->servo_state != SERVO_LOCKED_STABLE) { -+ pr_info("%s lost holdover lock (offset %10" PRId64 ")", -+ c->name, offset); -+ continue; -+ } -+ -+ pr_info("%s offset %10" PRId64 " s%d freq %+7.0f%s", -+ c->name, offset, c->servo_state, adj, -+ holdover ? " holdover" : ""); - - switch (c->servo_state) { - case SERVO_UNLOCKED: -@@ -751,6 +780,9 @@ int main(int argc, char *argv[]) - return -1; - } - -+ priv.holdover_length = config_get_int(cfg, NULL, "ts2phc.holdover"); -+ priv.holdover_start = 0; -+ - while (is_running()) { - struct ts2phc_clock *c; - -diff --git a/ts2phc.h b/ts2phc.h -index 4833ded..5dbde9b 100644 ---- a/ts2phc.h -+++ b/ts2phc.h -@@ -55,6 +55,8 @@ struct ts2phc_private { - bool state_changed; - LIST_HEAD(port_head, ts2phc_port) ports; - LIST_HEAD(clock_head, ts2phc_clock) clocks; -+ int holdover_length; -+ time_t holdover_start; - }; - - struct ts2phc_clock *ts2phc_clock_add(struct ts2phc_private *priv, -commit bf237fd55d4983a42d9344890dd861f18bea70ca -Author: Miroslav Lichvar -Date: Thu Jul 25 12:43:59 2024 +0200 - - ts2phc: Describe servo options in man page. - - Copy and adapt missing servo options used by ts2phc from the ptp4l man - page. - - Signed-off-by: Miroslav Lichvar - -diff --git a/ts2phc.8 b/ts2phc.8 -index bcc6f61..4c54576 100644 ---- a/ts2phc.8 -+++ b/ts2phc.8 -@@ -117,6 +117,16 @@ command line option. - - .SH GLOBAL OPTIONS - -+.TP -+.B clock_servo -+The servo which is used to synchronize the local clock. Valid values -+are "pi" for a PI controller, "linreg" for an adaptive controller -+using linear regression, "ntpshm" and "refclock_sock" for the NTP SHM and -+chrony SOCK reference clocks respectively to allow another process to -+synchronize the local clock, and "nullf" for a servo that always dials -+frequency offset zero (for use in SyncE nodes). -+The default is "pi". -+ - .TP - .B first_step_threshold - The maximum offset, specified in seconds, that the servo will correct by -@@ -162,12 +172,64 @@ with the log level of the message as a number. The default is an empty string - argument). - - .TP --.B step_threshold --The maximum offset, specified in seconds, that the servo will correct --by changing the clock frequency instead of stepping the clock. When --set to 0.0, the servo will never step the clock except on start. -+.B ntpshm_segment -+The number of the SHM segment used by ntpshm servo. -+The default is 0. -+ -+.TP -+.B pi_integral_const -+The integral constant of the PI controller. When set to 0.0, the -+integral constant will be set by the following formula from the current -+sync interval. -+The default is 0.0. -+ -+ki = min(ki_scale * sync^ki_exponent, ki_norm_max / sync) -+ -+.TP -+.B pi_integral_exponent -+The ki_exponent constant in the formula used to set the integral constant of -+the PI controller from the sync interval. -+The default is 0.4. -+ -+.TP -+.B pi_integral_norm_max -+The ki_norm_max constant in the formula used to set the integral constant of -+the PI controller from the sync interval. -+The default is 0.3. -+ -+.TP -+.B pi_integral_scale -+The ki_scale constant in the formula used to set the integral constant of -+the PI controller from the sync interval. -+The default is 0.3. -+ -+.TP -+.B pi_proportional_const -+The proportional constant of the PI controller. When set to 0.0, the -+proportional constant will be set by the following formula from the current -+sync interval. - The default is 0.0. - -+kp = min(kp_scale * sync^kp_exponent, kp_norm_max / sync) -+ -+.TP -+.B pi_proportional_exponent -+The kp_exponent constant in the formula used to set the proportional constant of -+the PI controller from the sync interval. -+The default is \-0.3. -+ -+.TP -+.B pi_proportional_norm_max -+The kp_norm_max constant in the formula used to set the proportional constant of -+the PI controller from the sync interval. -+The default is 0.7 -+ -+.TP -+.B pi_proportional_scale -+The kp_scale constant in the formula used to set the proportional constant of -+the PI controller from the sync interval. -+The default is 0.7. -+ - .TP - .B ts2phc.holdover - The holdover interval, specified in seconds. When the ToD information stops -@@ -178,6 +240,28 @@ 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 servo_num_offset_values -+The number of offset values considered in order to transition from the -+SERVO_LOCKED to the SERVO_LOCKED_STABLE state. -+The transition occurs once the last 'servo_num_offset_values' offsets -+are all below the 'servo_offset_threshold' value. -+The default value is 10. -+ -+.TP -+.B servo_offset_threshold -+The offset threshold used in order to transition from the SERVO_LOCKED -+to the SERVO_LOCKED_STABLE state. The transition occurs once the -+last 'servo_num_offset_values' offsets are all below the threshold value. -+The default value of offset_threshold is 0 (disabled). -+ -+.TP -+.B step_threshold -+The maximum offset, specified in seconds, that the servo will correct -+by changing the clock frequency instead of stepping the clock. When -+set to 0.0, the servo will never step the clock except on start. -+The default is 0.0. -+ - .TP - .B ts2phc.nmea_remote_host, ts2phc.nmea_remote_port - Specifies the remote host providing ToD information when using the - -commit 7734d2fe8ac52afaa233262548615f79021ae6ee -Author: Miroslav Lichvar -Date: Thu Jul 25 12:46:43 2024 +0200 - - ts2phc: Fix description of holdover option in man page. - - Fix the man page to explain that the LOCKED_STABLE servo state is - enabled by setting the servo_offset_threshold, not - servo_num_offset_values, which is already enabled by default. - - Signed-off-by: Miroslav Lichvar - -diff --git a/ts2phc.8 b/ts2phc.8 -index 4c54576..c0b718b 100644 ---- a/ts2phc.8 -+++ b/ts2phc.8 -@@ -236,7 +236,7 @@ The holdover interval, specified in seconds. When the ToD information stops - working (e.g. GNSS receiver lost its fix), ts2phc is allowed for the specified - interval to continue synchronizing the target clock as long as the servo is in - the SERVO_LOCKED_STABLE state. The servo state needs be enabled by the --\fBservo_num_offset_values\fP option. The holdover is not supported with the -+\fBservo_offset_threshold\fP option. The holdover is not supported with the - \fB-a\fP option and when \fBts2phc.extts_polarity\fP is set to \fIboth\fP. - The default is 0 (disabled). - 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 64c1ba1..0000000 --- a/SOURCES/linuxptp-nmeadelay.patch +++ /dev/null @@ -1,365 +0,0 @@ -commit 0c406008b530140ed6d992915a6c8a1e5abf15d5 -Author: Miroslav Lichvar -Date: Thu Jan 25 11:26:15 2024 +0100 - - ts2phc: Don't switch system clock to nanosecond mode. - - ts2phc is not synchronizing the system clock and should not switch the - clock to the nanosecond mode with adjtimex(modes=ADJ_NANO) or make any - other modifications to it. The process that is controlling the clock - (e.g. an NTP client) might not be using the nanosecond mode. - - There are two instances of the adjtimex() call in the code. One is used - only to read the clock and can be replaced with faster clock_gettime(). - The other instance is also reading the TAI offset. Instead of switching - to the nanosecond mode, change the timestamp conversion to handle both - microsecond and nanosecond modes according to the current clock status. - - Reviewed-by: Jacob Keller - Signed-off-by: Miroslav Lichvar - -diff --git a/ts2phc_generic_pps_source.c b/ts2phc_generic_pps_source.c -index d503aac..e6b8145 100644 ---- a/ts2phc_generic_pps_source.c -+++ b/ts2phc_generic_pps_source.c -@@ -38,7 +38,6 @@ static int get_ntx(struct timex *ntx) - return -1; - - memset(ntx, 0, sizeof(*ntx)); -- ntx->modes = ADJ_NANO; - code = adjtimex(ntx); - if (code == -1) { - pr_err("adjtimex failed: %m"); -@@ -93,7 +92,10 @@ static int ts2phc_generic_pps_source_getppstime(struct ts2phc_pps_source *src, - } - - ts->tv_sec = ntx.time.tv_sec + tai_offset; -- ts->tv_nsec = ntx.time.tv_usec; -+ if (ntx.status & STA_NANO) -+ ts->tv_nsec = ntx.time.tv_usec; -+ else -+ ts->tv_nsec = ntx.time.tv_usec * 1000; - - return 0; - } -diff --git a/ts2phc_nmea_pps_source.c b/ts2phc_nmea_pps_source.c -index 3a4267d..5b2e06b 100644 ---- a/ts2phc_nmea_pps_source.c -+++ b/ts2phc_nmea_pps_source.c -@@ -62,14 +62,13 @@ static int open_nmea_connection(const char *host, const char *port, - - static void *monitor_nmea_status(void *arg) - { -+ struct timespec rxtime, rxtime_rt, tmo = { 2, 0 }; - struct nmea_parser *np = nmea_parser_create(); - struct pollfd pfd = { -1, POLLIN | POLLPRI }; - char *host, input[256], *port, *ptr, *uart; - struct ts2phc_nmea_pps_source *s = arg; -- struct timespec rxtime, tmo = { 2, 0 }; - int cnt, num, parsed, baud; - struct nmea_rmc rmc; -- struct timex ntx; - - if (!np) { - pr_err("failed to create NMEA parser"); -@@ -79,8 +78,6 @@ static void *monitor_nmea_status(void *arg) - port = config_get_string(s->config, NULL, "ts2phc.nmea_remote_port"); - uart = config_get_string(s->config, NULL, "ts2phc.nmea_serialport"); - baud = config_get_int(s->config, NULL, "ts2phc.nmea_baudrate"); -- memset(&ntx, 0, sizeof(ntx)); -- ntx.modes = ADJ_NANO; - - while (is_running()) { - if (pfd.fd == -1) { -@@ -92,7 +89,7 @@ static void *monitor_nmea_status(void *arg) - } - num = poll(&pfd, 1, NMEA_TMO); - clock_gettime(CLOCK_MONOTONIC, &rxtime); -- adjtimex(&ntx); -+ clock_gettime(CLOCK_REALTIME, &rxtime_rt); - if (num < 0) { - pr_err("poll failed"); - break; -@@ -124,8 +121,7 @@ static void *monitor_nmea_status(void *arg) - if (!nmea_parse(np, ptr, cnt, &rmc, &parsed)) { - pthread_mutex_lock(&s->mutex); - s->local_monotime = rxtime; -- s->local_utctime.tv_sec = ntx.time.tv_sec; -- s->local_utctime.tv_nsec = ntx.time.tv_usec; -+ s->local_utctime = rxtime_rt; - s->rmc_utctime = rmc.ts; - s->rmc_fix_valid = rmc.fix_valid; - pthread_mutex_unlock(&s->mutex); - -commit 72b44bc885e519667a12c89d5b640484807e4946 -Author: Miroslav Lichvar -Date: Tue Jun 4 08:57:15 2024 +0200 - - ts2phc: Use CLOCK_MONOTONIC_RAW for NMEA PPS timestamp. - - In the calculation of the NMEA PPS timestamp is used an interval - measured by the CLOCK_MONOTONIC system clock. This clock may have a - large frequency error when another process (e.g. phc2sys or an NTP - client) is correcting a large time error by slewing. - - This frequency error may cause the timestamp to overflow into the next - second and cause a one-second error in the measured offset, or the wrong - edge of the pulse to be rejected. - - Switch from CLOCK_MONOTONIC to CLOCK_MONOTONIC_RAW to avoid the - impact of the system clock adjustments. - - Signed-off-by: Miroslav Lichvar - -diff --git a/ts2phc_nmea_pps_source.c b/ts2phc_nmea_pps_source.c -index 5b2e06b..7a28433 100644 ---- a/ts2phc_nmea_pps_source.c -+++ b/ts2phc_nmea_pps_source.c -@@ -88,7 +88,7 @@ static void *monitor_nmea_status(void *arg) - } - } - num = poll(&pfd, 1, NMEA_TMO); -- clock_gettime(CLOCK_MONOTONIC, &rxtime); -+ clock_gettime(CLOCK_MONOTONIC_RAW, &rxtime); - clock_gettime(CLOCK_REALTIME, &rxtime_rt); - if (num < 0) { - pr_err("poll failed"); -@@ -160,7 +160,7 @@ static int ts2phc_nmea_pps_source_getppstime(struct ts2phc_pps_source *src, - int64_t utc_time; - bool fix_valid; - -- clock_gettime(CLOCK_MONOTONIC, &now); -+ clock_gettime(CLOCK_MONOTONIC_RAW, &now); - local_t2 = timespec_to_tmv(now); - - pthread_mutex_lock(&m->mutex); - -commit 30e6c4dba892236d8cfe08dc6c55238e11504c71 -Author: Miroslav Lichvar -Date: Mon Jun 3 10:32:05 2024 +0200 - - ts2phc: Provide source type. - - Save the PPS source type in the instance and add a function to retrieve - it. This will be needed for NMEA-specific rounding of timestamps. - - Signed-off-by: Miroslav Lichvar - -diff --git a/ts2phc_pps_source.c b/ts2phc_pps_source.c -index c333f65..ae2ad46 100644 ---- a/ts2phc_pps_source.c -+++ b/ts2phc_pps_source.c -@@ -26,6 +26,8 @@ struct ts2phc_pps_source *ts2phc_pps_source_create(struct ts2phc_private *priv, - src = ts2phc_phc_pps_source_create(priv, dev); - break; - } -+ if (src) -+ src->type = type; - return src; - } - -@@ -46,3 +48,8 @@ struct ts2phc_clock *ts2phc_pps_source_get_clock(struct ts2phc_pps_source *src) - - return NULL; - } -+ -+enum ts2phc_pps_source_type ts2phc_pps_source_get_type(struct ts2phc_pps_source *src) -+{ -+ return src->type; -+} -diff --git a/ts2phc_pps_source.h b/ts2phc_pps_source.h -index 293c693..c87e3af 100644 ---- a/ts2phc_pps_source.h -+++ b/ts2phc_pps_source.h -@@ -53,4 +53,11 @@ int ts2phc_pps_source_getppstime(struct ts2phc_pps_source *src, struct timespec - - struct ts2phc_clock *ts2phc_pps_source_get_clock(struct ts2phc_pps_source *src); - -+/** -+ * Returns the type of the PPS source -+ * @param src Pointer to a source obtained via @ref ts2phc_pps_source_create(). -+ * @return The type of the clock. -+ */ -+enum ts2phc_pps_source_type ts2phc_pps_source_get_type(struct ts2phc_pps_source *src); -+ - #endif -diff --git a/ts2phc_pps_source_private.h b/ts2phc_pps_source_private.h -index 99e6a78..ea6a8ad 100644 ---- a/ts2phc_pps_source_private.h -+++ b/ts2phc_pps_source_private.h -@@ -13,6 +13,7 @@ - #include "ts2phc_pps_source.h" - - struct ts2phc_pps_source { -+ enum ts2phc_pps_source_type type; - void (*destroy)(struct ts2phc_pps_source *src); - int (*getppstime)(struct ts2phc_pps_source *src, struct timespec *ts); - struct ts2phc_clock *(*get_clock)(struct ts2phc_pps_source *src); - -commit bebd15ae90dbfcb74a33e5b428f24c733abf1134 -Author: Miroslav Lichvar -Date: Mon Jun 3 11:06:16 2024 +0200 - - ts2phc: Fix edge rejection for pulse widths over 0.5s. - - If the configured pulse width is longer than 0.5 seconds, the calculated - range of ignored offsets is too small to cover the wrong edge. Fix the - calculation of the limits to use the minimum of pulsewidth and - (1.0s - pulsewidth). A pulsewidth of 0.5s should give the shortest interval. - - Signed-off-by: Miroslav Lichvar - -diff --git a/ts2phc_pps_sink.c b/ts2phc_pps_sink.c -index 05ac225..ca9f721 100644 ---- a/ts2phc_pps_sink.c -+++ b/ts2phc_pps_sink.c -@@ -175,6 +175,8 @@ static struct ts2phc_pps_sink *ts2phc_pps_sink_create(struct ts2phc_private *pri - sink->correction = nanoseconds_to_tmv(correction); - - pulsewidth = config_get_int(cfg, device, "ts2phc.pulsewidth"); -+ if (pulsewidth > 500000000) -+ pulsewidth = 1000000000 - pulsewidth; - pulsewidth /= 2; - sink->ignore_upper = 1000000000 - pulsewidth; - sink->ignore_lower = pulsewidth; - -commit 435e9fc6ebec8daa8ab9f88c2d590e35ace9b2f6 -Author: Miroslav Lichvar -Date: Mon Jun 3 13:57:23 2024 +0200 - - ts2phc: Move upper/lower rejection limit calculation. - - The ignore_upper and ignore_lower fields of the ts2phc_pps_sink struct - are calculated when the PPS source is not known yet. Replace the fields - with the configured pulsewidth and calculate the limits locally later - when needed in ts2phc_pps_sink_ignore(). This will allow an - NMEA-specific calculation of the limits. - - Signed-off-by: Miroslav Lichvar - -diff --git a/ts2phc_pps_sink.c b/ts2phc_pps_sink.c -index ca9f721..8121afb 100644 ---- a/ts2phc_pps_sink.c -+++ b/ts2phc_pps_sink.c -@@ -30,8 +30,7 @@ struct ts2phc_pps_sink { - struct ptp_pin_desc pin_desc; - unsigned int polarity; - tmv_t correction; -- uint32_t ignore_lower; -- uint32_t ignore_upper; -+ uint32_t pulsewidth; - struct ts2phc_clock *clock; - }; - -@@ -153,8 +152,8 @@ static struct ts2phc_pps_sink *ts2phc_pps_sink_create(struct ts2phc_private *pri - struct config *cfg = priv->cfg; - struct ptp_extts_request extts; - struct ts2phc_pps_sink *sink; -- int err, pulsewidth; - int32_t correction; -+ int err; - - sink = calloc(1, sizeof(*sink)); - if (!sink) { -@@ -174,12 +173,9 @@ static struct ts2phc_pps_sink *ts2phc_pps_sink_create(struct ts2phc_private *pri - correction = config_get_int(cfg, device, "ts2phc.extts_correction"); - sink->correction = nanoseconds_to_tmv(correction); - -- pulsewidth = config_get_int(cfg, device, "ts2phc.pulsewidth"); -- if (pulsewidth > 500000000) -- pulsewidth = 1000000000 - pulsewidth; -- pulsewidth /= 2; -- sink->ignore_upper = 1000000000 - pulsewidth; -- sink->ignore_lower = pulsewidth; -+ sink->pulsewidth = config_get_int(cfg, device, "ts2phc.pulsewidth"); -+ if (sink->pulsewidth > 500000000) -+ sink->pulsewidth = 1000000000 - sink->pulsewidth; - - sink->clock = ts2phc_clock_add(priv, device); - if (!sink->clock) { -@@ -243,12 +239,16 @@ static bool ts2phc_pps_sink_ignore(struct ts2phc_private *priv, - struct timespec source_ts) - { - tmv_t source_tmv = timespec_to_tmv(source_ts); -+ uint32_t ignore_lower, ignore_upper; - - source_tmv = tmv_sub(source_tmv, priv->perout_phase); - source_ts = tmv_to_timespec(source_tmv); - -- return source_ts.tv_nsec > sink->ignore_lower && -- source_ts.tv_nsec < sink->ignore_upper; -+ ignore_upper = 1000000000 - sink->pulsewidth / 2; -+ ignore_lower = sink->pulsewidth / 2; -+ -+ return source_ts.tv_nsec > ignore_lower && -+ source_ts.tv_nsec < ignore_upper; - } - - static enum extts_result ts2phc_pps_sink_event(struct ts2phc_private *priv, - -commit 0257b245df1a32869f356c0cfbeacfe5f0a522f5 -Author: Miroslav Lichvar -Date: Mon Jun 3 11:31:45 2024 +0200 - - ts2phc: Allow longer NMEA delays. - - Timestamps from PPS sources are rounded to the nearest pulse, i.e. for - correct synchronization the offset between the source timestamp and - external PPS event timestamp needs to be between -0.5 and +0.5 seconds. - For the pulse edge rejection to work correctly it needs to be even - smaller, between -pulsewidth/2 and +pulsewidth/2. - - With the NMEA PPS source the offset is the delay in the reception of the - RMC message. This message is not expected to come exactly on time with - the corresponding pulse. A positive delay is expected, typically at - least few tens of milliseconds, but some receivers have delays longer - than 0.5 seconds. - - Add NMEA-specific rounding of the offset to not expect negative delays - and allow positive delays of up to 1 second, or whole pulsewidth if the - edge rejection is enabled. - - Signed-off-by: Miroslav Lichvar - -diff --git a/ts2phc.c b/ts2phc.c -index 03c88b1..4817c85 100644 ---- a/ts2phc.c -+++ b/ts2phc.c -@@ -418,9 +418,16 @@ static int ts2phc_pps_source_implicit_tstamp(struct ts2phc_private *priv, - * deduce the timestamp (actually only seconds part, nanoseconds are by - * construction zero) of this edge at the emitter based on the - * emitter's current time. -+ * -+ * With an NMEA source assume its messages always follow the pulse, i.e. -+ * assign the timestamp to the previous pulse instead of nearest pulse. - */ -- if (source_ts.tv_nsec > NS_PER_SEC / 2) -+ if (ts2phc_pps_source_get_type(priv->src) == TS2PHC_PPS_SOURCE_NMEA) { - source_ts.tv_sec++; -+ } else { -+ if (source_ts.tv_nsec > NS_PER_SEC / 2) -+ source_ts.tv_sec++; -+ } - source_ts.tv_nsec = 0; - - tmv = timespec_to_tmv(source_ts); -diff --git a/ts2phc_pps_sink.c b/ts2phc_pps_sink.c -index 8121afb..0d399b8 100644 ---- a/ts2phc_pps_sink.c -+++ b/ts2phc_pps_sink.c -@@ -244,8 +244,13 @@ static bool ts2phc_pps_sink_ignore(struct ts2phc_private *priv, - source_tmv = tmv_sub(source_tmv, priv->perout_phase); - source_ts = tmv_to_timespec(source_tmv); - -- ignore_upper = 1000000000 - sink->pulsewidth / 2; -- ignore_lower = sink->pulsewidth / 2; -+ if (ts2phc_pps_source_get_type(priv->src) == TS2PHC_PPS_SOURCE_NMEA) { -+ ignore_upper = sink->pulsewidth; -+ ignore_lower = 0; -+ } else { -+ ignore_upper = 1000000000 - sink->pulsewidth / 2; -+ ignore_lower = sink->pulsewidth / 2; -+ } - - return source_ts.tv_nsec > ignore_lower && - source_ts.tv_nsec < ignore_upper; diff --git a/SOURCES/linuxptp-nmeadelay2.patch b/SOURCES/linuxptp-nmeadelay2.patch deleted file mode 100644 index 24e4239..0000000 --- a/SOURCES/linuxptp-nmeadelay2.patch +++ /dev/null @@ -1,83 +0,0 @@ -commit 0d508d8cfb96cc32d3516f1d0d3e80db49f00468 -Author: Miroslav Lichvar -Date: Mon Jun 3 16:43:54 2024 +0200 - - ts2phc: Add option to correct for NMEA delay. - - Add an option to specify the minimum expected delay of NMEA RMC messages - to correct timestamps returned by the NMEA PPS time source. - - This enables operation with receivers that have delays outside of the - expected 0-1.0s interval, or 0-pulsewidth if the PPS edge rejection is - enabled. - - [ RPC: Preserve alphabetical ordering in the ts2phc man page. ] - - (Rebased to 4.2) - - Signed-off-by: Miroslav Lichvar - Signed-off-by: Richard Cochran - Reviewed-by: Jacob Keller - -diff --git a/config.c b/config.c -index 58481db..d441d1e 100644 ---- a/config.c -+++ b/config.c -@@ -347,6 +347,7 @@ struct config_item config_tab[] = { - PORT_ITEM_INT("ts2phc.holdover", 0, 0, INT_MAX), - PORT_ITEM_INT("ts2phc.master", 0, 0, 1), - PORT_ITEM_INT("ts2phc.nmea_baudrate", 9600, 300, INT_MAX), -+ PORT_ITEM_INT("ts2phc.nmea_delay", 0, INT_MIN, INT_MAX), - GLOB_ITEM_STR("ts2phc.nmea_remote_host", ""), - GLOB_ITEM_STR("ts2phc.nmea_remote_port", ""), - GLOB_ITEM_STR("ts2phc.nmea_serialport", "/dev/ttyS0"), -diff --git a/ts2phc.8 b/ts2phc.8 -index c0b718b..b8383ff 100644 ---- a/ts2phc.8 -+++ b/ts2phc.8 -@@ -262,6 +262,16 @@ by changing the clock frequency instead of stepping the clock. When - set to 0.0, the servo will never step the clock except on start. - The default is 0.0. - -+.TP -+.B ts2phc.nmea_delay -+Specifies the minimum expected delay of NMEA RMC messages in nanoseconds. -+If the maximum delay is longer than 1 second, or 'ts2phc.pulsewidth' -+if 'ts2phc.extts_polarity' is set to "both", this option needs to be set -+accordingly to allow the timestamps from NMEA messages to be correctly -+assigned to pulses from the PPS signal and wrong PPS edges to be rejected if -+the edge rejection is enabled. -+The default is 0 nanoseconds. -+ - .TP - .B ts2phc.nmea_remote_host, ts2phc.nmea_remote_port - Specifies the remote host providing ToD information when using the -diff --git a/ts2phc_nmea_pps_source.c b/ts2phc_nmea_pps_source.c -index bdfaf19..e345969 100644 ---- a/ts2phc_nmea_pps_source.c -+++ b/ts2phc_nmea_pps_source.c -@@ -33,6 +33,7 @@ struct ts2phc_nmea_pps_source { - pthread_t worker; - /* Protects anonymous struct fields, below, from concurrent access. */ - pthread_mutex_t mutex; -+ tmv_t delay_correction; - struct { - struct timespec local_monotime; - struct timespec local_utctime; -@@ -207,6 +208,7 @@ static int ts2phc_nmea_pps_source_getppstime(struct ts2phc_pps_source *src, - } - - rmc = tmv_add(rmc, duration_since_rmc); -+ rmc = tmv_add(rmc, m->delay_correction); - *ts = tmv_to_timespec(rmc); - ts->tv_sec += tai_offset; - -@@ -234,6 +236,8 @@ struct ts2phc_pps_source *ts2phc_nmea_pps_source_create(struct ts2phc_private *p - s->pps_source.destroy = ts2phc_nmea_pps_source_destroy; - s->pps_source.getppstime = ts2phc_nmea_pps_source_getppstime; - s->config = priv->cfg; -+ s->delay_correction = nanoseconds_to_tmv( -+ config_get_int(priv->cfg, NULL, "ts2phc.nmea_delay")); - pthread_mutex_init(&s->mutex, NULL); - err = pthread_create(&s->worker, NULL, monitor_nmea_status, s); - if (err) { diff --git a/SOURCES/linuxptp-nmealeap.patch b/SOURCES/linuxptp-nmealeap.patch deleted file mode 100644 index f00cb0b..0000000 --- a/SOURCES/linuxptp-nmealeap.patch +++ /dev/null @@ -1,76 +0,0 @@ -commit f3c742e24a40cf75272ec39789a2cba35389230d -Author: Miroslav Lichvar -Date: Tue Jun 11 15:25:54 2024 +0200 - - nmea: Fix conversion of leap second. - - When a leap second is inserted, the RMC message reports time of - 23:59:60, which overflows in mktime() to 0:00:00 after the leap second - with an incremented TAI-UTC offset. This causes a one-second error in - the offset meaured by ts2phc. - - Check the seconds field of the RMC message and convert 60 to 59 to make - the timestamp ambiguous per is_utc_ambiguous() and ignored by ts2phc to - avoid updating the clock with the one-second error. - - Signed-off-by: Miroslav Lichvar - -diff --git a/nmea.c b/nmea.c -index 7f1d9a2..b84b42e 100644 ---- a/nmea.c -+++ b/nmea.c -@@ -155,6 +155,9 @@ static int nmea_scan_rmc(struct nmea_parser *np, struct nmea_rmc *result) - if (cnt != 3) { - return -1; - } -+ /* Convert an inserted leap second to ambiguous 23:59:59 */ -+ if (tm.tm_sec == 60) -+ tm.tm_sec = 59; - tm.tm_year += 100; - tm.tm_mon--; - tm.tm_isdst = 0; - -commit b396d361b0d290ce83395851860c2dcd074e0f3b -Author: Miroslav Lichvar -Date: Tue Jun 11 15:32:55 2024 +0200 - - ts2phc: Fix timestamp conversion for leap seconds. - - The UTC timestamp parsed from the RMC message needs to be converted to - TAI in order to calculate the PHC offset. This conversion was done after - adjusting the timestamp for the measured delay between the reception of - the message and the following pulse, which caused the offset measured by - ts2phc to have a one-second error if the message expected during or - after a leap second was missed. - - Apply the TAI-UTC offset to the timestamp parsed from the RMC message - before any adjustments are made to avoid the error. - - Signed-off-by: Miroslav Lichvar - -diff --git a/ts2phc_nmea_pps_source.c b/ts2phc_nmea_pps_source.c -index 7a28433..bdfaf19 100644 ---- a/ts2phc_nmea_pps_source.c -+++ b/ts2phc_nmea_pps_source.c -@@ -186,10 +186,9 @@ static int ts2phc_nmea_pps_source_getppstime(struct ts2phc_pps_source *src, - pr_err("nmea: rmc time stamp stale"); - return -1; - } -- rmc = tmv_add(rmc, duration_since_rmc); -+ - utc_time = tmv_to_nanoseconds(rmc); - utc_time /= (int64_t) 1000000000; -- *ts = tmv_to_timespec(rmc); - - result = lstab_utc2tai(m->lstab, utc_time, &tai_offset); - switch (result) { -@@ -206,6 +205,9 @@ static int ts2phc_nmea_pps_source_getppstime(struct ts2phc_pps_source *src, - pr_err("nmea: utc time stamp is ambiguous"); - break; - } -+ -+ rmc = tmv_add(rmc, duration_since_rmc); -+ *ts = tmv_to_timespec(rmc); - ts->tv_sec += tai_offset; - - return lstab_error; diff --git a/SOURCES/linuxptp-nmeareset.patch b/SOURCES/linuxptp-nmeareset.patch deleted file mode 100644 index d52f279..0000000 --- a/SOURCES/linuxptp-nmeareset.patch +++ /dev/null @@ -1,25 +0,0 @@ -commit b4ad9dccf23cef2d79621cd36987428a65f2bcc9 -Author: Miroslav Lichvar -Date: Tue Jun 11 12:35:10 2024 +0200 - - ts2phc: Reset parser after RMC message. - - When the receiver was configured to generate only RMC messages, every - other message was skipped due to the parser not being in the right - state to process another message. Reset the parser to correctly parse - every valid message. - - Signed-off-by: Miroslav Lichvar - -diff --git a/nmea.c b/nmea.c -index 44c7c01..7f1d9a2 100644 ---- a/nmea.c -+++ b/nmea.c -@@ -171,6 +171,7 @@ int nmea_parse(struct nmea_parser *np, const char *ptr, int buflen, - while (buflen) { - if (!nmea_parse_symbol(np, *ptr)) { - if (!nmea_scan_rmc(np, result)) { -+ nmea_reset(np); - *parsed = count + 1; - return 0; - } diff --git a/SOURCES/linuxptp-nowait.patch b/SOURCES/linuxptp-nowait.patch index b7f9bfe..3b9d189 100644 --- a/SOURCES/linuxptp-nowait.patch +++ b/SOURCES/linuxptp-nowait.patch @@ -1,4 +1,81 @@ -commit e3867eb1ce2282f9ac4cc729a3b1beb74bb017d6 +commit a3420abab9eec2dc7b35e0e1e9f37ebeffc87655 +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 03ab6793abf665039b25319f0f4ad7ce03452874 +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 1e25a62e65e07f2cc9e1c390895f0a940d307a25 Author: Miroslav Lichvar Date: Tue Nov 26 15:10:34 2024 +0100 @@ -21,10 +98,10 @@ Date: Tue Nov 26 15:10:34 2024 +0100 Signed-off-by: Miroslav Lichvar diff --git a/phc2sys.8 b/phc2sys.8 -index df0608a..5ca467d 100644 +index 762a1b1..3246c8f 100644 --- a/phc2sys.8 +++ b/phc2sys.8 -@@ -161,7 +161,10 @@ minimize the error caused by random delays in scheduling and bus utilization. +@@ -164,7 +164,10 @@ minimize the error caused by random delays in scheduling and bus utilization. The default is 5. .TP .BI \-O " offset" @@ -37,10 +114,10 @@ index df0608a..5ca467d 100644 .B \-a option. See diff --git a/phc2sys.c b/phc2sys.c -index 1745558..d8b0991 100644 +index c98ecec..ddd0a6a 100644 --- a/phc2sys.c +++ b/phc2sys.c -@@ -1406,12 +1406,6 @@ int main(int argc, char *argv[]) +@@ -1452,12 +1452,6 @@ int main(int argc, char *argv[]) goto bad_usage; } @@ -53,7 +130,7 @@ index 1745558..d8b0991 100644 if (hardpps_configured(pps_fd) && (dst_cnt != 1 || strcmp(dst_names[0], "CLOCK_REALTIME"))) { fprintf(stderr, -@@ -1501,7 +1495,7 @@ int main(int argc, char *argv[]) +@@ -1559,7 +1553,7 @@ int main(int argc, char *argv[]) r = -1; @@ -62,7 +139,7 @@ index 1745558..d8b0991 100644 snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d", getpid()); -@@ -1516,7 +1510,7 @@ int main(int argc, char *argv[]) +@@ -1574,7 +1568,7 @@ int main(int argc, char *argv[]) phc2sys_recv_subscribed, &domains[0])) goto end; diff --git a/SOURCES/linuxptp-ptpver.patch b/SOURCES/linuxptp-ptpver.patch index ca7bad7..4cb1a01 100644 --- a/SOURCES/linuxptp-ptpver.patch +++ b/SOURCES/linuxptp-ptpver.patch @@ -1,4 +1,4 @@ -commit 6e480c9572925a4ea8aac45a10a306e0c4e509a9 +commit daa82cda8318edd6a8e75ef46d0ed065445c8922 Author: Miroslav Lichvar Date: Thu Jan 11 11:33:54 2024 +0100 @@ -7,33 +7,33 @@ Date: Thu Jan 11 11:33:54 2024 +0100 Signed-off-by: Miroslav Lichvar diff --git a/config.c b/config.c -index 398b420..d7775c0 100644 +index 4a28efb..cbff976 100644 --- a/config.c +++ b/config.c -@@ -319,7 +319,7 @@ struct config_item config_tab[] = { - GLOB_ITEM_STR("productDescription", ";;"), +@@ -347,7 +347,7 @@ struct config_item config_tab[] = { + PORT_ITEM_STR("ptp_dst_ipv4", "224.0.1.129"), + PORT_ITEM_STR("ptp_dst_ipv6", "FF0E:0:0:0:0:0:0:181"), 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), + GLOB_ITEM_STR("sa_file", NULL), diff --git a/configs/default.cfg b/configs/default.cfg -index 0c7661c..8f94c16 100644 +index c3ad618..768eef8 100644 --- a/configs/default.cfg +++ b/configs/default.cfg -@@ -46,7 +46,7 @@ power_profile.2011.networkTimeInaccuracy -1 +@@ -47,7 +47,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 +-ptp_minor_version 1 ++ptp_minor_version 0 + spp -1 + active_key_id 0 # diff --git a/msg.h b/msg.h -index 9c80f45..786ddc7 100644 +index 58c2287..d2658c9 100644 --- a/msg.h +++ b/msg.h @@ -32,7 +32,7 @@ @@ -45,16 +45,44 @@ index 9c80f45..786ddc7 100644 #define PTP_VERSION (PTP_MINOR_VERSION << 4 | PTP_MAJOR_VERSION) #define MAJOR_VERSION_MASK 0x0f +diff --git a/port.c b/port.c +index db35a44..7f945ac 100644 +--- a/port.c ++++ b/port.c +@@ -3696,7 +3696,7 @@ struct port *port_open(const char *phc_device, + pr_err("%s: spp not supported on one-step ports", p->log_name); + goto err_uc_service; + } +- if (port_has_security(p) && (config_get_int(cfg, NULL, "ptp_minor_version") < 1)) { ++ if (port_has_security(p) && ptp_hdr_ver >> 4 < 1) { + pr_err("%s: spp needs at least PTPv2.1", p->log_name); + goto err_uc_service; + } diff --git a/ptp4l.8 b/ptp4l.8 -index 4cb9adb..c59b0b4 100644 +index 87900e3..28cc4c9 100644 --- a/ptp4l.8 +++ b/ptp4l.8 -@@ -813,7 +813,7 @@ The default is 128. +@@ -900,7 +900,8 @@ 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. ++The default (specific to the installed linuxptp package) is 0, but setting ++\fBsa_file\fR forces the version to 1. .TP .B refclock_sock_address +diff --git a/ptp4l.c b/ptp4l.c +index ac2ef96..0d54d6c 100644 +--- a/ptp4l.c ++++ b/ptp4l.c +@@ -194,6 +194,9 @@ int main(int argc, char *argv[]) + sk_hwts_filter_mode = config_get_int(cfg, NULL, "hwts_filter"); + + ptp_hdr_ver = config_get_int(cfg, NULL, "ptp_minor_version"); ++ /* Override patched default for spp, which requires PTPv2.1 */ ++ if (ptp_hdr_ver < 1 && config_get_string(cfg, NULL, "sa_file")) ++ ptp_hdr_ver = 1; + ptp_hdr_ver = (ptp_hdr_ver << 4) | PTP_MAJOR_VERSION; + + if (sad_create(cfg)) { diff --git a/SOURCES/linuxptp-staticauto.patch b/SOURCES/linuxptp-staticauto.patch new file mode 100644 index 0000000..a3fd1f1 --- /dev/null +++ b/SOURCES/linuxptp-staticauto.patch @@ -0,0 +1,302 @@ +commit f0ea5436b60494a8c5dac8d39e2b62dd8cab6f53 +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 2ceb8289b26e98f9f2179f021aa153db28c31dcf +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 5f37c1609d4a21daf7f7c12ae6f3fee327c03c3f +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 11f06a29e6cb34104785435274e3673dd72970e0 +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-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/linuxptp-udpaddr.patch b/SOURCES/linuxptp-udpaddr.patch new file mode 100644 index 0000000..d4804b3 --- /dev/null +++ b/SOURCES/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/SPECS/linuxptp.spec b/SPECS/linuxptp.spec index a344807..1705308 100644 --- a/SPECS/linuxptp.spec +++ b/SPECS/linuxptp.spec @@ -1,16 +1,16 @@ %global _hardened_build 1 -%global testsuite_ver bf8ead -%global clknetsim_ver 5d1dc0 +%global testsuite_ver d27dbd +%global clknetsim_ver 64df92 Name: linuxptp -Version: 4.2 -Release: 3%{?dist}.1 +Version: 4.4 +Release: 1%{?dist}.2 Summary: PTP implementation for Linux -License: GPLv2+ -URL: http://linuxptp.sourceforge.net/ +License: GPL-2.0-or-later +URL: https://www.linuxptp.org/ -Source0: https://downloads.sourceforge.net/%{name}/%{name}-%{version}.tgz +Source0: https://downloads.nwtime.org/%{name}/%{name}-%{version}.tgz Source1: phc2sys.service Source2: ptp4l.service Source3: timemaster.service @@ -21,34 +21,26 @@ Source10: https://github.com/mlichvar/linuxptp-testsuite/archive/%{testsuite_ver # 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 -# fix ts2phc to correctly handle leap seconds -Patch7: linuxptp-nmealeap.patch -# fix ts2phc to reset NMEA parser after RMC message -Patch8: linuxptp-nmeareset.patch -# add options to configure multicast IP addresses -Patch9: linuxptp-addropts.patch -# add holdover support to ts2phc -Patch10: linuxptp-holdover.patch -# add option to ts2phc to specify minimum expected NMEA delay -Patch11: linuxptp-nmeadelay2.patch +# fix port-specific ptp/p2p_dst_ipv4 configuration +Patch5: linuxptp-udpaddr.patch +# support static sink clocks in phc2sys automatic mode +Patch6: linuxptp-staticauto.patch +# don't require -O option without -a and -w in phc2sys +Patch7: 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 # check for EL-specific kernels with vclock support Patch12: linuxptp-vclock.patch -# don't require -O option without -a and -w in phc2sys -Patch13: linuxptp-nowait.patch -BuildRequires: gcc gcc-c++ make systemd +BuildRequires: gcc gcc-c++ gnutls-devel make systemd %{?systemd_requires} @@ -62,6 +54,10 @@ Supporting legacy APIs and other platforms is not a goal. %prep %setup -q -a 10 -a 11 -n %{name}-%{!?gitfullver:%{version}}%{?gitfullver} %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 @@ -125,9 +121,18 @@ PATH=..:$PATH ./run %{_mandir}/man8/*.8* %changelog -* Thu Jan 02 2025 Miroslav Lichvar 4.2-3.el9_5.1 -- add option to ts2phc to specify minimum expected NMEA delay (RHEL-70168) -- don't require -O option without -a and -w in phc2sys (RHEL-70678) +* Wed May 14 2025 Miroslav Lichvar 4.4-1.el9_6.2 +- add command to set external grandmaster properties (RHEL-91297) + +* Tue May 06 2025 Miroslav Lichvar 4.4-1.el9_6.1 +- add experimental option for external PPS in ts2phc automatic mode + (RHEL-89604) + +* Tue Dec 03 2024 Miroslav Lichvar 4.4-1 +- update to 4.4 (RHEL-58213 RHEL-57040) +- fix port-specific ptp/p2p_dst_ipv4 configuration (RHEL-60027) +- support static sink clocks in phc2sys automatic mode (RHEL-62864) +- don't require -O option without -a and -w in phc2sys (RHEL-69138) * Thu Jul 25 2024 Miroslav Lichvar 4.2-3 - rework NMEA delay patch to fix PPS edge rejection (RHEL-39387)