This change furnishes the plumbing for interacting with CMLDS
Link Ports (i.e. ports with "run_cmlds=1").

It adds internal functions for PTP Ports which employ the
COMMON_P2P delay mechanism to issue requests to a CMLDS Link Port at
MID_CMLDS_INFO_NP and handle the response.

port_request_cmlds_info() encodes the CMLDS Link Port portNumber
associated with its physical port as read from its config file.
The request is sent to the configured cmlds_uds_address, i.e. the
uds_address of a ptp4l instance that hosts the CMLDS Link Port.

Upon receiving a request for MID_CMLDS_INFO_NP, the receiving ptp4l
instance matches the target portNumber against the CMLDS Link Port
portNumber that was assigned in its own config file and invokes
process_cmlds_response().

Ports that do not expose the CMLDS ('run_cmlds' set to 0) will not
respond to MID_CMLDS_INFO_NP queries.

Co-authored-by: Andrew Zaborowski <andrew.zaborow...@intel.com>
Signed-off-by: Kishen Maloor <kishen.mal...@intel.com>
---
 clock.c        |  10 ++++
 clock.h        |   6 +++
 port.c         | 133 ++++++++++++++++++++++++++++++++++++++++++++++++-
 port_private.h |   2 +
 4 files changed, 149 insertions(+), 2 deletions(-)

diff --git a/clock.c b/clock.c
index c74a6baa9f61..810d57d849d1 100644
--- a/clock.c
+++ b/clock.c
@@ -1650,6 +1650,11 @@ int clock_manage(struct clock *c, struct port *p, struct 
ptp_message *msg)
                        return changed;
                }
                break;
+       case RESPONSE:
+               /* Let the destined Port handle a response from CMLDS */
+               if (mgt->id == MID_CMLDS_INFO_NP)
+                       break;
+               return changed;
        default:
                return changed;
        }
@@ -2282,3 +2287,8 @@ enum servo_state clock_servo_state(struct clock *c)
 {
        return c->servo_state;
 }
+
+struct port *clock_uds_rw_port(struct clock *c)
+{
+       return c->uds_rw_port;
+}
diff --git a/clock.h b/clock.h
index ce9ae913eaaf..deb827f0afad 100644
--- a/clock.h
+++ b/clock.h
@@ -396,4 +396,10 @@ void clock_check_ts(struct clock *c, uint64_t ts);
  */
 double clock_rate_ratio(struct clock *c);
 
+/**
+ * Return a handle to the UDS RW port.
+ * @param c   The clock instance.
+ */
+struct port *clock_uds_rw_port(struct clock *c);
+
 #endif
diff --git a/port.c b/port.c
index acce160b6499..ad13a919f161 100644
--- a/port.c
+++ b/port.c
@@ -1216,6 +1216,12 @@ static int port_management_fill_response(struct port 
*target,
                cmlds->egress_ts = tmv_to_nanoseconds(target->peer_delay_t1);
                cmlds->rx_ts = tmv_to_nanoseconds(target->peer_delay_t2);
                datalen = sizeof(*cmlds);
+               /* Reflect the CMLDS sdoid/domainNumber/port id in
+                * MID_CMLDS_INFO_NP responses
+                */
+               rsp->header.tsmt = MANAGEMENT | CMLDS_TRANSPORTSPECIFIC;
+               rsp->header.domainNumber = CMLDS_DOMAINNUMBER;
+               rsp->header.sourcePortIdentity = target->cmlds_portIdentity;
                break;
        default:
                /* The caller should *not* respond to this message. */
@@ -3244,10 +3250,26 @@ int port_manage(struct port *p, struct port *ingress, 
struct ptp_message *msg)
        struct management_tlv *mgt;
        UInteger16 target = msg->management.targetPortIdentity.portNumber;
 
-       if (target != portnum(p) && target != 0xffff) {
+       mgt = (struct management_tlv *) msg->management.suffix;
+
+       /* Given a query to CMLDS and this port exposes CMLDS, try to match
+        * the target portNumber with the CMLDS Link Port PortNumber.
+        */
+       if (mgt->id == MID_CMLDS_INFO_NP &&
+           management_action(msg) == GET) {
+               if (port_cmlds_enabled(p)) {
+                       if (target != 0xffff &&
+                           target != p->cmlds_portIdentity.portNumber)
+                               return 0;
+               } else {
+                       /* Do not respond to MID_CMLDS_INFO_NP if this port
+                        * does not expose CMLDS
+                        */
+                       return 0;
+               }
+       } else if (target != portnum(p) && target != 0xffff) {
                return 0;
        }
-       mgt = (struct management_tlv *) msg->management.suffix;
 
        switch (management_action(msg)) {
        case GET:
@@ -3260,6 +3282,12 @@ int port_manage(struct port *p, struct port *ingress, 
struct ptp_message *msg)
                break;
        case COMMAND:
                break;
+       case RESPONSE:
+               /* Handle a response from CMLDS */
+               if (mgt->id == MID_CMLDS_INFO_NP) {
+                       return process_cmlds_response(p, msg);
+               }
+               break;
        default:
                return -1;
        }
@@ -3710,3 +3738,104 @@ void port_update_unicast_state(struct port *p)
                p->unicast_state_dirty = false;
        }
 }
