Delay asymmetry calculation based on the PTP port interface speed of
master obtained from TLV and the slave interface rate obtained by ethtool.

v3: updating network/host byte order handling.
v1: initial commit

Signed-off-by: Greg Armstrong <greg.armstrong...@renesas.com>
Signed-off-by: Leon Goldin <leon.goldin...@renesas.com>
Signed-off-by: Devasish Dey <devasish....@syncmonk.net>
Signed-off-by: Vipin Sharma <vipin.sha...@syncmonk.net>
---
 interface.c       | 10 ++++++++++
 interface.h       |  7 +++++++
 port_private.h    |  1 +
 port_signaling.c  | 39 ++++++++++++++++++++++++++++++++++++---
 ptp4l.8           |  7 +++++++
 tlv.c             | 29 +++++++++++++++++++++++++++++
 unicast_service.c | 32 ++++++++++++++++++++++++++++++++
 7 files changed, 122 insertions(+), 3 deletions(-)

diff --git a/interface.c b/interface.c
index 3157e8c..02d530e 100644
--- a/interface.c
+++ b/interface.c
@@ -94,3 +94,13 @@ int interface_get_vclock(struct interface *iface)
 {
        return iface->vclock;
 }
+
+uint64_t interface_bitperiod(struct interface *iface)
+{
+       if (!iface->if_info.valid)
+               return 0;
+
+       /* Megabits per secon converted to attoseconds per bit. */
+       return 1000000000000ULL/ iface->if_info.speed;
+}
+
diff --git a/interface.h b/interface.h
index f4b9545..7c9a6bd 100644
--- a/interface.h
+++ b/interface.h
@@ -113,4 +113,11 @@ void interface_set_vclock(struct interface *iface, int 
vclock);
  */
 int interface_get_vclock(struct interface *iface);
 
+/**
+ * Obtains the interface bit period based on the speed.
+ * @param iface  The interface of interest.
+ * @return       if valid speed return interface bitperiod in atto seconds.
+ */
+uint64_t interface_bitperiod(struct interface *iface);
+
 #endif
