105 lines
3.3 KiB
Diff
105 lines
3.3 KiB
Diff
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
|