From: Vincent Cheng <vincent.cheng...@renesas.com>

ptp4l currently does not cancel unicast service on program exit.
This causes problems for subsequent ptp4l session that is using different 
masters.

Below example has debug statements to print out announce master address and 
received
packet address.

Start unicast slave session with master 10.64.10.13, and unicast_req_duration 
300.

  ptp4l[682807.352]: port 1 (eth0): INITIALIZING to LISTENING on INIT_COMPLETE
  ptp4l[682811.352]: debug: announce master 10.64.10.13
  ptp4l[682812.770]: debug: sk_receive from 10.64.10.13
  ptp4l[682812.810]: debug: sk_receive from 10.64.10.13
  ptp4l[682813.120]: selected local clock 000a35.fffe.002201 as best master
  ptp4l[682814.755]: port 1 (eth0): new foreign master 84c807.fffe.10c570-1

Exit ptp4l.

The unicast master continues to send SYNC packets to slave until renewal period
expires.

Start unicast same slave, but different master 10.64.10.14.  This master is
not online, so ptp4l should choose local clock as best master.

However, because there is no checking of received unicast master to configured
unicast table, ptp4l is quite content with packets from previous master 
10.64.10.13.

  ptp4l[682848.858]: port 1 (eth0): INITIALIZING to LISTENING on INIT_COMPLETE
  ptp4l[682848.892]: debug: sk_receive from 10.64.10.13
  ...
  ptp4l[682850.704]: debug: sk_receive from 10.64.10.13
  ptp4l[682850.751]: debug: sk_receive from 10.64.10.13
  ptp4l[682850.751]: port 1 (eth0): new foreign master 84c807.fffe.10c570-1
  ptp4l[682850.766]: debug: sk_receive from 10.64.10.13
  ...
  ptp4l[682852.829]: debug: sk_receive from 10.64.10.13
  ptp4l[682852.858]: debug: announce master 10.64.10.14
  ptp4l[682852.891]: debug: sk_receive from 10.64.10.13
  ptp4l[682854.751]: port 1 (eth0): LISTENING to UNCALIBRATED on RS_SLAVE
  ptp4l[682854.766]: debug: sk_receive from 10.64.10.13
  ...
  ptp4l[682854.891]: master offset      -3269 s0 freq    -397 path delay      
4757

This patch implements a workaround by canceling unicast session on exit so that
subsequent session is not polluted by lingering unicast session traffic.

Signed-off-by: Vincent Cheng <vincent.cheng...@renesas.com>
---
 port.c            |  1 +
 unicast_service.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 unicast_service.h |  7 +++++
 3 files changed, 92 insertions(+)

diff --git a/port.c b/port.c
index f2b666c..ebc345f 100644
--- a/port.c
+++ b/port.c
@@ -2462,6 +2462,7 @@ void process_sync(struct port *p, struct ptp_message *m)
 void port_close(struct port *p)
 {
        if (port_is_enabled(p)) {
+               unicast_service_cancel(p);
                port_disable(p);
        }
 
diff --git a/unicast_service.c b/unicast_service.c
index 3154894..ac5f6fb 100644
--- a/unicast_service.c
+++ b/unicast_service.c
@@ -84,6 +84,23 @@ static int attach_grant(struct ptp_message *msg,
        return 0;
 }
 
+static int attach_cancel(struct ptp_message *msg, uint8_t message_type)
+{
+       struct cancel_unicast_xmit_tlv *req;
+       struct tlv_extra *extra;
+
+       extra = msg_tlv_append(msg, sizeof(*req));
+       if (!extra) {
+               return -1;
+       }
+       req = (struct cancel_unicast_xmit_tlv *) extra->tlv;
+       req->type = TLV_CANCEL_UNICAST_TRANSMISSION;
+       req->length = sizeof(*req) - sizeof(req->type) - sizeof(req->length);
+       req->message_type_flags = message_type << 4;
+
+       return 0;
+}
+
 static int compare_timeout(void *ain, void *bin)
 {
        struct unicast_service_interval *a, *b;
@@ -94,6 +111,58 @@ static int compare_timeout(void *ain, void *bin)
        return timespec_compare(&a->tmo, &b->tmo);
 }
 
+static int unicast_client_cancel_announce(struct port *p,
+                                         struct unicast_master_address *dst)
+{
+       struct ptp_message *msg;
+       int err;
+
+       msg = port_signaling_uc_construct(p, &dst->address, &dst->portIdentity);
+       if (!msg) {
+               return -1;
+       }
+       err = attach_cancel(msg, ANNOUNCE);
+       if (err) {
+               goto out;
+       }
+       err = port_prepare_and_send(p, msg, TRANS_GENERAL);
+       if (err) {
+               pr_err("%s: signaling message failed", p->log_name);
+       }
+out:
+       msg_put(msg);
+       return err;
+}
+
+static int unicast_client_cancel_sydy(struct port *p,
+                                     struct unicast_master_address *dst)
+{
+       struct ptp_message *msg;
+       int err;
+
+       msg = port_signaling_uc_construct(p, &dst->address, &dst->portIdentity);
+       if (!msg) {
+               return -1;
+       }
+       err = attach_cancel(msg, SYNC);
+       if (err) {
+               goto out;
+       }
+       if (p->delayMechanism != DM_P2P) {
+               err = attach_cancel(msg, DELAY_RESP);
+               if (err) {
+                       goto out;
+               }
+       }
+       err = port_prepare_and_send(p, msg, TRANS_GENERAL);
+       if (err) {
+               pr_err("%s: signaling message failed", p->log_name);
+       }
+out:
+       msg_put(msg);
+       return err;
+}
+
 static void initialize_interval(struct unicast_service_interval *interval,
                                int log_period)
 {
@@ -429,6 +498,21 @@ int unicast_service_initialize(struct port *p)
        return 0;
 }
 
+void unicast_service_cancel(struct port *p)
+{
+       struct unicast_master_address *master;
+
+       if (!p->unicast_service) {
+               return;
+       }
+       STAILQ_FOREACH(master, &p->unicast_master_table->addrs, list) {
+               if (master->state != UC_WAIT) {
+                       unicast_client_cancel_announce(p, master);
+                       unicast_client_cancel_sydy(p, master);
+               }
+       }
+}
+
 void unicast_service_remove(struct port *p, struct ptp_message *m,
                            struct tlv_extra *extra)
 {
diff --git a/unicast_service.h b/unicast_service.h
index f0d6487..2b55ecd 100644
--- a/unicast_service.h
+++ b/unicast_service.h
@@ -71,6 +71,13 @@ int unicast_service_grant(struct port *p, struct ptp_message 
*m,
  */
 int unicast_service_initialize(struct port *p);
 
+
+/**
+ * Cancel a port's unicast service.
+ * @param p      The port in question.
+ */
+void unicast_service_cancel(struct port *p);
+
 /**
  * Handle a unicast service cancellation.
  * @param p      The port on which the signaling message was received.
-- 
2.7.4



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to