When NSM is enabled on a given port, that port always replies to a NSM
delay request with a delay response, sync, and follow up, regardless
of the current state of the port.

Signed-off-by: Richard Cochran <richardcoch...@gmail.com>
---
 port.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 123 insertions(+), 5 deletions(-)

diff --git a/port.c b/port.c
index 4e0da1a..4113d3f 100644
--- a/port.c
+++ b/port.c
@@ -126,6 +126,7 @@ struct port {
        int                 freq_est_interval;
        int                 hybrid_e2e;
        int                 min_neighbor_prop_delay;
+       int                 net_sync_monitor;
        int                 path_trace_enabled;
        int                 rx_timestamp_offset;
        int                 tx_timestamp_offset;
@@ -184,6 +185,29 @@ static int clear_fault_asap(struct fault_interval *faint)
        return 0;
 }
 
+static void extract_address(struct ptp_message *m, struct PortAddress *paddr)
+{
+       int len = 0;
+
+       switch (paddr->networkProtocol) {
+       case TRANS_UDP_IPV4:
+               len = sizeof(m->address.sin.sin_addr.s_addr);
+               memcpy(paddr->address, &m->address.sin.sin_addr.s_addr, len);
+               break;
+       case TRANS_UDP_IPV6:
+               len = sizeof(m->address.sin6.sin6_addr.s6_addr);
+               memcpy(paddr->address, &m->address.sin6.sin6_addr.s6_addr, len);
+               break;
+       case TRANS_IEEE_802_3:
+               len = MAC_LEN;
+               memcpy(paddr->address, &m->address.sll.sll_addr, len);
+               break;
+       default:
+               return;
+       }
+       paddr->addressLength = len;
+}
+
 static int msg_current(struct ptp_message *m, struct timespec now)
 {
        int64_t t1, t2, tmo;
@@ -443,6 +467,61 @@ static int follow_up_info_append(struct port *p, struct 
ptp_message *m)
        return sizeof(*fui);
 }
 
+static int net_sync_resp_append(struct port *p, struct ptp_message *m)
+{
+       struct timePropertiesDS *tp = clock_time_properties(p->clock);
+       struct ClockIdentity cid = clock_identity(p->clock), pid;
+       struct currentDS *cds = clock_current_dataset(p->clock);
+       struct parent_ds *dad = clock_parent_ds(p->clock);
+       struct port *best = clock_best_port(p->clock);
+       struct nsm_resp_tlv_head *head;
+       struct nsm_resp_tlv_foot *foot;
+       struct Timestamp last_sync;
+       struct PortAddress *paddr;
+       struct ptp_message *tmp;
+       unsigned char *ptr;
+
+       last_sync = tmv_to_Timestamp(clock_ingress_time(p->clock));
+       pid = dad->pds.parentPortIdentity.clockIdentity;
+
+       head = (struct nsm_resp_tlv_head *) m->delay_resp.suffix;
+       head->type = TLV_PTPMON_RESP;
+       head->port_state = p->state == PS_GRAND_MASTER ? PS_MASTER : p->state;
+
+       paddr = &head->parent_addr;
+
+       if (best && memcmp(&cid, &pid, sizeof(cid))) {
+               /* Extract the parent's protocol address. */
+               paddr->networkProtocol = transport_type(best->trp);
+               paddr->addressLength =
+                       transport_protocol_addr(best->trp, paddr->address);
+               if (best->best) {
+                       tmp = TAILQ_FIRST(&best->best->messages);
+                       extract_address(tmp, paddr);
+               }
+       } else {
+               /* We are our own parent. */
+               paddr->networkProtocol = transport_type(p->trp);
+               paddr->addressLength =
+                       transport_protocol_addr(p->trp, paddr->address);
+       }
+
+       head->length = sizeof(*head) + sizeof(*foot) + paddr->addressLength
+               - sizeof(head->type) - sizeof(head->length);
+
+       ptr = (unsigned char *) head;
+       ptr += sizeof(*head) + paddr->addressLength;
+       foot = (struct nsm_resp_tlv_foot *) ptr;
+
+       memcpy(&foot->parent, &dad->pds, sizeof(foot->parent));
+       memcpy(&foot->current, cds, sizeof(foot->current));
+       memcpy(&foot->timeprop, tp, sizeof(foot->timeprop));
+       memcpy(&foot->lastsync, &last_sync, sizeof(foot->lastsync));
+
+       m->tlv_count = 1;
+       return sizeof(*head) + sizeof(*foot) + paddr->addressLength;
+}
+
 static struct follow_up_info_tlv *follow_up_info_extract(struct ptp_message *m)
 {
        struct follow_up_info_tlv *f;
@@ -660,6 +739,28 @@ static int port_ignore(struct port *p, struct ptp_message 
*m)
        return 0;
 }
 