+
+int process_cmlds_response(struct port *p,
+                          struct ptp_message *msg)
+{
+       struct management_tlv *mgt = (struct management_tlv *)
+                                       msg->management.suffix;
+       struct cmlds_info_np *cmlds;
+
+       if (port_delay_mechanism(p) != DM_COMMON_P2P ||
+           msg_tlv_count(msg) != 1) {
+               return -1;
+       }
+
+       pr_debug("Response\t%s seq %hu ",
+               pid2str(&msg->header.sourcePortIdentity),
+               msg->header.sequenceId);
+
+       cmlds = (struct cmlds_info_np *) mgt->data;
+
+       pr_debug("CMLDS INFO\n"
+                "\tserviceMeasurementValid %i\n"
+                "\tmeanLinkDelay %" PRId64 "\n"
+                "\tscaledNeighborRateRatio %" PRId32 "\n"
+                "\tegress_ts %" PRId64 "\n"
+                "\trx_ts %" PRId64,
+                cmlds->serviceMeasurementValid, cmlds->meanLinkDelay,
+                cmlds->scaledNeighborRateRatio, cmlds->egress_ts,
+                cmlds->rx_ts);
+
+       /* COMMON_P2P DM implementation goes here */
+
+       return 0;
+}
+
+int port_request_cmlds_info(struct port *p)
+{
+       struct port *uds = clock_uds_rw_port(p->clock);
+       struct management_tlv *mgt;
+       struct tlv_extra *extra;
+       struct ptp_message *msg;
+       int err;
+
+       if (port_delay_mechanism(p) != DM_COMMON_P2P) {
+               return -1;
+       }
+
+       msg = msg_allocate();
+       if (!msg)
+               return -ENOMEM;
+
+       msg->hwts.type = p->timestamping;
+
+       msg->header.tsmt               = MANAGEMENT | CMLDS_TRANSPORTSPECIFIC;
+       msg->header.ver                = PTP_VERSION;
+       msg->header.domainNumber       = CMLDS_DOMAINNUMBER;
+       msg->header.sourcePortIdentity = p->portIdentity;
+       msg->header.sequenceId         = p->seqnum.delayreq++;
+       msg->header.logMessageInterval = 0x7f;
+
+       /* Set the target cid to the wildcard as this request is being
+        * sent to the specific ptp4l instance that exposes the CMLDS
+        */
+       msg->management.targetPortIdentity.clockIdentity =
+         (struct ClockIdentity){
+               .id = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+       };
+       /* Set the target CMLDS Link Port portNumber */
+       msg->management.targetPortIdentity.portNumber = 
p->cmlds_portIdentity.portNumber;
+
+       msg->management.flags = GET;
+
+       mgt = (struct management_tlv *) msg->management.suffix;
+       mgt->type = TLV_MANAGEMENT;
+       mgt->length = sizeof(mgt->id);
+       mgt->id = MID_CMLDS_INFO_NP;
+       msg->header.messageLength = sizeof(struct management_msg) + 
sizeof(*mgt);
+
+       extra = tlv_extra_alloc();
+       if (!extra) {
+               pr_err("failed to allocate TLV descriptor");
+               msg_put(msg);
+               return -ENOMEM;
+       }
+       extra->tlv = (struct TLV *) msg->management.suffix;
+       msg_tlv_attach(msg, extra);
+
+       err = msg_pre_send(msg);
+       if (err) {
+               pr_err("msg_pre_send failed");
+               return -1;
+       }
+
+       /* Set the target CMLDS UDS address */
+       msg->address = p->cmlds_uds_address;
+       err = port_forward_to(uds, msg);
+
+       pr_debug("CMLDS request sent: %s", strerror(err < 0 ? -err : 0));
+
+       msg_put(msg);
+       return err;
+}
diff --git a/port_private.h b/port_private.h
index f5543076f76e..664d14944919 100644
--- a/port_private.h
+++ b/port_private.h
@@ -207,6 +207,8 @@ int port_tx_interval_request(struct port *p,
                             Integer8 timeSyncInterval,
                             Integer8 linkDelayInterval);
 int port_tx_sync(struct port *p, struct address *dst, uint16_t sequence_id);
+int port_request_cmlds_info(struct port *p);
+int process_cmlds_response(struct port *p, struct ptp_message *msg);
 int process_announce(struct port *p, struct ptp_message *m);
 void process_delay_resp(struct port *p, struct ptp_message *m);
 void process_follow_up(struct port *p, struct ptp_message *m);
-- 
2.31.1



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

Reply via email to