For ports that are configured with "run_cmlds=1", i.e. CMLDS Link
Ports, this change updates port_pdelay_request(), process_pdelay_req() and
port_peer_delay() to utilize the CMLDS sdoid/domainNumber/portId
along code paths where necessary. It also ensures that
neighborRateRatio is calculated on CMLDS Link Ports and is available
to users of MID_CMLDS_INFO_NP. Further, process_pdelay_request()
enforces two-step Pdelay when responding as CMLDS.
These changes are in accordance to the requirements outlined in
IEEE 1588, clause 16.6.3.

In addition, CMLDS Link Ports respond with instance-specific peer delay
messages to PdelayReqs with an sdoid/domainNumber that match their ptp4l
instance configuration. This aims to address the requirement outlined
above NOTE 3 in IEEE 802.1AS-2020, clause 11.2.17.1.

Note that all these changes take effect only in ports with a
"run_cmlds=1" setting. Default behavior applies otherwise.

Co-authored-by: Andrew Zaborowski <andrew.zaborow...@intel.com>
Signed-off-by: Kishen Maloor <kishen.mal...@intel.com>
---
 port.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 60 insertions(+), 8 deletions(-)

diff --git a/port.c b/port.c
index 87780fd39caa..435d9ab543c7 100644
--- a/port.c
+++ b/port.c
@@ -47,6 +47,8 @@
 
 #define ALLOWED_LOST_RESPONSES 3
 #define ANNOUNCE_SPAN 1