+static int port_nsm_reply(struct port *p, struct ptp_message *m)
+{
+       struct TLV *tlv = (struct TLV *) m->delay_req.suffix;
+
+       if (!p->net_sync_monitor) {
+               return 0;
+       }
+       if (!p->hybrid_e2e) {
+               return 0;
+       }
+       if (!(m->header.flagField[0] & UNICAST)) {
+               return 0;
+       }
+       if (!m->tlv_count) {
+               return 0;
+       }
+       if (tlv->type != TLV_PTPMON_REQ) {
+               return 0;
+       }
+       return 1;
+}
+
 /*
  * Test whether a 802.1AS port may transmit a sync message.
  */
@@ -1642,10 +1743,12 @@ static int process_announce(struct port *p, struct 
ptp_message *m)
 
 static int process_delay_req(struct port *p, struct ptp_message *m)
 {
+       int err, nsm, pdulen, saved_seqnum_sync;
        struct ptp_message *msg;
-       int err;
 
-       if (p->state != PS_MASTER && p->state != PS_GRAND_MASTER)
+       nsm = port_nsm_reply(p, m);
+
+       if (!nsm && p->state != PS_MASTER && p->state != PS_GRAND_MASTER)
                return 0;
 
        if (p->delayMechanism == DM_P2P) {
@@ -1657,11 +1760,14 @@ static int process_delay_req(struct port *p, struct 
ptp_message *m)
        if (!msg)
                return -1;
 
+       pdulen = sizeof(struct delay_resp_msg);
        msg->hwts.type = p->timestamping;
-
+       if (nsm) {
+               pdulen += net_sync_resp_append(p, msg);
+       }
        msg->header.tsmt               = DELAY_RESP | p->transportSpecific;
        msg->header.ver                = PTP_VERSION;
-       msg->header.messageLength      = sizeof(struct delay_resp_msg);
+       msg->header.messageLength      = pdulen;
        msg->header.domainNumber       = m->header.domainNumber;
        msg->header.correction         = m->header.correction;
        msg->header.sourcePortIdentity = p->portIdentity;
@@ -1680,8 +1786,17 @@ static int process_delay_req(struct port *p, struct 
ptp_message *m)
        }
 
        err = port_prepare_and_send(p, msg, 0);
-       if (err)
+       if (err) {
                pr_err("port %hu: send delay response failed", portnum(p));
+               goto out;
+       }
+       if (nsm) {
+               saved_seqnum_sync = p->seqnum.sync;
+               p->seqnum.sync = m->header.sequenceId;
+               err = port_tx_sync(p, &m->address);
+               p->seqnum.sync = saved_seqnum_sync;
+       }
+out:
        msg_put(msg);
        return err;
 }
@@ -2705,6 +2820,9 @@ struct port *port_open(int phc_index,
        if (p->hybrid_e2e && p->delayMechanism != DM_E2E) {
                pr_warning("port %d: hybrid_e2e only works with E2E", number);
        }
+       if (p->net_sync_monitor && !p->hybrid_e2e) {
+               pr_warning("port %d: net_sync_monitor needs hybrid_e2e", 
number);
+       }
 
        /* Set fault timeouts to a default value */
        for (i = 0; i < FT_CNT; i++) {
-- 
2.11.0


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to