import CS linuxptp-4.4-3.el9
This commit is contained in:
parent
47794fd076
commit
f72a08b49b
275
SOURCES/linuxptp-externalgm.patch
Normal file
275
SOURCES/linuxptp-externalgm.patch
Normal file
@ -0,0 +1,275 @@
|
||||
commit a0fb624d9a2bb804d85f4597b1249123c7978fed
|
||||
Author: Miroslav Lichvar <mlichvar@redhat.com>
|
||||
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 <mlichvar@redhat.com>
|
||||
|
||||
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 <mlichvar@redhat.com>
|
||||
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 <mlichvar@redhat.com>
|
||||
|
||||
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.
|
||||
149
SOURCES/linuxptp-externalpps.patch
Normal file
149
SOURCES/linuxptp-externalpps.patch
Normal file
@ -0,0 +1,149 @@
|
||||
commit f20e568cb2bf3b0ea6105e5624409f02fb9aa2bc
|
||||
Author: Miroslav Lichvar <mlichvar@redhat.com>
|
||||
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 <mlichvar@redhat.com>
|
||||
|
||||
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;
|
||||
75
SOURCES/linuxptp-rtnlinit.patch
Normal file
75
SOURCES/linuxptp-rtnlinit.patch
Normal file
@ -0,0 +1,75 @@
|
||||
commit 01de33e91f9717d0cbae5af6eee2beb45deee219
|
||||
Author: Miroslav Lichvar <mlichvar@redhat.com>
|
||||
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 <mlichvar@redhat.com>
|
||||
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
104
SOURCES/linuxptp-unirecover.patch
Normal file
104
SOURCES/linuxptp-unirecover.patch
Normal file
@ -0,0 +1,104 @@
|
||||
commit 71241f3fdcff59b35ad5de0b8b37cb07a4b677bd
|
||||
Author: Vincent Cheng <vscheng@gmail.com>
|
||||
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 <vincent.cheng.xh@renesas.com>
|
||||
|
||||
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
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
Name: linuxptp
|
||||
Version: 4.4
|
||||
Release: 1%{?dist}
|
||||
Release: 3%{?dist}
|
||||
Summary: PTP implementation for Linux
|
||||
|
||||
License: GPL-2.0-or-later
|
||||
@ -33,6 +33,14 @@ Patch5: linuxptp-udpaddr.patch
|
||||
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
|
||||
# refresh link status on faults
|
||||
Patch10: linuxptp-rtnlinit.patch
|
||||
# fix unicast server to recover after port fault
|
||||
Patch11: linuxptp-unirecover.patch
|
||||
# check for EL-specific kernels with vclock support
|
||||
Patch12: linuxptp-vclock.patch
|
||||
|
||||
@ -117,6 +125,15 @@ PATH=..:$PATH ./run
|
||||
%{_mandir}/man8/*.8*
|
||||
|
||||
%changelog
|
||||
* Wed May 28 2025 Miroslav Lichvar <mlichvar@redhat.com> 4.4-3
|
||||
- fix unicast server to recover after port fault (RHEL-93496)
|
||||
|
||||
* Wed May 14 2025 Miroslav Lichvar <mlichvar@redhat.com> 4.4-2
|
||||
- add experimental option for external PPS in ts2phc automatic mode
|
||||
(RHEL-72468)
|
||||
- add command to set external grandmaster properties (RHEL-90585)
|
||||
- refresh link status on faults (RHEL-56168)
|
||||
|
||||
* Tue Dec 03 2024 Miroslav Lichvar <mlichvar@redhat.com> 4.4-1
|
||||
- update to 4.4 (RHEL-58213 RHEL-57040)
|
||||
- fix port-specific ptp/p2p_dst_ipv4 configuration (RHEL-60027)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user