+#define CMLDS_TRANSPORTSPECIFIC 0x20
+#define CMLDS_DOMAINNUMBER 0
 
 enum syfu_event {
        SYNC_MISMATCH,
@@ -1544,6 +1546,9 @@ static void port_syfufsm(struct port *p, enum syfu_event 
event,
 
 static int port_pdelay_request(struct port *p)
 {
+       struct PortIdentity sourcePortIdentity = p->portIdentity;
+       UInteger8 domainNumber = clock_domain_number(p->clock);
+       UInteger8 transportSpecific = p->transportSpecific;
        struct ptp_message *msg;
        int err;
 
@@ -1558,14 +1563,23 @@ static int port_pdelay_request(struct port *p)
                return -1;
        }
 
+       /* If this port exposes CMLDS, advertise the CMLDS sdoid,
+        * domainNumber and portId
+        */
+       if (port_cmlds_enabled(p)) {
+               transportSpecific = CMLDS_TRANSPORTSPECIFIC;
+               domainNumber = CMLDS_DOMAINNUMBER;
+               sourcePortIdentity = p->cmlds_portIdentity;
+       }
+
        msg->hwts.type = p->timestamping;
 
-       msg->header.tsmt               = PDELAY_REQ | p->transportSpecific;
+       msg->header.tsmt               = PDELAY_REQ | transportSpecific;
        msg->header.ver                = PTP_VERSION;
        msg->header.messageLength      = sizeof(struct pdelay_req_msg);
-       msg->header.domainNumber       = clock_domain_number(p->clock);
+       msg->header.domainNumber       = domainNumber;
        msg->header.correction         = -p->asymmetry;
-       msg->header.sourcePortIdentity = p->portIdentity;
+       msg->header.sourcePortIdentity = sourcePortIdentity;
        msg->header.sequenceId         = p->seqnum.delayreq++;
        msg->header.logMessageInterval = port_is_ieee8021as(p) ?
                p->logPdelayReqInterval : 0x7f;
@@ -2305,7 +2319,16 @@ int process_pdelay_req(struct port *p, struct 
ptp_message *m)
                port_set_delay_tmo(p);
        }
        if (p->peer_portid_valid) {
-               if (!pid_eq(&p->peer_portid, &m->header.sourcePortIdentity)) {
+               /* The first subexpression bypasses port ID matching
+                * and the ensuing block in the specific case when
+                * a CMLDS Link Port receives a PdelayReq with the PTP
+                * instance's sdoid/domainNumber in order to
+                * issue PDELAY_RESP/RESP_FOLLOW_UP messages
+                * back to the requesting port.
+                */
+               if ((!port_cmlds_enabled(p) ||
+                   msg_transport_specific(m) == CMLDS_TRANSPORTSPECIFIC) &&
+                   !pid_eq(&p->peer_portid, &m->header.sourcePortIdentity)) {
                        pr_err("%s: received pdelay_req msg with "
                                "unexpected peer port id %s",
                                p->log_name,
@@ -2341,11 +2364,22 @@ int process_pdelay_req(struct port *p, struct 
ptp_message *m)
        rsp->header.sequenceId         = m->header.sequenceId;
        rsp->header.logMessageInterval = 0x7f;
 
+       /* If this is a CMLDS PdelayReq, then respond with the CMLDS
+        * sdoid/domainNumber/port id.
+        */
+       if (msg_transport_specific(m) == CMLDS_TRANSPORTSPECIFIC) {
+               rsp->header.tsmt = PDELAY_RESP | CMLDS_TRANSPORTSPECIFIC;
+               rsp->header.domainNumber = CMLDS_DOMAINNUMBER;
+               rsp->header.sourcePortIdentity = p->cmlds_portIdentity;
+       }
+
        /*
         * NB - We do not have any fraction nanoseconds for the correction
         * fields, neither in the response or the follow up.
         */
-       if (p->timestamping == TS_P2P1STEP) {
+       if (p->timestamping == TS_P2P1STEP &&
+           /* Enforce two-step Pdelay when responding as CMLDS */
+           msg_transport_specific(m) != CMLDS_TRANSPORTSPECIFIC) {
                rsp->header.correction = m->header.correction;
                rsp->header.correction += p->tx_timestamp_offset;
                rsp->header.correction += p->rx_timestamp_offset;
@@ -2393,6 +2427,15 @@ int process_pdelay_req(struct port *p, struct 
ptp_message *m)
        fup->pdelay_resp_fup.responseOriginTimestamp =
                tmv_to_Timestamp(rsp->hwts.ts);
 
+       /* If this is a CMLDS PdelayReq, then respond with the CMLDS
+        * sdoid/domainNumber/port id.
+        */
+       if (msg_transport_specific(m) == CMLDS_TRANSPORTSPECIFIC) {
+               fup->header.tsmt = PDELAY_RESP_FOLLOW_UP | 
CMLDS_TRANSPORTSPECIFIC;
+               fup->header.domainNumber = CMLDS_DOMAINNUMBER;
+               fup->header.sourcePortIdentity = p->cmlds_portIdentity;
+       }
+
        if (msg_unicast(m)) {
                fup->address = m->address;
                fup->header.flagField[0] |= UNICAST;
@@ -2410,17 +2453,25 @@ out:
 
 static void port_peer_delay(struct port *p)
 {
+       struct PortIdentity portIdentity = p->portIdentity;
        tmv_t c1, c2, t1, t2, t3, t3c, t4;
        struct ptp_message *req = p->peer_delay_req;
        struct ptp_message *rsp = p->peer_delay_resp;
        struct ptp_message *fup = p->peer_delay_fup;
 
+       /* Following a CMLDS PDELAY transaction, use the CMLDS port id
+        * for comparisons below with the 'requestingPortIdentity'.
+        */
+       if (msg_transport_specific(req) == CMLDS_TRANSPORTSPECIFIC) {
+               portIdentity = p->cmlds_portIdentity;
+       }
+
        /* Check for response, validate port and sequence number. */
 
        if (!rsp)
                return;
 
-       if (!pid_eq(&rsp->pdelay_resp.requestingPortIdentity, &p->portIdentity))
+       if (!pid_eq(&rsp->pdelay_resp.requestingPortIdentity, &portIdentity))
                return;
 
        if (rsp->header.sequenceId != ntohs(req->header.sequenceId))
@@ -2443,7 +2494,7 @@ static void port_peer_delay(struct port *p)
        if (!fup)
                return;
 
-       if (!pid_eq(&fup->pdelay_resp_fup.requestingPortIdentity, 
&p->portIdentity))
+       if (!pid_eq(&fup->pdelay_resp_fup.requestingPortIdentity, 
&portIdentity))
                return;
 
        if (fup->header.sequenceId != rsp->header.sequenceId)
@@ -2459,7 +2510,8 @@ static void port_peer_delay(struct port *p)
 calc:
        t3c = tmv_add(t3, tmv_add(c1, c2));
 
-       if (p->follow_up_info)
+       /* Always calculate the NRR when the port exposes CMLDS */
+       if (p->follow_up_info || port_cmlds_enabled(p))
                port_nrate_calculate(p, t3c, t4);
 
        tsproc_set_clock_rate_ratio(p->tsproc, p->nrate.ratio *
-- 
2.31.1



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

Reply via email to