diff --git a/port_private.h b/port_private.h
index d6487eb..6ad4af8 100644
--- a/port_private.h
+++ b/port_private.h
@@ -146,6 +146,7 @@ struct port {
        UInteger8           delay_response_counter;
        UInteger8           delay_response_timeout;
        bool                iface_rate_tlv;
+       Integer64           portAsymmetry;
        struct PortStats    stats;
        struct PortServiceStats    service_stats;
        /* foreignMasterDS */
diff --git a/port_signaling.c b/port_signaling.c
index ed217c0..75a0689 100644
--- a/port_signaling.c
+++ b/port_signaling.c
@@ -103,10 +103,37 @@ static int process_interval_request(struct port *p,
        return 0;
 }
 
+static int process_interface_rate(struct port *p,
+                                 struct msg_interface_rate_tlv *r)
+{
+       Integer64 delayAsymmetry;
+       double    nsDelay;
+       Integer64 slaveBitPeriod;
+       Integer64 masterBitPeriod;
+
+       if (p->iface_rate_tlv && interface_ifinfo_valid(p->iface)) {
+               slaveBitPeriod = interface_bitperiod(p->iface);
+               masterBitPeriod = r->interfaceBitPeriod;
+
+               /* Delay Asymmetry Calculation */
+               nsDelay = (masterBitPeriod - slaveBitPeriod) / (2 * 1.0e9);
+               delayAsymmetry =
+                       (r->numberOfBitsAfterTimestamp - 
r->numberOfBitsBeforeTimestamp)  * nsDelay;
+
+               if (delayAsymmetry != p->portAsymmetry) {
+                       p->asymmetry += ((delayAsymmetry - p->portAsymmetry) << 
16);
+                       p->portAsymmetry = delayAsymmetry;
+               }
+       }
+       return 0;
+}
+
 int process_signaling(struct port *p, struct ptp_message *m)
 {
        struct tlv_extra *extra;
+       struct organization_tlv *org;
        struct msg_interval_req_tlv *r;
+       struct msg_interface_rate_tlv *rate;
        int err = 0, result;
 
        switch (p->state) {
@@ -160,11 +187,17 @@ int process_signaling(struct port *p, struct ptp_message 
*m)
                        break;
 
                case TLV_ORGANIZATION_EXTENSION:
-                       r = (struct msg_interval_req_tlv *) extra->tlv;
+                       org = (struct organization_tlv *)extra->tlv;
 
-                       if (0 == memcmp(r->id, ieee8021_id, 
sizeof(ieee8021_id)) &&
-                           r->subtype[0] == 0 && r->subtype[1] == 0 && 
r->subtype[2] == 2)
+                       if (0 == memcmp(org->id, ieee8021_id, 
sizeof(ieee8021_id)) &&
+                           org->subtype[0] == 0 && org->subtype[1] == 0 && 
org->subtype[2] == 2) {
+                               r = (struct msg_interval_req_tlv *) extra->tlv;
                                err = process_interval_request(p, r);
+                       } else if (0 == memcmp(org->id, itu_t_id, 
sizeof(itu_t_id)) &&
+                                  org->subtype[0] == 0 && org->subtype[1] == 0 
&& org->subtype[2] == 2) {
+                               rate = (struct msg_interface_rate_tlv *) 
extra->tlv;
+                               err = process_interface_rate(p, rate);
+                       }
                        break;
                }
        }
diff --git a/ptp4l.8 b/ptp4l.8
index cd6299f..e96d090 100644
--- a/ptp4l.8
+++ b/ptp4l.8
@@ -697,6 +697,13 @@ The default is 0 (disabled).
 Print messages to the system log if enabled.
 The default is 1 (enabled).
 .TP
+.B interface_rate_tlv
+When the client and server are operating are operating at different interface 
rate,
+delay asymmetry caused due to different interface rate needs to be compensated.
+The server sends its interface rate using interface rate TLV
+as per G.8275.2 Annex D.
+The default is 0 (does not support interface rate tlv).
+.TP
 .B summary_interval
 The time interval in which are printed summary statistics of the clock. It is
 specified as a power of two in seconds. The statistics include offset root mean
diff --git a/tlv.c b/tlv.c
index 35bee4f..7a2a4fa 100644
--- a/tlv.c
+++ b/tlv.c
@@ -681,6 +681,7 @@ static void nsm_resp_pre_send(struct tlv_extra *extra)
 static int org_post_recv(struct organization_tlv *org)
 {
        struct follow_up_info_tlv *f;
+       struct msg_interface_rate_tlv *m;
 
        if (0 == memcmp(org->id, ieee8021_id, sizeof(ieee8021_id))) {
                if (org->subtype[0] || org->subtype[1]) {
@@ -701,6 +702,21 @@ static int org_post_recv(struct organization_tlv *org)
                        if (org->length + sizeof(struct TLV) != sizeof(struct 
msg_interval_req_tlv))
                                goto bad_length;
                }
+       } else if (0 == memcmp(org->id, itu_t_id, sizeof(itu_t_id))) {
+               if (org->subtype[0] || org->subtype[1]) {
+                       return 0;
+               }
+               switch (org->subtype[2]) {
+               case 2:
+                       if (org->length + sizeof(struct TLV) != sizeof(struct 
msg_interface_rate_tlv))
+                               goto bad_length;
+                       m = (struct msg_interface_rate_tlv *)org;
+                       m->interfaceBitPeriod = 
net2host64(m->interfaceBitPeriod);
+                       m->numberOfBitsBeforeTimestamp = 
ntohs(m->numberOfBitsBeforeTimestamp);
+                       m->numberOfBitsAfterTimestamp = 
ntohs(m->numberOfBitsAfterTimestamp);
+                       break;
+               }
+
        }
        return 0;
 bad_length:
@@ -710,6 +726,7 @@ bad_length:
 static void org_pre_send(struct organization_tlv *org)
 {
        struct follow_up_info_tlv *f;
+       struct msg_interface_rate_tlv *m;
 
        if (0 == memcmp(org->id, ieee8021_id, sizeof(ieee8021_id))) {
                if (org->subtype[0] || org->subtype[1]) {
@@ -724,6 +741,18 @@ static void org_pre_send(struct organization_tlv *org)
                        f->scaledLastGmPhaseChange = 
htonl(f->scaledLastGmPhaseChange);
                        break;
                }
+       } else if (0 == memcmp(org->id, itu_t_id, sizeof(itu_t_id))) {
+               if (org->subtype[0] || org->subtype[1]) {
+                       return;
+               }
+               switch (org->subtype[2]) {
+               case 2:
+                       m = (struct msg_interface_rate_tlv *)org;
+                       m->interfaceBitPeriod = 
host2net64(m->interfaceBitPeriod);
+                       m->numberOfBitsBeforeTimestamp = 
htons(m->numberOfBitsBeforeTimestamp);
+                       m->numberOfBitsAfterTimestamp = 
htons(m->numberOfBitsAfterTimestamp);
+                       break;
+               }
        }
 }
 
diff --git a/unicast_service.c b/unicast_service.c
index 3154894..1078041 100644
--- a/unicast_service.c
+++ b/unicast_service.c
@@ -84,6 +84,30 @@ static int attach_grant(struct ptp_message *msg,
        return 0;
 }
 
+static int attach_interface_rate(struct ptp_message *msg,
+                                uint64_t iface_bit_period,
+                                uint16_t  no_of_bits_before_ts,
+                                uint16_t  no_of_bits_after_ts)
+{
+       struct msg_interface_rate_tlv *mir;
+       struct tlv_extra *extra;
+
+       extra = msg_tlv_append(msg, sizeof(*mir));
+       if (!extra) {
+               return -1;
+       }
+       mir = (struct msg_interface_rate_tlv *) extra->tlv;
+       mir->type = TLV_ORGANIZATION_EXTENSION;
+       mir->length = sizeof(*mir) - sizeof(mir->type) - sizeof(mir->length);
+       memcpy(mir->id, itu_t_id, sizeof(itu_t_id));
+       mir->subtype[2] = 2;
+       mir->interfaceBitPeriod = iface_bit_period;
+       mir->numberOfBitsBeforeTimestamp = no_of_bits_before_ts;
+       mir->numberOfBitsAfterTimestamp = no_of_bits_after_ts;
+
+       return 0;
+}
+
 static int compare_timeout(void *ain, void *bin)
 {
        struct unicast_service_interval *a, *b;
@@ -256,6 +280,14 @@ static int unicast_service_reply(struct port *p, struct 
ptp_message *dst,
        if (err) {
                goto out;
        }
+       if (p->iface_rate_tlv && duration > 0 && 
interface_ifinfo_valid(p->iface)) {
+               err = attach_interface_rate(msg,
+                               interface_bitperiod(p->iface), 64, 720);
+               if (err) {
+                       goto out;
+               }
+       }
+
        err = port_prepare_and_send(p, msg, TRANS_GENERAL);
        if (err) {
                pr_err("%s: signaling message failed", p->log_name);
-- 
2.34.1



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

Reply via email to