99ab1d
commit 134dc3c4655fcd9f314a5e56cd50db2f87366f5a
99ab1d
Author: davidjm via Linuxptp-devel <linuxptp-devel@lists.sourceforge.net>
99ab1d
Date:   Wed Nov 23 15:50:30 2022 -0800
99ab1d
99ab1d
    Don't re-arm fault clearing timer on unrelated netlink events
99ab1d
    
99ab1d
    Set the timer only when an event causes the port to transition to the
99ab1d
    FAULTY state, rather than potentially re-arming the timeout when an
99ab1d
    event occurs while the port was already FAULTY.
99ab1d
    
99ab1d
    Concretely this occurs when a port is in fault, perhaps due to a
99ab1d
    single time out while polling for tx-timestamp. If any other port in the
99ab1d
    system (including unrelated ones ptp4l does not even know about) cause
99ab1d
    netlink messages to be sent. As it stands, clock_poll() will note that
99ab1d
    the port is in fault (from before, not due to the current event) and
99ab1d
    reset the timeout to its original value.
99ab1d
    
99ab1d
    If such unrelated netlink messages arrive at a regular enough cadence
99ab1d
    the timeout may be repeatedly reset, not trigger on time (if at all) and
99ab1d
    the port may not get a chance to clear its fault, perhaps indefinitely.
99ab1d
    
99ab1d
    Signed-off-by: David Mirabito <davidjm@arista.com>
99ab1d
99ab1d
diff --git a/clock.c b/clock.c
99ab1d
index eea7983..451473e 100644
99ab1d
--- a/clock.c
99ab1d
+++ b/clock.c
99ab1d
@@ -1586,6 +1586,7 @@ void clock_set_sde(struct clock *c, int sde)
99ab1d
 int clock_poll(struct clock *c)
99ab1d
 {
99ab1d
 	int cnt, i;
99ab1d
+	enum port_state prior_state;
99ab1d
 	enum fsm_event event;
99ab1d
 	struct pollfd *cur;
99ab1d
 	struct port *p;
99ab1d
@@ -1609,6 +1610,7 @@ int clock_poll(struct clock *c)
99ab1d
 		/* Let the ports handle their events. */
99ab1d
 		for (i = 0; i < N_POLLFD; i++) {
99ab1d
 			if (cur[i].revents & (POLLIN|POLLPRI|POLLERR)) {
99ab1d
+				prior_state = port_state(p);
99ab1d
 				if (cur[i].revents & POLLERR) {
99ab1d
 					pr_err("port %d: unexpected socket error",
99ab1d
 					       port_number(p));
99ab1d
@@ -1624,7 +1626,7 @@ int clock_poll(struct clock *c)
99ab1d
 				}
99ab1d
 				port_dispatch(p, event, 0);
99ab1d
 				/* Clear any fault after a little while. */
99ab1d
-				if (PS_FAULTY == port_state(p)) {
99ab1d
+				if ((PS_FAULTY == port_state(p)) && (prior_state != PS_FAULTY)) {
99ab1d
 					clock_fault_timeout(p, 1);
99ab1d
 					break;
99ab1d
 				}