- adding organizational TLV support for interface rate - delay asymmetry calculation for master and slave
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 | 12 ++++++++++++ clock.h | 14 ++++++++++++++ config.c | 1 + interface.c | 15 +++++++++++++++ interface.h | 7 +++++++ pdt.h | 1 + port_private.h | 1 + port_signaling.c | 33 ++++++++++++++++++++++++++++++++- ptp4l.8 | 6 ++++++ tlv.c | 1 + tlv.h | 14 ++++++++++++++ unicast_service.c | 35 +++++++++++++++++++++++++++++++++++ 12 files changed, 139 insertions(+), 1 deletion(-) diff --git a/clock.c b/clock.c index 8f328e5..e271f5a 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; @@ -1107,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; @@ -1718,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; @@ -2083,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..d38ef6a 100644 --- a/clock.h +++ b/clock.h @@ -388,4 +388,18 @@ 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); + +/** + * 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); + #endif diff --git a/config.c b/config.c index 6ba9996..90040de 100644 --- a/config.c +++ b/config.c @@ -240,6 +240,7 @@ struct config_item config_tab[] = { GLOB_ITEM_ENU("clock_type", CLOCK_TYPE_ORDINARY, clock_type_enu), GLOB_ITEM_ENU("dataset_comparison", DS_CMP_IEEE1588, dataset_comp_enu), PORT_ITEM_INT("delayAsymmetry", 0, INT_MIN, INT_MAX), + GLOB_ITEM_INT("interface_rate_tlv", 0, 0, 1), PORT_ITEM_ENU("delay_filter", FILTER_MOVING_MEDIAN, delay_filter_enu), PORT_ITEM_INT("delay_filter_length", 10, 1, INT_MAX), PORT_ITEM_ENU("delay_mechanism", DM_E2E, delay_mech_enu), diff --git a/interface.c b/interface.c index 44d6588..d186455 100644 --- a/interface.c +++ b/interface.c @@ -99,3 +99,18 @@ int interface_get_vclock(struct interface *iface) { return iface->vclock; } + +uint64_t interface_bitperiod(struct interface *iface) +{ + /* 10^18 atto-sec per bit*/ + uint64_t if_atto_sec_bit_period = 0x0DE0B6B3A7640000; + + if (!iface->if_info.valid) { + return 0; + } + + if_atto_sec_bit_period /= iface->if_info.speed; + if_atto_sec_bit_period /= 1000000; /* 1 Mb = 10^6 */ + return if_atto_sec_bit_period; + +} diff --git a/interface.h b/interface.h index fbbe919..4303568 100644 --- a/interface.h +++ b/interface.h @@ -119,4 +119,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/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_private.h b/port_private.h index d27dceb..d1a1e76 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..78db221 100644 --- a/port_signaling.c +++ b/port_signaling.c @@ -103,10 +103,38 @@ 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; + 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 +189,13 @@ 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/ptp4l.8 b/ptp4l.8 index e33454a..01b0d0f 100644 --- a/ptp4l.8 +++ b/ptp4l.8 @@ -705,6 +705,12 @@ the interval, the sample will be printed instead of the statistics. The messages are printed at the LOG_INFO level. The default is 0 (1 second). .TP +.B interface_rate_tlv +When master and slave instances are operating at different interface rate, +delay asymmetry caused due to different interface rate needs to be compensated. +The master and slave exhanges their interface rate based on interface rate TLV +as per G.8275.2 Annex D. +The default is 0 (does not support interface rate tlv). .B time_stamping The time stamping method to be used. The allowed values are hardware, software, legacy, onestep, and p2p1step. 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..ec22e2f 100644 --- a/tlv.h +++ b/tlv.h @@ -395,6 +395,20 @@ struct tlv_extra { }; }; +/* 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; + /** * 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..d7bcc42 100644 --- a/unicast_service.c +++ b/unicast_service.c @@ -84,6 +84,31 @@ 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 +281,16 @@ 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