When master and slave instance interacting with each other operating
at different interface speed, delay assymetry needs to be compensated
as described in G.8271 appendix V.

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>
---
 clock.c             | 14 ++++++++++
 clock.h             | 14 ++++++++++
 config.c            |  1 +
 configs/default.cfg |  1 +
 interface.c         | 50 ++++++++++++++++++++++++++++++++++
 interface.h         | 21 +++++++++++++++
 pdt.h               |  1 +
 port.c              |  5 ++++
 port_private.h      |  1 +
 port_signaling.c    | 34 ++++++++++++++++++++++++
 sk.c                | 65 +++++++++++++++++++++++++++++++++++++++++++++
 sk.h                | 18 +++++++++++++
 tlv.c               |  1 +
 tlv.h               | 16 +++++++++++
 unicast_service.c   | 33 +++++++++++++++++++++++
 15 files changed, 275 insertions(+)

diff --git a/clock.c b/clock.c
index f808b35..695f818 100644
--- a/clock.c
+++ b/clock.c
@@ -137,6 +137,7 @@ struct clock {
        struct monitor *slave_event_monitor;
        int step_window_counter;
        int step_window;
+       bool iface_rate_tlv;
 };
 
 struct clock the_clock;
@@ -1005,6 +1006,8 @@ struct clock *clock_create(enum clock_type type, struct 
config *config,
                rtnl_get_ts_device(interface_name(iface), ts_label);
                interface_set_label(iface, ts_label);
                interface_ensure_tslabel(iface);
+               /* Interface speed information */
+               interface_get_ifinfo(iface);
                interface_get_tsinfo(iface);
                if (interface_tsinfo_valid(iface) &&
                    !interface_tsmodes_supported(iface, required_modes)) {
@@ -1105,6 +1108,7 @@ struct clock *clock_create(enum clock_type type, struct 
config *config,
        c->utc_offset = config_get_int(config, NULL, "utc_offset");
        c->time_source = config_get_int(config, NULL, "timeSource");
        c->step_window = config_get_int(config, NULL, "step_window");
+       c->iface_rate_tlv = config_get_int(config, NULL, "interface_rate_tlv");
 
        if (c->free_running) {
                c->clkid = CLOCK_INVALID;
@@ -1716,6 +1720,11 @@ int clock_slave_only(struct clock *c)
        return c->dds.flags & DDS_SLAVE_ONLY;
 }
 
+bool clock_telecom_profile(struct clock *c)
+{
+       return (c->dscmp == telecom_dscmp);
+}
+
 UInteger8 clock_max_steps_removed(struct clock *c)
 {
        return c->max_steps_removed;
@@ -2081,3 +2090,8 @@ enum servo_state clock_servo_state(struct clock *c)
 {
        return c->servo_state;
 }
+
+bool clock_interface_rate_tlv (struct clock *c)
+{
+       return c->iface_rate_tlv;
+}
diff --git a/clock.h b/clock.h
index 0534f21..9b2738a 100644
--- a/clock.h
+++ b/clock.h
@@ -289,6 +289,13 @@ int clock_slave_only(struct clock *c);
  */
 UInteger8 clock_max_steps_removed(struct clock *c);
 
+/**
+ * Obtain the clock is set for telecom profile .
+ * @param c  The clock instance.
+ * @return   True if the profile is telecom, false otherwise.
+ */
+bool clock_telecom_profile(struct clock *c);
+
 /**
  * Obtain the clock class threshold field from a clock's default data set.
  * @param c  The clock instance.
@@ -388,4 +395,11 @@ void clock_check_ts(struct clock *c, uint64_t ts);
  */
 double clock_rate_ratio(struct clock *c);
 
+/**
+ * Obtain interface rate tlv support configuration.
+ * @param c  The clock instance.
+ * @return   The interface_rate_supoort config true if supported, else false.
+ */
+bool clock_interface_rate_tlv (struct clock *c);
+
 #endif
diff --git a/config.c b/config.c
index 6ba9996..0419423 100644
--- a/config.c
+++ b/config.c
@@ -266,6 +266,7 @@ struct config_item config_tab[] = {
        PORT_ITEM_INT("inhibit_delay_req", 0, 0, 1),
        PORT_ITEM_INT("inhibit_multicast_service", 0, 0, 1),
        GLOB_ITEM_INT("initial_delay", 0, 0, INT_MAX),
+       GLOB_ITEM_INT("interface_rate_tlv", 0, 0, 1),
        GLOB_ITEM_INT("kernel_leap", 1, 0, 1),
        GLOB_ITEM_STR("leapfile", NULL),
        PORT_ITEM_INT("logAnnounceInterval", 1, INT8_MIN, INT8_MAX),
diff --git a/configs/default.cfg b/configs/default.cfg
index 1b5b806..4c40a03 100644
--- a/configs/default.cfg
+++ b/configs/default.cfg
@@ -19,6 +19,7 @@ dscp_general          0
 dataset_comparison     ieee1588
 G.8275.defaultDS.localPriority 128
 maxStepsRemoved                255
+interface_rate_tlv     0
 #
 # Port Data Set
 #
diff --git a/interface.c b/interface.c
index 445a270..8559f62 100644
--- a/interface.c
+++ b/interface.c
@@ -12,6 +12,7 @@ struct interface {
        char name[MAX_IFNAME_SIZE + 1];
        char ts_label[MAX_IFNAME_SIZE + 1];
        struct sk_ts_info ts_info;
+       struct sk_if_info if_info;
        int vclock;
 };
 
@@ -46,6 +47,11 @@ int interface_get_tsinfo(struct interface *iface)
        return sk_get_ts_info(iface->ts_label, &iface->ts_info);
 }
 
+int interface_get_ifinfo(struct interface *iface)
+{
+       return sk_get_if_info(iface->ts_label, &iface->if_info);
+}
+
 const char *interface_label(struct interface *iface)
 {
        return iface->ts_label;
@@ -71,6 +77,11 @@ bool interface_tsinfo_valid(struct interface *iface)
        return iface->ts_info.valid ? true : false;
 }
 
+bool interface_ifinfo_valid(struct interface *iface)
+{
+       return iface->if_info.valid ? true : false;
+}
+
 bool interface_tsmodes_supported(struct interface *iface, int modes)
 {
        if ((iface->ts_info.so_timestamping & modes) == modes) {
@@ -88,3 +99,42 @@ int interface_get_vclock(struct interface *iface)
 {
        return iface->vclock;
 }
+
+uint64_t interface_bitperiod(struct interface *iface)
+{
+       uint64_t if_atto_sec_bit_period = 0;
+
+       if (!iface->if_info.valid)
+       return if_atto_sec_bit_period;
+
+       switch (iface->if_info.speed) {
+               case 1:
+                       if_atto_sec_bit_period = 0x0DE0B6B3A7640000;
+                       break;
+               case 10:
+                       if_atto_sec_bit_period = 0x000000174876E800;
+                       break;
+               case 100:
+                       if_atto_sec_bit_period = 0x00000002540BE400;
+                       break;
+               case 1000:
+                       if_atto_sec_bit_period = 0x000000003B9ACA00;
+                       break;
+               case 10000:
+                       if_atto_sec_bit_period = 0x0000000005F5E100;
+                       break;
+               case 25000:
+                       if_atto_sec_bit_period = 0x0000000002625A00;
+                       break;
+               case 40000:
+                       if_atto_sec_bit_period = 0x00000000017D7840;
+                       break;
+               case 100000:
+                       if_atto_sec_bit_period = 0x0000000000989680;
+                       break;
+               case 1000000:
+                       if_atto_sec_bit_period = 0x00000000000F4240;
+                       break;
+       }
+       return if_atto_sec_bit_period;
+}
diff --git a/interface.h b/interface.h
index 752f4f1..d9fce5c 100644
--- a/interface.h
+++ b/interface.h
@@ -46,6 +46,13 @@ void interface_ensure_tslabel(struct interface *iface);
  */
 int interface_get_tsinfo(struct interface *iface);
 
+/**
+ * Populate the time stamping information of a given interface.
+ * @param iface  The interface of interest.
+ * @return       zero on success, negative on failure.
+ */
+int interface_get_ifinfo(struct interface *iface);
+
 /**
  * Obtain the time stamping label of a network interface.  This can be
  * different from the name of the interface when bonding is in effect.
@@ -83,6 +90,13 @@ void interface_set_label(struct interface *iface, const char 
*label);
  */
 bool interface_tsinfo_valid(struct interface *iface);
 
+/**
+ * Tests whether an interface's interface information is valid or not.
+ * @param iface  The interface of interest.
+ * @return       True if the interface information is valid, false otherwise.
+ */
+bool interface_ifinfo_valid(struct interface *iface);
+
 /**
  * Tests whether an interface supports a set of given time stamping modes.
  * @param iface  The interface of interest.
@@ -91,6 +105,13 @@ bool interface_tsinfo_valid(struct interface *iface);
  */
 bool interface_tsmodes_supported(struct interface *iface, int modes);
 
+/**
+ * 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);
+
 /**
  * Set the vclock (virtual PHC) to be used for timestamping on an interface.
  * @param iface  The interface of interest.
diff --git a/pdt.h b/pdt.h
index e46b218..1ad23d4 100644
--- a/pdt.h
+++ b/pdt.h
@@ -39,6 +39,7 @@ typedef uint16_t  UInteger16;
 typedef int32_t   Integer32;
 typedef uint32_t  UInteger32;
 typedef int64_t   Integer64;
+typedef uint64_t  UInteger64;
 typedef uint8_t   Octet;
 
 #endif
diff --git a/port.c b/port.c
index d9dac38..b93225b 100644
--- a/port.c
+++ b/port.c
@@ -2690,6 +2690,11 @@ void port_link_status(void *ctx, int linkup, int 
ts_index)
                p->link_status = link_state;
        } else {
                p->link_status = link_state | LINK_STATE_CHANGED;
+               /* Update Interface speed information on Link up*/
+               if (linkup) {
+                       interface_get_ifinfo(p->iface);
+               }
+
                pr_notice("%s: link %s", p->log_name, linkup ? "up" : "down");
        }
 
diff --git a/port_private.h b/port_private.h
index d27dceb..6c8eba8 100644
--- a/port_private.h
+++ b/port_private.h
@@ -145,6 +145,7 @@ struct port {
        UInteger8           versionNumber; /* UInteger4 */
        UInteger8           delay_response_counter;
        UInteger8           delay_response_timeout;
+       Integer64           portAsymmetry;
        struct PortStats    stats;
        struct PortServiceStats    service_stats;
        /* foreignMasterDS */
diff --git a/port_signaling.c b/port_signaling.c
index ed217c0..ccc1b11 100644
--- a/port_signaling.c
+++ b/port_signaling.c
@@ -22,6 +22,7 @@
 #include "print.h"
 #include "unicast_client.h"
 #include "unicast_service.h"
+#include "clock.h"
 
 const struct PortIdentity wildcard_pid = {
        .clockIdentity = {
@@ -103,10 +104,39 @@ 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;
+
+       if (clock_interface_rate_tlv (p->clock) &&
+                       interface_ifinfo_valid(p->iface)) {
+               /* Delay Asymmetry Calculation */
+               delayAsymmetry  = r->interfaceBitPeriod -
+                       interface_bitperiod(p->iface);
+               delayAsymmetry  = delayAsymmetry/2;
+               nsDelay = (double)delayAsymmetry / 1000000000;
+               if (nsDelay) {
+                       delayAsymmetry =
+                               (r->numberOfBitsAfterTimestamp -
+                                r->numberOfBitsBeforeTimestamp)  * nsDelay;
+                       if (delayAsymmetry != p->portAsymmetry) {
+                               /* Updating the nanosecond part */
+                               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 msg_interval_req_tlv *r;
+       struct msg_interface_rate_tlv *rate;
        int err = 0, result;
 
        switch (p->state) {
@@ -161,10 +191,14 @@ int process_signaling(struct port *p, struct ptp_message 
*m)
 
                case TLV_ORGANIZATION_EXTENSION:
                        r = (struct msg_interval_req_tlv *) extra->tlv;
+                       rate = (struct msg_interface_rate_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)
                                err = process_interval_request(p, r);
+                       else if (0 == memcmp(r->id, itu_t_id, sizeof(itu_t_id)) 
&&
+                           r->subtype[0] == 0 && r->subtype[1] == 0 && 
r->subtype[2] == 2)
+                               err = process_interface_rate(p, rate);
                        break;
                }
        }
diff --git a/sk.c b/sk.c
index b55d6b5..6a0fc5e 100644
--- a/sk.c
+++ b/sk.c
@@ -200,6 +200,71 @@ failed:
        return -1;
 }
 
+int sk_get_if_info(const char *name, struct sk_if_info *if_info)
+{
+#ifdef ETHTOOL_GLINKSETTINGS
+       struct ifreq ifr;
+       int fd, err;
+
+       struct {
+               struct ethtool_link_settings req;
+               __u32 link_mode_data[3 * 127];
+       } ecmd;
+
+       memset(&ifr, 0, sizeof(ifr));
+       memset(&ecmd, 0, sizeof(ecmd));
+
+       fd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fd < 0) {
+               goto failed;
+       }
+
+       ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
+
+       strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
+       ifr.ifr_data = (char *) &ecmd;
+
+       /* Handshake with kernel to determine number of words for link
+        * mode bitmaps. When requested number of bitmap words is not
+        * the one expected by kernel, the latter returns the integer
+        * opposite of what it is expecting. We request length 0 below
+        * (aka. invalid bitmap length) to get this info.
+        */
+       err = ioctl(fd, SIOCETHTOOL, &ifr);
+       if (err < 0) {
+               pr_err("ioctl SIOCETHTOOL failed: %m");
+               close(fd);
+               goto failed;
+       }
+
+       if (ecmd.req.link_mode_masks_nwords >= 0 ||
+                       ecmd.req.cmd != ETHTOOL_GLINKSETTINGS) {
+               return 1;
+       }
+       ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords;
+
+       err = ioctl(fd, SIOCETHTOOL, &ifr);
+       if (err < 0) {
+               pr_err("ioctl SIOCETHTOOL failed: %m");
+               close(fd);
+               goto failed;
+       }
+
+       close(fd);
+
+       /* copy the necessary data to sk_info */
+       memset(if_info, 0, sizeof(struct sk_if_info));
+       if_info->valid = 1;
+       if_info->speed = ecmd.req.speed;
+
+       return 0;
+failed:
+#endif
+       /* clear data and ensure it is not marked valid */
+       memset(if_info, 0, sizeof(struct sk_if_info));
+       return -1;
+}
+
 static int sk_interface_guidaddr(const char *name, unsigned char *guid)
 {
        char file_name[64], buf[64], addr[8];
diff --git a/sk.h b/sk.h
index 486dbc4..853aadf 100644
--- a/sk.h
+++ b/sk.h
@@ -49,6 +49,16 @@ struct sk_ts_info {
        unsigned int rx_filters;
 };
 
+/**
+ * Contains interface information returned by theGLINKSETTINGS ioctl.
+ * @valid:            set to non-zero when the info struct contains valid data.
+ * @speed:            interface speed.
+ */
+struct sk_if_info {
+       int valid;
+       int speed;
+};
+
 /**
  * Obtains a socket suitable for use with sk_interface_index().
  * @return  An open socket on success, -1 otherwise.
@@ -78,6 +88,14 @@ int sk_general_init(int fd);
  */
 int sk_get_ts_info(const char *name, struct sk_ts_info *sk_info);
 
+/**
+ * Obtain supporte interface information
+ * @param name     The name of the interface
+ * @param info      Struct containing obtained interface information.
+ * @return          zero on success, negative on failure.
+ */
+int sk_get_if_info(const char *name, struct sk_if_info *sk_info);
+
 /**
  * Obtain the MAC address of a network interface.
  * @param name  The name of the interface
diff --git a/tlv.c b/tlv.c
index 1c13460..35bee4f 100644
--- a/tlv.c
+++ b/tlv.c
@@ -35,6 +35,7 @@
        (tlv->length < sizeof(struct type) - sizeof(struct TLV))
 
 uint8_t ieee8021_id[3] = { IEEE_802_1_COMMITTEE };
+uint8_t itu_t_id[3] = { ITU_T_COMMITTEE };
 
 static TAILQ_HEAD(tlv_pool, tlv_extra) tlv_pool =
        TAILQ_HEAD_INITIALIZER(tlv_pool);
diff --git a/tlv.h b/tlv.h
index 8966696..573af89 100644
--- a/tlv.h
+++ b/tlv.h
@@ -312,6 +312,20 @@ struct msg_interval_req_tlv {
        Octet         reserved[2];
 } PACKED;
 
+/* Organizationally Unique Identifiers */
+#define ITU_T_COMMITTEE 0x00, 0x19, 0xA7
+extern uint8_t itu_t_id[3];
+
+struct msg_interface_rate_tlv {
+       Enumeration16 type;
+       UInteger16    length;
+       Octet         id[3];
+       Octet         subtype[3];
+       UInteger64    interfaceBitPeriod;
+       UInteger16    numberOfBitsBeforeTimestamp;
+       UInteger16    numberOfBitsAfterTimestamp;
+} PACKED;
+
 struct time_status_np {
        int64_t       master_offset; /*nanoseconds*/
        int64_t       ingress_time;  /*nanoseconds*/
@@ -395,6 +409,8 @@ struct tlv_extra {
        };
 };
 
+extern uint8_t itu_t_id[3];
+
 /**
  * Allocates a new tlv_extra structure.
  * @return  Pointer to a new structure on success or NULL otherwise.
diff --git a/unicast_service.c b/unicast_service.c
index 3154894..8ca2214 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,15 @@ static int unicast_service_reply(struct port *p, struct 
ptp_message *dst,
        if (err) {
                goto out;
        }
+       if (clock_interface_rate_tlv (p->clock) && duration > 0 &&
+               clock_telecom_profile(p->clock) &&
+               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.17.1



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

Reply via email to