Thread: [Linuxptp-devel] [PATCH RFC v3 00/10] Profile support for IEEE C37.238-2011 and IEEE C37.238-2017
PTP IEEE 1588 stack for Linux
Brought to you by:
rcochran
|
From: Richard C. <ric...@gm...> - 2021-11-09 20:12:10
|
ChangeLog:
v3 First public release
v2 never published
v1 never published
The Power Profiles need two TLVs:
1. IEEE_C37_238 TLV
- New configuration option to enable the TLV.
- New configuration options for grandmasterID and default
totalTimeInaccuracy.
- New custom management message for changing totalTimeInaccuracy at
run time. This message allows switching the TLV from the 2017
format into the 2011 format by specifying grandmasterTimeInaccuracy
and networkTimeInaccuracy.
2. ALTERNATE_TIME_OFFSET_INDICATOR TLV
- New custom management message for enabling the TLV and setting
the TLV values.
- New helper program that computes the values from the local time
and the Linux time zone data base and then sends the values to
ptp4l. This method assumes that the local Linux system time and
the PHC clock are synchronized.
Comments and feedback are much appreciated!
Thanks,
Richard
Richard Cochran (10):
tlv: Encode and decode power profile TLVs.
Introduce the power profile.
Add a custom management message for power profile settings.
tlv: Encode and decode alternate time offset indicator TLVs.
Prepare clock based storage of up to four time zones.
Add the ALTERNATE_TIME_OFFSET_PROPERTIES management message.
Add the ALTERNATE_TIME_OFFSET_NAME management message.
Implement the ALTERNATE_TIME_OFFSET_ENABLE management message.
pmc: Convert internal helper function into global method.
Introduce a time zone helper program.
clock.c | 184 +++++++++++++++++++++--
clock.h | 8 +
config.c | 15 +-
makefile | 7 +-
pmc.c | 45 ++++++
pmc_common.c | 135 ++++++++++++++++-
pmc_common.h | 2 +
port.c | 76 +++++++++-
port_private.h | 3 +
power_profile.h | 31 ++++
tlv.c | 146 +++++++++++++++++++
tlv.h | 64 ++++++++
tz.h | 26 ++++
tztool.c | 377 ++++++++++++++++++++++++++++++++++++++++++++++++
util.h | 7 +
15 files changed, 1107 insertions(+), 19 deletions(-)
create mode 100644 power_profile.h
create mode 100644 tz.h
create mode 100644 tztool.c
--
2.20.1
|
|
From: Richard C. <ric...@gm...> - 2023-01-28 22:44:04
|
ChangeLog
~~~~~~~~~
v4:
Preserve all 48 bits of "next jump" (v3 review feedback from Erez Geva)
Accept the full range for domainNumber (suggested by v.nosikov)
v3:
Initial RFC
v2, v1:
never published
The Power Profile specifies two new TLVs:
1. IEEE_C37_238 TLV
- New configuration option to enable the TLV.
- New configuration options for grandmasterID and default
totalTimeInaccuracy.
- New custom management message for changing totalTimeInaccuracy at
run time. This message allows switching the TLV from the 2017
format into the 2011 format by specifying grandmasterTimeInaccuracy
and networkTimeInaccuracy.
2. ALTERNATE_TIME_OFFSET_INDICATOR TLV
- New custom management message for enabling the TLV and setting
the TLV values.
- New helper program that computes the values from the local time
and the Linux time zone data base and then sends the values to
ptp4l. This method assumes that the local Linux system time and
the PHC clock are synchronized.
Thanks,
Richard
*** BLURB HERE ***
Richard Cochran (11):
Accept the full range for domainNumber.
tlv: Encode and decode power profile TLVs.
Introduce the power profile.
Add a custom management message for power profile settings.
tlv: Encode and decode alternate time offset indicator TLVs.
Prepare clock based storage of up to four time zones.
Add the ALTERNATE_TIME_OFFSET_PROPERTIES management message.
Add the ALTERNATE_TIME_OFFSET_NAME management message.
Implement the ALTERNATE_TIME_OFFSET_ENABLE management message.
pmc: Convert internal helper function into global method.
Introduce a time zone helper program.
clock.c | 188 ++++++++++++++++++++++--
clock.h | 8 +
config.c | 17 ++-
makefile | 7 +-
pmc.c | 49 +++++++
pmc_common.c | 133 ++++++++++++++++-
pmc_common.h | 2 +
port.c | 76 +++++++++-
port_private.h | 3 +
power_profile.h | 31 ++++
tlv.c | 146 +++++++++++++++++++
tlv.h | 64 ++++++++
tz.h | 26 ++++
tztool.c | 377 ++++++++++++++++++++++++++++++++++++++++++++++++
util.h | 7 +
15 files changed, 1117 insertions(+), 17 deletions(-)
create mode 100644 power_profile.h
create mode 100644 tz.h
create mode 100644 tztool.c
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-01-28 22:44:02
|
IEEE Std C37.238 invented its own rules with respect to the range of
values allowed for the domainNumber attribute. The profile
"complies with IEEE Std 1588-2008 with the exception of the use of
the reserved domain 254. The value 254 is an exception granted to
this profile."
In addition, Table 2 of IEEE Std 1588-2019 presents an incoherent
Swiss cheese of allowed ranges, depending sdoId and network transport.
Avoid the standardized madness by allowing the user to simply choose
any domainNumber they want.
Signed-off-by: Richard Cochran <ric...@gm...>
---
config.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config.c b/config.c
index 08e3346..6684c9f 100644
--- a/config.c
+++ b/config.c
@@ -247,7 +247,7 @@ struct config_item config_tab[] = {
PORT_ITEM_INT("delay_response_timeout", 0, 0, UINT8_MAX),
GLOB_ITEM_INT("dscp_event", 0, 0, 63),
GLOB_ITEM_INT("dscp_general", 0, 0, 63),
- GLOB_ITEM_INT("domainNumber", 0, 0, 127),
+ GLOB_ITEM_INT("domainNumber", 0, 0, 255),
PORT_ITEM_INT("egressLatency", 0, INT_MIN, INT_MAX),
PORT_ITEM_INT("fault_badpeernet_interval", 16, INT32_MIN, INT32_MAX),
PORT_ITEM_INT("fault_reset_interval", 4, INT8_MIN, INT8_MAX),
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-01-28 22:44:04
|
Signed-off-by: Richard Cochran <ric...@gm...>
---
tlv.c | 36 ++++++++++++++++++++++++++++++++++++
tlv.h | 24 ++++++++++++++++++++++++
2 files changed, 60 insertions(+)
diff --git a/tlv.c b/tlv.c
index 1c13460..29d0556 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 ieeec37_238_id[3] = { IEEE_C37_238_PROFILE };
static TAILQ_HEAD(tlv_pool, tlv_extra) tlv_pool =
TAILQ_HEAD_INITIALIZER(tlv_pool);
@@ -679,6 +680,7 @@ static void nsm_resp_pre_send(struct tlv_extra *extra)
static int org_post_recv(struct organization_tlv *org)
{
+ struct ieee_c37_238_2017_tlv *p;
struct follow_up_info_tlv *f;
if (0 == memcmp(org->id, ieee8021_id, sizeof(ieee8021_id))) {
@@ -701,6 +703,24 @@ static int org_post_recv(struct organization_tlv *org)
goto bad_length;
}
}
+ if (0 == memcmp(org->id, ieeec37_238_id, sizeof(ieeec37_238_id))) {
+ if (org->subtype[0] || org->subtype[1]) {
+ return 0;
+ }
+ switch (org->subtype[2]) {
+ case 1:
+ case 2:
+ /* Layout of 2011 and 2017 messages is compatible. */
+ if (org->length + sizeof(struct TLV) !=
+ sizeof(struct ieee_c37_238_2017_tlv))
+ goto bad_length;
+ p = (struct ieee_c37_238_2017_tlv *) org;
+ NTOHS(p->grandmasterID);
+ NTOHL(p->reserved1);
+ NTOHL(p->totalTimeInaccuracy);
+ break;
+ }
+ }
return 0;
bad_length:
return -EBADMSG;
@@ -708,6 +728,7 @@ bad_length:
static void org_pre_send(struct organization_tlv *org)
{
+ struct ieee_c37_238_2017_tlv *p;
struct follow_up_info_tlv *f;
if (0 == memcmp(org->id, ieee8021_id, sizeof(ieee8021_id))) {
@@ -724,6 +745,21 @@ static void org_pre_send(struct organization_tlv *org)
break;
}
}
+ if (0 == memcmp(org->id, ieeec37_238_id, sizeof(ieeec37_238_id))) {
+ if (org->subtype[0] || org->subtype[1]) {
+ return;
+ }
+ switch (org->subtype[2]) {
+ case 1:
+ case 2:
+ /* Layout of 2011 and 2017 messages is compatible. */
+ p = (struct ieee_c37_238_2017_tlv *) org;
+ HTONS(p->grandmasterID);
+ HTONL(p->reserved1);
+ HTONL(p->totalTimeInaccuracy);
+ break;
+ }
+ }
}
static int slave_delay_timing_data_post_revc(struct tlv_extra *extra)
diff --git a/tlv.h b/tlv.h
index 8966696..409c8d0 100644
--- a/tlv.h
+++ b/tlv.h
@@ -213,6 +213,8 @@ struct nsm_resp_tlv_foot {
/* Organizationally Unique Identifiers */
#define IEEE_802_1_COMMITTEE 0x00, 0x80, 0xC2
extern uint8_t ieee8021_id[3];
+#define IEEE_C37_238_PROFILE 0x1C, 0x12, 0x9D
+extern uint8_t ieeec37_238_id[3];
struct organization_tlv {
Enumeration16 type;
@@ -300,6 +302,28 @@ struct follow_up_info_tlv {
Integer32 scaledLastGmPhaseChange;
} PACKED;
+struct ieee_c37_238_2011_tlv {
+ Enumeration16 type;
+ UInteger16 length;
+ Octet id[3];
+ Octet subtype[3];
+ UInteger16 grandmasterID;
+ UInteger32 grandmasterTimeInaccuracy;
+ UInteger32 networkTimeInaccuracy;
+ Octet pad[2];
+} PACKED;
+
+struct ieee_c37_238_2017_tlv {
+ Enumeration16 type;
+ UInteger16 length;
+ Octet id[3];
+ Octet subtype[3];
+ UInteger16 grandmasterID;
+ UInteger32 reserved1;
+ UInteger32 totalTimeInaccuracy;
+ Octet pad[2];
+} PACKED;
+
struct msg_interval_req_tlv {
Enumeration16 type;
UInteger16 length;
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-01-28 22:44:04
|
Signed-off-by: Richard Cochran <ric...@gm...>
---
config.c | 15 +++++++++++++-
port.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++
port_private.h | 3 +++
power_profile.h | 31 +++++++++++++++++++++++++++++
tlv.h | 8 ++++++++
5 files changed, 109 insertions(+), 1 deletion(-)
create mode 100644 power_profile.h
diff --git a/config.c b/config.c
index 6684c9f..4c58a0a 100644
--- a/config.c
+++ b/config.c
@@ -31,6 +31,7 @@
#include "config.h"
#include "ether.h"
#include "hash.h"
+#include "power_profile.h"
#include "print.h"
#include "util.h"
@@ -66,7 +67,7 @@ typedef union {
char *s;
} any_t;
-#define CONFIG_LABEL_SIZE 32
+#define CONFIG_LABEL_SIZE 64
#define CFG_ITEM_STATIC (1 << 0) /* statically allocated, not to be freed */
#define CFG_ITEM_LOCKED (1 << 1) /* command line value, may not be changed */
@@ -189,6 +190,13 @@ static struct config_enum hwts_filter_enu[] = {
{ NULL, 0 },
};
+static struct config_enum ieee_c37_238_enu[] = {
+ { "none", IEEE_C37_238_VERSION_NONE },
+ { "2011", IEEE_C37_238_VERSION_2011 },
+ { "2017", IEEE_C37_238_VERSION_2017 },
+ { NULL, 0 },
+};
+
static struct config_enum nw_trans_enu[] = {
{ "L2", TRANS_IEEE_802_3 },
{ "UDPv4", TRANS_UDP_IPV4 },
@@ -298,6 +306,11 @@ struct config_item config_tab[] = {
GLOB_ITEM_DBL("pi_proportional_exponent", -0.3, -DBL_MAX, DBL_MAX),
GLOB_ITEM_DBL("pi_proportional_norm_max", 0.7, DBL_MIN, 1.0),
GLOB_ITEM_DBL("pi_proportional_scale", 0.0, 0.0, DBL_MAX),
+ PORT_ITEM_ENU("power_profile.version", IEEE_C37_238_VERSION_NONE, ieee_c37_238_enu),
+ PORT_ITEM_INT("power_profile.2011.grandmasterTimeInaccuracy", 0xFFFFFFFF, 0, INT_MAX),
+ PORT_ITEM_INT("power_profile.2011.networkTimeInaccuracy", 0, 0, INT_MAX),
+ PORT_ITEM_INT("power_profile.2017.totalTimeInaccuracy", 0xFFFFFFFF, 0, INT_MAX),
+ PORT_ITEM_INT("power_profile.grandmasterID", 0, 0, 0xFFFF),
GLOB_ITEM_INT("priority1", 128, 0, UINT8_MAX),
GLOB_ITEM_INT("priority2", 128, 0, UINT8_MAX),
GLOB_ITEM_STR("productDescription", ";;"),
diff --git a/port.c b/port.c
index 6baf5c8..7bcf88c 100644
--- a/port.c
+++ b/port.c
@@ -453,6 +453,46 @@ static int follow_up_info_append(struct ptp_message *m)
return 0;
}
+static int ieee_c37_238_append(struct port *p, struct ptp_message *m)
+{
+ struct ieee_c37_238_2017_tlv *p17;
+ struct ieee_c37_238_2011_tlv *p11;
+ struct tlv_extra *extra;
+
+ switch (p->pwr.version) {
+ case IEEE_C37_238_VERSION_NONE:
+ return 0;
+ case IEEE_C37_238_VERSION_2011:
+ extra = msg_tlv_append(m, sizeof(*p11));
+ if (!extra) {
+ return -1;
+ }
+ p11 = (struct ieee_c37_238_2011_tlv *) extra->tlv;
+ p11->type = TLV_ORGANIZATION_EXTENSION;
+ p11->length = sizeof(*p11) - sizeof(p11->type) - sizeof(p11->length);
+ memcpy(p11->id, ieeec37_238_id, sizeof(ieeec37_238_id));
+ p11->subtype[2] = 1;
+ p11->grandmasterID = p->pwr.grandmasterID;
+ p11->grandmasterTimeInaccuracy = p->pwr.grandmasterTimeInaccuracy;
+ p11->networkTimeInaccuracy = p->pwr.networkTimeInaccuracy;
+ break;
+ case IEEE_C37_238_VERSION_2017:
+ extra = msg_tlv_append(m, sizeof(*p17));
+ if (!extra) {
+ return -1;
+ }
+ p17 = (struct ieee_c37_238_2017_tlv *) extra->tlv;
+ p17->type = TLV_ORGANIZATION_EXTENSION;
+ p17->length = sizeof(*p17) - sizeof(p17->type) - sizeof(p17->length);
+ memcpy(p17->id, ieeec37_238_id, sizeof(ieeec37_238_id));
+ p17->subtype[2] = 2;
+ p17->grandmasterID = p->pwr.grandmasterID;
+ p17->totalTimeInaccuracy = p->pwr.totalTimeInaccuracy;
+ break;
+ }
+ return 0;
+}
+
static int net_sync_resp_append(struct port *p, struct ptp_message *m)
{
struct timePropertiesDS tp = clock_time_properties(p->clock);
@@ -1622,6 +1662,9 @@ int port_tx_announce(struct port *p, struct address *dst, uint16_t sequence_id)
if (p->path_trace_enabled && path_trace_append(p, msg, dad)) {
pr_err("%s: append path trace failed", p->log_name);
}
+ if (ieee_c37_238_append(p, msg)) {
+ pr_err("%s: append power profile failed", p->log_name);
+ }
err = port_prepare_and_send(p, msg, TRANS_GENERAL);
if (err) {
@@ -3326,6 +3369,16 @@ struct port *port_open(const char *phc_device,
p->state = PS_INITIALIZING;
p->delayMechanism = config_get_int(cfg, p->name, "delay_mechanism");
p->versionNumber = PTP_MAJOR_VERSION;
+ p->pwr.version =
+ config_get_int(cfg, p->name, "power_profile.version");
+ p->pwr.grandmasterID =
+ config_get_int(cfg, p->name, "power_profile.grandmasterID");
+ p->pwr.grandmasterTimeInaccuracy =
+ config_get_int(cfg, p->name, "power_profile.2011.grandmasterTimeInaccuracy");
+ p->pwr.networkTimeInaccuracy =
+ config_get_int(cfg, p->name, "power_profile.2011.networkTimeInaccuracy");
+ p->pwr.totalTimeInaccuracy =
+ config_get_int(cfg, p->name, "power_profile.2017.totalTimeInaccuracy");
p->slave_event_monitor = clock_slave_monitor(clock);
if (!port_is_uds(p) && unicast_client_initialize(p)) {
diff --git a/port_private.h b/port_private.h
index d27dceb..204ec61 100644
--- a/port_private.h
+++ b/port_private.h
@@ -26,6 +26,7 @@
#include "fsm.h"
#include "monitor.h"
#include "msg.h"
+#include "power_profile.h"
#include "tmv.h"
#define NSEC2SEC 1000000000LL
@@ -151,6 +152,8 @@ struct port {
LIST_HEAD(fm, foreign_clock) foreign_masters;
/* TC book keeping */
TAILQ_HEAD(tct, tc_txd) tc_transmitted;
+ /* power profile */
+ struct ieee_c37_238_settings_np pwr;
/* unicast client mode */
struct unicast_master_table *unicast_master_table;
/* unicast service mode */
diff --git a/power_profile.h b/power_profile.h
new file mode 100644
index 0000000..6a7c8a4
--- /dev/null
+++ b/power_profile.h
@@ -0,0 +1,31 @@
+/**
+ * @file power_profile.h
+ * @brief Implements power profile features.
+ * @note Copyright (C) 2021 Richard Cochran <ric...@gm...>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef HAVE_POWER_PROFILE_H
+#define HAVE_POWER_PROFILE_H
+
+#include "pdt.h"
+
+enum power_profile_version {
+ IEEE_C37_238_VERSION_NONE,
+ IEEE_C37_238_VERSION_2011,
+ IEEE_C37_238_VERSION_2017,
+};
+
+#endif
diff --git a/tlv.h b/tlv.h
index 409c8d0..a435588 100644
--- a/tlv.h
+++ b/tlv.h
@@ -324,6 +324,14 @@ struct ieee_c37_238_2017_tlv {
Octet pad[2];
} PACKED;
+struct ieee_c37_238_settings_np {
+ Enumeration16 version;
+ UInteger16 grandmasterID;
+ UInteger32 grandmasterTimeInaccuracy;
+ UInteger32 networkTimeInaccuracy;
+ UInteger32 totalTimeInaccuracy;
+} PACKED;
+
struct msg_interval_req_tlv {
Enumeration16 type;
UInteger16 length;
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-01-28 22:44:06
|
Signed-off-by: Richard Cochran <ric...@gm...>
---
tlv.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tlv.h | 26 ++++++++++++++++++++++++++
2 files changed, 84 insertions(+)
diff --git a/tlv.c b/tlv.c
index 2e421ed..212414f 100644
--- a/tlv.c
+++ b/tlv.c
@@ -77,6 +77,22 @@ static uint16_t flip16(void *p)
return v;
}
+static void host2net32_unaligned(void *p)
+{
+ int32_t v;
+ memcpy(&v, p, sizeof(v));
+ v = htonl(v);
+ memcpy(p, &v, sizeof(v));
+}
+
+static void net2host32_unaligned(void *p)
+{
+ int32_t v;
+ memcpy(&v, p, sizeof(v));
+ v = ntohl(v);
+ memcpy(p, &v, sizeof(v));
+}
+
static int64_t host2net64_unaligned(void *p)
{
int64_t v;
@@ -111,6 +127,43 @@ static bool tlv_array_invalid(struct TLV *tlv, size_t base_size, size_t item_siz
return (tlv->length == expected_length) ? false : true;
}
+static int alttime_offset_post_recv(struct tlv_extra *extra)
+{
+ struct TLV *tlv = extra->tlv;
+ struct alternate_time_offset_indicator_tlv *atoi =
+ (struct alternate_time_offset_indicator_tlv *) tlv;
+
+ if (tlv->length < sizeof(struct alternate_time_offset_indicator_tlv) +
+ atoi->displayName.length - sizeof(struct TLV)) {
+ return -EBADMSG;
+ }
+
+ NTOHS(atoi->type);
+ NTOHS(atoi->length);
+ /* Message alignment broken by design. */
+ net2host32_unaligned(&atoi->currentOffset);
+ net2host32_unaligned(&atoi->jumpSeconds);
+ flip16(&atoi->timeOfNextJump.seconds_msb);
+ net2host32_unaligned(&atoi->timeOfNextJump.seconds_lsb);
+
+ return 0;
+}
+
+static void alttime_offset_pre_send(struct tlv_extra *extra)
+{
+ struct alternate_time_offset_indicator_tlv *atoi;
+
+ atoi = (struct alternate_time_offset_indicator_tlv *) extra->tlv;
+
+ HTONS(atoi->type);
+ HTONS(atoi->length);
+ /* Message alignment broken by design. */
+ host2net32_unaligned(&atoi->currentOffset);
+ host2net32_unaligned(&atoi->jumpSeconds);
+ flip16(&atoi->timeOfNextJump.seconds_msb);
+ host2net32_unaligned(&atoi->timeOfNextJump.seconds_lsb);
+}
+
static int mgt_post_recv(struct management_tlv *m, uint16_t data_len,
struct tlv_extra *extra)
{
@@ -1035,6 +1088,8 @@ int tlv_post_recv(struct tlv_extra *extra)
}
break;
case TLV_ALTERNATE_TIME_OFFSET_INDICATOR:
+ result = alttime_offset_post_recv(extra);
+ break;
case TLV_AUTHENTICATION_2008:
case TLV_AUTHENTICATION_CHALLENGE:
case TLV_SECURITY_ASSOCIATION_UPDATE:
@@ -1098,7 +1153,10 @@ void tlv_pre_send(struct TLV *tlv, struct tlv_extra *extra)
unicast_negotiation_pre_send(tlv);
break;
case TLV_PATH_TRACE:
+ break;
case TLV_ALTERNATE_TIME_OFFSET_INDICATOR:
+ alttime_offset_pre_send(extra);
+ break;
case TLV_AUTHENTICATION_2008:
case TLV_AUTHENTICATION_CHALLENGE:
case TLV_SECURITY_ASSOCIATION_UPDATE:
diff --git a/tlv.h b/tlv.h
index 3dbce4f..a1a7dbc 100644
--- a/tlv.h
+++ b/tlv.h
@@ -175,6 +175,32 @@ struct grant_unicast_xmit_tlv {
uint8_t flags;
} PACKED;
+struct alternate_time_offset_indicator_tlv {
+ Enumeration16 type;
+ UInteger16 length;
+ UInteger8 keyField;
+ /* Message alignment broken by design. */
+ Integer32 currentOffset;
+ Integer32 jumpSeconds;
+ struct {
+ uint16_t seconds_msb; /* 16 bits + */
+ uint32_t seconds_lsb; /* 32 bits = 48 bits*/
+ } PACKED timeOfNextJump;
+ struct PTPText displayName;
+} PACKED;
+
+struct alternate_time_offset_properties {
+ UInteger8 keyField;
+ /* Message alignment broken by design. */
+ Integer32 currentOffset;
+ Integer32 jumpSeconds;
+ struct {
+ uint16_t seconds_msb; /* 16 bits + */
+ uint32_t seconds_lsb; /* 32 bits = 48 bits*/
+ } PACKED timeOfNextJump;
+ uint8_t pad;
+} PACKED;
+
struct management_tlv {
Enumeration16 type;
UInteger16 length;
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-01-28 22:44:09
|
Signed-off-by: Richard Cochran <ric...@gm...>
---
pmc.c | 15 +++++++++++++++
pmc_common.c | 37 +++++++++++++++++++++++++++++++++++++
port.c | 20 +++++++++++++++++++-
tlv.c | 20 ++++++++++++++++++++
tlv.h | 1 +
5 files changed, 92 insertions(+), 1 deletion(-)
diff --git a/pmc.c b/pmc.c
index e218ca4..793a790 100644
--- a/pmc.c
+++ b/pmc.c
@@ -157,6 +157,7 @@ static void pmc_show_signaling(struct ptp_message *msg, FILE *fp)
static void pmc_show(struct ptp_message *msg, FILE *fp)
{
+ struct ieee_c37_238_settings_np *pwr;
struct unicast_master_table_np *umtn;
struct grandmaster_settings_np *gsn;
struct port_service_stats_np *pssp;
@@ -572,6 +573,20 @@ static void pmc_show(struct ptp_message *msg, FILE *fp)
phn->phc_index,
phn->flags);
break;
+ case MID_POWER_PROFILE_SETTINGS_NP:
+ pwr = (struct ieee_c37_238_settings_np *) mgt->data;
+ fprintf(fp, "POWER_PROFILE_SETTINGS_NP "
+ IFMT "version %hu"
+ IFMT "grandmasterID 0x%04hx"
+ IFMT "grandmasterTimeInaccuracy %u"
+ IFMT "networkTimeInaccuracy %u"
+ IFMT "totalTimeInaccuracy %u",
+ pwr->version,
+ pwr->grandmasterID,
+ pwr->grandmasterTimeInaccuracy,
+ pwr->networkTimeInaccuracy,
+ pwr->totalTimeInaccuracy);
+ break;
case MID_LOG_ANNOUNCE_INTERVAL:
mtd = (struct management_tlv_datum *) mgt->data;
fprintf(fp, "LOG_ANNOUNCE_INTERVAL "
diff --git a/pmc_common.c b/pmc_common.c
index 1dd89f6..bb7d087 100644
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -28,6 +28,7 @@
#include "tlv.h"
#include "transport.h"
#include "pmc_common.h"
+#include "power_profile.h"
#define BAD_ACTION -1
#define BAD_ID -1
@@ -154,6 +155,7 @@ struct management_id idtab[] = {
{ "PORT_SERVICE_STATS_NP", MID_PORT_SERVICE_STATS_NP, do_get_action },
{ "UNICAST_MASTER_TABLE_NP", MID_UNICAST_MASTER_TABLE_NP, do_get_action },
{ "PORT_HWCLOCK_NP", MID_PORT_HWCLOCK_NP, do_get_action },
+ { "POWER_PROFILE_SETTINGS_NP", MID_POWER_PROFILE_SETTINGS_NP, do_set_action },
};
static void do_get_action(struct pmc *pmc, int action, int index, char *str)
@@ -168,6 +170,7 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
{
int cnt, code = idtab[index].code, freq_traceable, leap_59, leap_61,
ptp_timescale, time_traceable, utc_off_valid;
+ struct ieee_c37_238_settings_np pwr;
struct grandmaster_settings_np gsn;
struct management_tlv_datum mtd;
struct subscribe_events_np sen;
@@ -302,6 +305,37 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
}
pmc_send_set_action(pmc, code, &pnp, sizeof(pnp));
break;
+ case MID_POWER_PROFILE_SETTINGS_NP:
+ cnt = sscanf(str, " %*s %*s "
+ "version %hu "
+ "grandmasterID %hx "
+ "grandmasterTimeInaccuracy %u "
+ "networkTimeInaccuracy %u "
+ "totalTimeInaccuracy %u ",
+ &pwr.version,
+ &pwr.grandmasterID,
+ &pwr.grandmasterTimeInaccuracy,
+ &pwr.networkTimeInaccuracy,
+ &pwr.totalTimeInaccuracy);
+ if (cnt != 5) {
+ fprintf(stderr, "%s SET needs 5 values\n",
+ idtab[index].name);
+ break;
+ }
+ switch (pwr.version) {
+ case IEEE_C37_238_VERSION_NONE:
+ case IEEE_C37_238_VERSION_2011:
+ case IEEE_C37_238_VERSION_2017:
+ pmc_send_set_action(pmc, code, &pwr, sizeof(pwr));
+ break;
+ default:
+ fprintf(stderr, "\nusage: set PROFILE_SETTINGS_NP version "
+ "%hu (none), %hu (2011), or %hu (2017)\n\n",
+ IEEE_C37_238_VERSION_NONE,
+ IEEE_C37_238_VERSION_2011,
+ IEEE_C37_238_VERSION_2017);
+ }
+ break;
}
}
@@ -573,6 +607,9 @@ static int pmc_tlv_datalen(struct pmc *pmc, int id)
case MID_PORT_HWCLOCK_NP:
len += sizeof(struct port_hwclock_np);
break;
+ case MID_POWER_PROFILE_SETTINGS_NP:
+ len += sizeof(struct ieee_c37_238_settings_np);
+ break;
case MID_LOG_ANNOUNCE_INTERVAL:
case MID_ANNOUNCE_RECEIPT_TIMEOUT:
case MID_LOG_SYNC_INTERVAL:
diff --git a/port.c b/port.c
index 7bcf88c..7200a87 100644
--- a/port.c
+++ b/port.c
@@ -877,6 +877,7 @@ static const Octet profile_id_8275_2[] = {0x00, 0x19, 0xA7, 0x02, 0x01, 0x02};
static int port_management_fill_response(struct port *target,
struct ptp_message *rsp, int id)
{
+ struct ieee_c37_238_settings_np *pwr;
struct unicast_master_table_np *umtn;
struct unicast_master_address *ucma;
struct port_service_stats_np *pssn;
@@ -1123,6 +1124,11 @@ static int port_management_fill_response(struct port *target,
PORT_HWCLOCK_VCLOCK : 0;
datalen = sizeof(*phn);
break;
+ case MID_POWER_PROFILE_SETTINGS_NP:
+ pwr = (struct ieee_c37_238_settings_np *)tlv->data;
+ memcpy(pwr, &target->pwr, sizeof(*pwr));
+ datalen = sizeof(*pwr);
+ break;
default:
/* The caller should *not* respond to this message. */
tlv_extra_recycle(extra);
@@ -1164,9 +1170,10 @@ static int port_management_set(struct port *target,
struct port *ingress, int id,
struct ptp_message *req)
{
- int respond = 0;
+ struct ieee_c37_238_settings_np *pwr;
struct management_tlv *tlv;
struct port_ds_np *pdsnp;
+ int respond = 0;
tlv = (struct management_tlv *) req->management.suffix;
@@ -1176,6 +1183,17 @@ static int port_management_set(struct port *target,
target->neighborPropDelayThresh = pdsnp->neighborPropDelayThresh;
respond = 1;
break;
+ case MID_POWER_PROFILE_SETTINGS_NP:
+ pwr = (struct ieee_c37_238_settings_np *) tlv->data;
+ switch (pwr->version) {
+ case IEEE_C37_238_VERSION_NONE:
+ case IEEE_C37_238_VERSION_2011:
+ case IEEE_C37_238_VERSION_2017:
+ target->pwr = *pwr;
+ respond = 1;
+ break;
+ }
+ break;
}
if (respond && !port_management_get_response(target, ingress, id, req))
pr_err("%s: failed to send management set response", target->log_name);
diff --git a/tlv.c b/tlv.c
index 29d0556..2e421ed 100644
--- a/tlv.c
+++ b/tlv.c
@@ -114,6 +114,7 @@ static bool tlv_array_invalid(struct TLV *tlv, size_t base_size, size_t item_siz
static int mgt_post_recv(struct management_tlv *m, uint16_t data_len,
struct tlv_extra *extra)
{
+ struct ieee_c37_238_settings_np *pwr;
struct unicast_master_table_np *umtn;
struct grandmaster_settings_np *gsn;
struct port_service_stats_np *pssn;
@@ -399,6 +400,16 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len,
phn->phc_index = ntohl(phn->phc_index);
extra_len = sizeof(struct port_hwclock_np);
break;
+ case MID_POWER_PROFILE_SETTINGS_NP:
+ if (data_len < sizeof(struct ieee_c37_238_settings_np))
+ goto bad_length;
+ pwr = (struct ieee_c37_238_settings_np *)m->data;
+ NTOHS(pwr->version);
+ NTOHS(pwr->grandmasterID);
+ NTOHL(pwr->grandmasterTimeInaccuracy);
+ NTOHL(pwr->networkTimeInaccuracy);
+ NTOHL(pwr->totalTimeInaccuracy);
+ break;
case MID_SAVE_IN_NON_VOLATILE_STORAGE:
case MID_RESET_NON_VOLATILE_STORAGE:
case MID_INITIALIZE:
@@ -422,6 +433,7 @@ bad_length:
static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra)
{
+ struct ieee_c37_238_settings_np *pwr;
struct unicast_master_table_np *umtn;
struct grandmaster_settings_np *gsn;
struct port_service_stats_np *pssn;
@@ -570,6 +582,14 @@ static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra)
phn->portIdentity.portNumber = htons(phn->portIdentity.portNumber);
phn->phc_index = htonl(phn->phc_index);
break;
+ case MID_POWER_PROFILE_SETTINGS_NP:
+ pwr = (struct ieee_c37_238_settings_np *)m->data;
+ HTONS(pwr->version);
+ HTONS(pwr->grandmasterID);
+ HTONL(pwr->grandmasterTimeInaccuracy);
+ HTONL(pwr->networkTimeInaccuracy);
+ HTONL(pwr->totalTimeInaccuracy);
+ break;
}
}
diff --git a/tlv.h b/tlv.h
index a435588..3dbce4f 100644
--- a/tlv.h
+++ b/tlv.h
@@ -128,6 +128,7 @@ enum management_action {
#define MID_PORT_SERVICE_STATS_NP 0xC007
#define MID_UNICAST_MASTER_TABLE_NP 0xC008
#define MID_PORT_HWCLOCK_NP 0xC009
+#define MID_POWER_PROFILE_SETTINGS_NP 0xC00A
/* Management error ID values */
#define MID_RESPONSE_TOO_BIG 0x0001
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-01-28 22:44:08
|
Signed-off-by: Richard Cochran <ric...@gm...>
---
clock.c | 19 ++++++++++++++++---
tz.h | 26 ++++++++++++++++++++++++++
2 files changed, 42 insertions(+), 3 deletions(-)
create mode 100644 tz.h
diff --git a/clock.c b/clock.c
index 134c7c3..767599b 100644
--- a/clock.c
+++ b/clock.c
@@ -42,6 +42,7 @@
#include "rtnl.h"
#include "tlv.h"
#include "tsproc.h"
+#include "tz.h"
#include "uds.h"
#include "util.h"
@@ -79,6 +80,15 @@ struct clock_subscriber {
time_t expiration;
};
+struct time_zone {
+ bool enabled;
+ int32_t current_offset;
+ int32_t jump_seconds;
+ uint16_t next_jump_msb;
+ uint32_t next_jump_lsb;
+ struct static_ptp_text display_name;
+};
+
struct clock {
enum clock_type type;
struct config *config;
@@ -137,6 +147,7 @@ struct clock {
struct monitor *slave_event_monitor;
int step_window_counter;
int step_window;
+ struct time_zone tz[MAX_TIME_ZONES];
};
struct clock the_clock;
@@ -894,19 +905,17 @@ int clock_required_modes(struct clock *c)
struct clock *clock_create(enum clock_type type, struct config *config,
const char *phc_device)
{
+ int conf_phc_index, i, max_adj = 0, phc_index, required_modes = 0, sfl, sw_ts;
enum servo_type servo = config_get_int(config, NULL, "clock_servo");
char ts_label[IF_NAMESIZE], phc[32], *tmp;
enum timestamp_type timestamping;
- int phc_index, conf_phc_index, required_modes = 0;
struct clock *c = &the_clock;
- int max_adj = 0, sw_ts;
const char *uds_ifname;
double fadj = 0.0;
struct port *p;
unsigned char oui[OUI_LEN];
struct interface *iface;
struct timespec ts;
- int sfl;
clock_gettime(CLOCK_REALTIME, &ts);
srandom(ts.tv_sec ^ ts.tv_nsec);
@@ -1201,6 +1210,10 @@ struct clock *clock_create(enum clock_type type, struct config *config,
c->dad.pds.observedParentClockPhaseChangeRate = 0x7fffffff;
c->dad.ptl = c->ptl;
+ for (i = 0; i < MAX_TIME_ZONES; i++) {
+ c->tz[i].display_name.max_symbols = MAX_TZ_DISPLAY_NAME;
+ }
+
clock_sync_interval(c, 0);
LIST_INIT(&c->subscribers);
diff --git a/tz.h b/tz.h
new file mode 100644
index 0000000..986f976
--- /dev/null
+++ b/tz.h
@@ -0,0 +1,26 @@
+/**
+ * @file tz.h
+ * @brief Implements time zone constants.
+ * @note Copyright (C) 2021 Richard Cochran <ric...@gm...>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef HAVE_TZ_H
+#define HAVE_TZ_H
+
+#define MAX_TZ_DISPLAY_NAME 10
+#define MAX_TIME_ZONES 4
+
+#endif
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-01-28 22:44:09
|
If the local PTP management client enables a time zone, append the
matching TLV to outgoing Announce messages.
Signed-off-by: Richard Cochran <ric...@gm...>
---
clock.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++--
clock.h | 8 ++++++
pmc.c | 8 ++++++
pmc_common.c | 17 ++++++++++-
port.c | 3 ++
5 files changed, 113 insertions(+), 3 deletions(-)
diff --git a/clock.c b/clock.c
index ab3b892..96f391f 100644
--- a/clock.c
+++ b/clock.c
@@ -157,6 +157,43 @@ static int clock_resize_pollfd(struct clock *c, int new_nports);
static void clock_remove_port(struct clock *c, struct port *p);
static void clock_stats_display(struct clock_stats *s);
+static int clock_alttime_offset_append(struct clock *c, int key, struct ptp_message *m)
+{
+ struct alternate_time_offset_indicator_tlv *atoi;
+ struct tlv_extra *extra;
+ int tlv_len;
+
+ tlv_len = sizeof(*atoi) + c->tz[key].display_name.length;
+ if (tlv_len % 2) {
+ tlv_len++;
+ }
+ extra = msg_tlv_append(m, tlv_len);
+ if (!extra) {
+ return -1;
+ }
+ atoi = (struct alternate_time_offset_indicator_tlv *) extra->tlv;
+ atoi->type = TLV_ALTERNATE_TIME_OFFSET_INDICATOR;
+ atoi->length = tlv_len - sizeof(atoi->type) - sizeof(atoi->length);
+ atoi->keyField = key;
+
+ /* Message alignment broken by design. */
+ memcpy(&atoi->currentOffset, &c->tz[key].current_offset,
+ sizeof(atoi->currentOffset));
+
+ memcpy(&atoi->jumpSeconds, &c->tz[key].jump_seconds,
+ sizeof(atoi->jumpSeconds));
+
+ memcpy(&atoi->timeOfNextJump.seconds_lsb, &c->tz[key].next_jump_lsb,
+ sizeof(atoi->timeOfNextJump.seconds_lsb));
+
+ memcpy(&atoi->timeOfNextJump.seconds_msb, &c->tz[key].next_jump_msb,
+ sizeof(atoi->timeOfNextJump.seconds_msb));
+
+ ptp_text_copy(&atoi->displayName, &c->tz[key].display_name);
+
+ return 0;
+}
+
uint8_t clock_alttime_offset_get_key(struct ptp_message *req)
{
struct management_tlv_datum *mtd;
@@ -462,6 +499,16 @@ static int clock_management_fill_response(struct clock *c, struct port *p,
mtd->val = c->tds.flags & PTP_TIMESCALE;
datalen = sizeof(*mtd);
break;
+ case MID_ALTERNATE_TIME_OFFSET_ENABLE:
+ key = clock_alttime_offset_get_key(req);
+ if (key >= MAX_TIME_ZONES) {
+ break;
+ }
+ mtd = (struct management_tlv_datum *) tlv->data;
+ mtd->val = key;
+ mtd->reserved = c->tz[key].enabled ? 1 : 0;
+ datalen = sizeof(*mtd);
+ break;
case MID_ALTERNATE_TIME_OFFSET_NAME:
key = clock_alttime_offset_get_key(req);
if (key >= MAX_TIME_ZONES) {
@@ -574,7 +621,7 @@ static int clock_management_set(struct clock *c, struct port *p,
struct management_tlv_datum *mtd;
struct subscribe_events_np *sen;
struct management_tlv *tlv;
- int key, respond = 0;
+ int k, key, respond = 0;
tlv = (struct management_tlv *) req->management.suffix;
@@ -591,6 +638,20 @@ static int clock_management_set(struct clock *c, struct port *p,
*changed = 1;
respond = 1;
break;
+ case MID_ALTERNATE_TIME_OFFSET_ENABLE:
+ mtd = (struct management_tlv_datum *) tlv->data;
+ key = mtd->val;
+ if (key == 0xff) {
+ for (k = 0; k < MAX_TIME_ZONES; k++) {
+ c->tz[k].enabled = mtd->reserved & 1 ? true : false;
+ }
+ respond = 1;
+ }
+ if (key < MAX_TIME_ZONES) {
+ c->tz[key].enabled = mtd->reserved & 1 ? true : false;
+ respond = 1;
+ }
+ break;
case MID_ALTERNATE_TIME_OFFSET_NAME:
aton = (struct alternate_time_offset_name *) tlv->data;
key = aton->keyField;
@@ -894,6 +955,22 @@ static int forwarding(struct clock *c, struct port *p)
/* public methods */
+int clock_append_timezones(struct clock *c, struct ptp_message *m)
+{
+ int err = 0, i;
+
+ for (i = 0; i < MAX_TIME_ZONES; i++) {
+ if (!c->tz[i].enabled) {
+ continue;
+ }
+ err = clock_alttime_offset_append(c, i, m);
+ if (err) {
+ break;
+ }
+ }
+ return err;
+}
+
UInteger8 clock_class(struct clock *c)
{
return c->dds.clockQuality.clockClass;
@@ -1609,7 +1686,6 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
case MID_GRANDMASTER_CLUSTER_TABLE:
case MID_ACCEPTABLE_MASTER_TABLE:
case MID_ACCEPTABLE_MASTER_MAX_TABLE_SIZE:
- case MID_ALTERNATE_TIME_OFFSET_ENABLE:
case MID_ALTERNATE_TIME_OFFSET_MAX_KEY:
case MID_TRANSPARENT_CLOCK_DEFAULT_DATA_SET:
case MID_PRIMARY_DOMAIN:
diff --git a/clock.h b/clock.h
index 0534f21..ce9ae91 100644
--- a/clock.h
+++ b/clock.h
@@ -43,6 +43,14 @@ enum clock_type {
CLOCK_TYPE_MANAGEMENT = 0x0800,
};
+/**
+ * Appends the active time zone TLVs to a given message.
+ * @param c The clock instance.
+ * @param m The message that will receive the TLVs.
+ * @return Zero on success, non-zero otherwise.
+ */
+int clock_append_timezones(struct clock *c, struct ptp_message *m);
+
/**
* Obtains a reference to the best foreign master of a clock.
* @param c The clock instance.
diff --git a/pmc.c b/pmc.c
index 35dddba..00e691f 100644
--- a/pmc.c
+++ b/pmc.c
@@ -362,6 +362,14 @@ static void pmc_show(struct ptp_message *msg, FILE *fp)
fprintf(fp, "TIMESCALE_PROPERTIES "
IFMT "ptpTimescale %d", mtd->val & PTP_TIMESCALE ? 1 : 0);
break;
+ case MID_ALTERNATE_TIME_OFFSET_ENABLE:
+ mtd = (struct management_tlv_datum *) mgt->data;
+ fprintf(fp, "ALTERNATE_TIME_OFFSET_ENABLE "
+ IFMT "keyField %hhu"
+ IFMT "enable %d",
+ mtd->val,
+ mtd->reserved & 1 ? 1 : 0);
+ break;
case MID_ALTERNATE_TIME_OFFSET_NAME:
aton = (struct alternate_time_offset_name *) mgt->data;
fprintf(fp, "ALTERNATE_TIME_OFFSET_NAME "
diff --git a/pmc_common.c b/pmc_common.c
index 1062c59..6cab5e0 100644
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -121,7 +121,7 @@ struct management_id idtab[] = {
{ "GRANDMASTER_CLUSTER_TABLE", MID_GRANDMASTER_CLUSTER_TABLE, not_supported },
{ "ACCEPTABLE_MASTER_TABLE", MID_ACCEPTABLE_MASTER_TABLE, not_supported },
{ "ACCEPTABLE_MASTER_MAX_TABLE_SIZE", MID_ACCEPTABLE_MASTER_MAX_TABLE_SIZE, not_supported },
- { "ALTERNATE_TIME_OFFSET_ENABLE", MID_ALTERNATE_TIME_OFFSET_ENABLE, not_supported },
+ { "ALTERNATE_TIME_OFFSET_ENABLE", MID_ALTERNATE_TIME_OFFSET_ENABLE, do_set_action },
{ "ALTERNATE_TIME_OFFSET_NAME", MID_ALTERNATE_TIME_OFFSET_NAME, do_set_action },
{ "ALTERNATE_TIME_OFFSET_MAX_KEY", MID_ALTERNATE_TIME_OFFSET_MAX_KEY, not_supported },
{ "ALTERNATE_TIME_OFFSET_PROPERTIES", MID_ALTERNATE_TIME_OFFSET_PROPERTIES, do_set_action },
@@ -181,6 +181,7 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
char onoff_time_status[4] = "off";
char display_name[11] = {0};
uint8_t key;
+ int enable;
mtd.reserved = 0;
@@ -209,6 +210,17 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
}
pmc_send_set_action(pmc, code, &mtd, sizeof(mtd));
break;
+ case MID_ALTERNATE_TIME_OFFSET_ENABLE:
+ cnt = sscanf(str, " %*s %*s keyField %hhu enable %d",
+ &mtd.val, &enable);
+ if (cnt != 2) {
+ fprintf(stderr, "%s SET needs 2 values\n",
+ idtab[index].name);
+ break;
+ }
+ mtd.reserved = enable ? 1 : 0;
+ pmc_send_set_action(pmc, code, &mtd, sizeof(mtd));
+ break;
case MID_ALTERNATE_TIME_OFFSET_NAME:
cnt = sscanf(str, " %*s %*s "
"keyField %hhu "
@@ -610,6 +622,9 @@ static int pmc_tlv_datalen(struct pmc *pmc, int id)
case MID_TIME_STATUS_NP:
len += sizeof(struct time_status_np);
break;
+ case MID_ALTERNATE_TIME_OFFSET_ENABLE:
+ len += sizeof(struct management_tlv_datum);
+ break;
case MID_ALTERNATE_TIME_OFFSET_NAME:
len += sizeof(struct alternate_time_offset_name);
break;
diff --git a/port.c b/port.c
index 7200a87..208ee73 100644
--- a/port.c
+++ b/port.c
@@ -1683,6 +1683,9 @@ int port_tx_announce(struct port *p, struct address *dst, uint16_t sequence_id)
if (ieee_c37_238_append(p, msg)) {
pr_err("%s: append power profile failed", p->log_name);
}
+ if (clock_append_timezones(p->clock, msg)) {
+ pr_err("%s: append time zones failed", p->log_name);
+ }
err = port_prepare_and_send(p, msg, TRANS_GENERAL);
if (err) {
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-01-28 22:44:10
|
Signed-off-by: Richard Cochran <ric...@gm...>
---
clock.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++---
pmc.c | 17 +++++++++++++
pmc_common.c | 24 +++++++++++++++++-
tlv.c | 21 ++++++++++++++++
util.h | 7 ++++++
5 files changed, 134 insertions(+), 5 deletions(-)
diff --git a/clock.c b/clock.c
index 767599b..93f00b1 100644
--- a/clock.c
+++ b/clock.c
@@ -157,6 +157,32 @@ static int clock_resize_pollfd(struct clock *c, int new_nports);
static void clock_remove_port(struct clock *c, struct port *p);
static void clock_stats_display(struct clock_stats *s);
+uint8_t clock_alttime_offset_get_key(struct ptp_message *req)
+{
+ struct management_tlv_datum *mtd;
+ struct management_tlv *mgt =
+ (struct management_tlv *) req->management.suffix;
+
+ /*
+ * The data field of incoming management request messages is
+ * normally ignored. Indeed it can even be empty. However
+ * the ALTERNATE_TIME_OFFSET requests are exceptional because
+ * the key field selects one of the configured time zones.
+ *
+ * Provide the first time zone for an empty GET, and validate
+ * the length of the request when non-empty.
+ */
+ if (mgt->length == sizeof(mgt->id)) {
+ return 0;
+ }
+ if (mgt->length < sizeof(mgt->id) + sizeof(*mtd)) {
+ return MAX_TIME_ZONES;
+ }
+ mtd = (struct management_tlv_datum *) mgt->data;
+
+ return mtd->val;
+}
+
static void remove_subscriber(struct clock_subscriber *s)
{
LIST_REMOVE(s, list);
@@ -354,6 +380,7 @@ static int clock_management_fill_response(struct clock *c, struct port *p,
struct ptp_message *req,
struct ptp_message *rsp, int id)
{
+ struct alternate_time_offset_properties *atop;
struct grandmaster_settings_np *gsn;
struct management_tlv_datum *mtd;
struct subscribe_events_np *sen;
@@ -363,6 +390,7 @@ static int clock_management_fill_response(struct clock *c, struct port *p,
struct PTPText *text;
uint16_t duration;
int datalen = 0;
+ uint8_t key;
extra = tlv_extra_alloc();
if (!extra) {
@@ -433,6 +461,24 @@ static int clock_management_fill_response(struct clock *c, struct port *p,
mtd->val = c->tds.flags & PTP_TIMESCALE;
datalen = sizeof(*mtd);
break;
+ case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
+ key = clock_alttime_offset_get_key(req);
+ if (key >= MAX_TIME_ZONES) {
+ break;
+ }
+ atop = (struct alternate_time_offset_properties *) tlv->data;
+ atop->keyField = key;
+ /* Message alignment broken by design. */
+ memcpy(&atop->currentOffset, &c->tz[key].current_offset,
+ sizeof(atop->currentOffset));
+ memcpy(&atop->jumpSeconds, &c->tz[key].jump_seconds,
+ sizeof(atop->jumpSeconds));
+ memcpy(&atop->timeOfNextJump.seconds_lsb, &c->tz[key].next_jump_lsb,
+ sizeof(atop->timeOfNextJump.seconds_lsb));
+ memcpy(&atop->timeOfNextJump.seconds_msb, &c->tz[key].next_jump_msb,
+ sizeof(atop->timeOfNextJump.seconds_msb));
+ datalen = sizeof(*atop);
+ break;
case MID_TIME_STATUS_NP:
tsn = (struct time_status_np *) tlv->data;
tsn->master_offset = tmv_to_nanoseconds(c->master_offset);
@@ -511,11 +557,12 @@ static int clock_management_get_response(struct clock *c, struct port *p,
static int clock_management_set(struct clock *c, struct port *p,
int id, struct ptp_message *req, int *changed)
{
- int respond = 0;
- struct management_tlv *tlv;
- struct management_tlv_datum *mtd;
+ struct alternate_time_offset_properties *atop;
struct grandmaster_settings_np *gsn;
+ struct management_tlv_datum *mtd;
struct subscribe_events_np *sen;
+ struct management_tlv *tlv;
+ int key, respond = 0;
tlv = (struct management_tlv *) req->management.suffix;
@@ -532,6 +579,22 @@ static int clock_management_set(struct clock *c, struct port *p,
*changed = 1;
respond = 1;
break;
+ case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
+ atop = (struct alternate_time_offset_properties *) tlv->data;
+ key = atop->keyField;
+ if (key < MAX_TIME_ZONES) {
+ /* Message alignment broken by design. */
+ memcpy(&c->tz[key].current_offset, &atop->currentOffset,
+ sizeof(c->tz[key].current_offset));
+ memcpy(&c->tz[key].jump_seconds, &atop->jumpSeconds,
+ sizeof(c->tz[key].jump_seconds));
+ memcpy(&c->tz[key].next_jump_lsb, &atop->timeOfNextJump.seconds_lsb,
+ sizeof(c->tz[key].next_jump_lsb));
+ memcpy(&c->tz[key].next_jump_msb, &atop->timeOfNextJump.seconds_msb,
+ sizeof(c->tz[key].next_jump_msb));
+ respond = 1;
+ }
+ break;
case MID_GRANDMASTER_SETTINGS_NP:
gsn = (struct grandmaster_settings_np *) tlv->data;
c->dds.clockQuality = gsn->clockQuality;
@@ -1529,7 +1592,6 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
case MID_ALTERNATE_TIME_OFFSET_ENABLE:
case MID_ALTERNATE_TIME_OFFSET_NAME:
case MID_ALTERNATE_TIME_OFFSET_MAX_KEY:
- case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
case MID_TRANSPARENT_CLOCK_DEFAULT_DATA_SET:
case MID_PRIMARY_DOMAIN:
case MID_TIME_STATUS_NP:
diff --git a/pmc.c b/pmc.c
index 793a790..fd8b978 100644
--- a/pmc.c
+++ b/pmc.c
@@ -157,6 +157,7 @@ static void pmc_show_signaling(struct ptp_message *msg, FILE *fp)
static void pmc_show(struct ptp_message *msg, FILE *fp)
{
+ struct alternate_time_offset_properties *atop;
struct ieee_c37_238_settings_np *pwr;
struct unicast_master_table_np *umtn;
struct grandmaster_settings_np *gsn;
@@ -176,6 +177,7 @@ static void pmc_show(struct ptp_message *msg, FILE *fp)
struct defaultDS *dds;
struct currentDS *cds;
struct parentDS *pds;
+ uint64_t next_jump;
struct portDS *p;
struct TLV *tlv;
uint8_t *buf;
@@ -359,6 +361,21 @@ static void pmc_show(struct ptp_message *msg, FILE *fp)
fprintf(fp, "TIMESCALE_PROPERTIES "
IFMT "ptpTimescale %d", mtd->val & PTP_TIMESCALE ? 1 : 0);
break;
+ case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
+ atop = (struct alternate_time_offset_properties *) mgt->data;
+ next_jump = atop->timeOfNextJump.seconds_msb;
+ next_jump <<= 32;
+ next_jump |= atop->timeOfNextJump.seconds_lsb;
+ fprintf(fp, "ALTERNATE_TIME_OFFSET_PROPERTIES "
+ IFMT "keyField %hhu"
+ IFMT "currentOffset %d"
+ IFMT "jumpSeconds %d"
+ IFMT "timeOfNextJump %" PRIu64,
+ atop->keyField,
+ align32(&atop->currentOffset),
+ align32(&atop->jumpSeconds),
+ next_jump);
+ break;
case MID_MASTER_ONLY:
mtd = (struct management_tlv_datum *) mgt->data;
fprintf(fp, "MASTER_ONLY "
diff --git a/pmc_common.c b/pmc_common.c
index bb7d087..4ae9db0 100644
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -123,7 +123,7 @@ struct management_id idtab[] = {
{ "ALTERNATE_TIME_OFFSET_ENABLE", MID_ALTERNATE_TIME_OFFSET_ENABLE, not_supported },
{ "ALTERNATE_TIME_OFFSET_NAME", MID_ALTERNATE_TIME_OFFSET_NAME, not_supported },
{ "ALTERNATE_TIME_OFFSET_MAX_KEY", MID_ALTERNATE_TIME_OFFSET_MAX_KEY, not_supported },
- { "ALTERNATE_TIME_OFFSET_PROPERTIES", MID_ALTERNATE_TIME_OFFSET_PROPERTIES, not_supported },
+ { "ALTERNATE_TIME_OFFSET_PROPERTIES", MID_ALTERNATE_TIME_OFFSET_PROPERTIES, do_set_action },
{ "MASTER_ONLY", MID_MASTER_ONLY, do_get_action },
{ "TRANSPARENT_CLOCK_DEFAULT_DATA_SET", MID_TRANSPARENT_CLOCK_DEFAULT_DATA_SET, not_supported },
{ "PRIMARY_DOMAIN", MID_PRIMARY_DOMAIN, not_supported },
@@ -170,6 +170,7 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
{
int cnt, code = idtab[index].code, freq_traceable, leap_59, leap_61,
ptp_timescale, time_traceable, utc_off_valid;
+ struct alternate_time_offset_properties atop;
struct ieee_c37_238_settings_np pwr;
struct grandmaster_settings_np gsn;
struct management_tlv_datum mtd;
@@ -205,6 +206,24 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
}
pmc_send_set_action(pmc, code, &mtd, sizeof(mtd));
break;
+ case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
+ memset(&atop, 0, sizeof(atop));
+ cnt = sscanf(str, " %*s %*s "
+ "keyField %hhu "
+ "currentOffset %d "
+ "jumpSeconds %d "
+ "timeOfNextJump %u ",
+ &atop.keyField,
+ &atop.currentOffset,
+ &atop.jumpSeconds,
+ &atop.timeOfNextJump.seconds_lsb);
+ if (cnt != 4) {
+ fprintf(stderr, "%s SET needs 4 values\n",
+ idtab[index].name);
+ break;
+ }
+ pmc_send_set_action(pmc, code, &atop, sizeof(atop));
+ break;
case MID_GRANDMASTER_SETTINGS_NP:
cnt = sscanf(str, " %*s %*s "
"clockClass %hhu "
@@ -575,6 +594,9 @@ static int pmc_tlv_datalen(struct pmc *pmc, int id)
case MID_TIME_STATUS_NP:
len += sizeof(struct time_status_np);
break;
+ case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
+ len += sizeof(struct alternate_time_offset_properties);
+ break;
case MID_GRANDMASTER_SETTINGS_NP:
len += sizeof(struct grandmaster_settings_np);
break;
diff --git a/tlv.c b/tlv.c
index 212414f..740d57b 100644
--- a/tlv.c
+++ b/tlv.c
@@ -167,6 +167,7 @@ static void alttime_offset_pre_send(struct tlv_extra *extra)
static int mgt_post_recv(struct management_tlv *m, uint16_t data_len,
struct tlv_extra *extra)
{
+ struct alternate_time_offset_properties *atop;
struct ieee_c37_238_settings_np *pwr;
struct unicast_master_table_np *umtn;
struct grandmaster_settings_np *gsn;
@@ -337,6 +338,17 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len,
p->portIdentity.portNumber = ntohs(p->portIdentity.portNumber);
p->peerMeanPathDelay = net2host64(p->peerMeanPathDelay);
break;
+ case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
+ atop = (struct alternate_time_offset_properties *) m->data;
+ if (data_len != sizeof(*atop)) {
+ goto bad_length;
+ }
+ /* Message alignment broken by design. */
+ net2host32_unaligned(&atop->currentOffset);
+ net2host32_unaligned(&atop->jumpSeconds);
+ flip16(&atop->timeOfNextJump.seconds_msb);
+ net2host32_unaligned(&atop->timeOfNextJump.seconds_lsb);
+ break;
case MID_TIME_STATUS_NP:
if (data_len != sizeof(struct time_status_np))
goto bad_length;
@@ -486,6 +498,7 @@ bad_length:
static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra)
{
+ struct alternate_time_offset_properties *atop;
struct ieee_c37_238_settings_np *pwr;
struct unicast_master_table_np *umtn;
struct grandmaster_settings_np *gsn;
@@ -548,6 +561,14 @@ static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra)
p->portIdentity.portNumber = htons(p->portIdentity.portNumber);
p->peerMeanPathDelay = host2net64(p->peerMeanPathDelay);
break;
+ case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
+ atop = (struct alternate_time_offset_properties *) m->data;
+ /* Message alignment broken by design. */
+ host2net32_unaligned(&atop->currentOffset);
+ host2net32_unaligned(&atop->jumpSeconds);
+ flip16(&atop->timeOfNextJump.seconds_msb);
+ host2net32_unaligned(&atop->timeOfNextJump.seconds_lsb);
+ break;
case MID_TIME_STATUS_NP:
tsn = (struct time_status_np *) m->data;
tsn->master_offset = host2net64(tsn->master_offset);
diff --git a/util.h b/util.h
index 542f3b5..2bbde71 100644
--- a/util.h
+++ b/util.h
@@ -66,6 +66,13 @@ static inline uint16_t align16(void *p)
return v;
}
+static inline uint32_t align32(void *p)
+{
+ uint32_t v;
+ memcpy(&v, p, sizeof(v));
+ return v;
+}
+
char *bin2str_impl(Octet *data, int len, char *buf, int buf_len);
/**
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-01-28 22:44:12
|
The function to set the alternate time offset name, a.k.a. time zone, will
be used by the time zone stand alone program. Make the function into a
public PMC method.
Signed-off-by: Richard Cochran <ric...@gm...>
---
pmc_common.c | 5 ++---
pmc_common.h | 2 ++
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/pmc_common.c b/pmc_common.c
index 6cab5e0..539e812 100644
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -79,7 +79,6 @@ static void do_get_action(struct pmc *pmc, int action, int index, char *str);
static void do_set_action(struct pmc *pmc, int action, int index, char *str);
static void not_supported(struct pmc *pmc, int action, int index, char *str);
static void null_management(struct pmc *pmc, int action, int index, char *str);
-static int send_set_aton(struct pmc *pmc, int id, uint8_t key, const char *name);
static const char *action_string[] = {
"GET",
@@ -232,7 +231,7 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
idtab[index].name);
break;
}
- send_set_aton(pmc, code, key, display_name);
+ pmc_send_set_aton(pmc, code, key, display_name);
break;
case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
memset(&atop, 0, sizeof(atop));
@@ -759,7 +758,7 @@ int pmc_send_set_action(struct pmc *pmc, int id, void *data, int datasize)
return 0;
}
-static int send_set_aton(struct pmc *pmc, int id, uint8_t key, const char *name)
+int pmc_send_set_aton(struct pmc *pmc, int id, uint8_t key, const char *name)
{
struct alternate_time_offset_name *aton;
struct management_tlv *mgt;
diff --git a/pmc_common.h b/pmc_common.h
index 8bea2e0..6fb2fae 100644
--- a/pmc_common.h
+++ b/pmc_common.h
@@ -41,6 +41,8 @@ int pmc_send_get_action(struct pmc *pmc, int id);
int pmc_send_set_action(struct pmc *pmc, int id, void *data, int datasize);
+int pmc_send_set_aton(struct pmc *pmc, int id, uint8_t key, const char *name);
+
struct ptp_message *pmc_recv(struct pmc *pmc);
int pmc_target(struct pmc *pmc, struct PortIdentity *pid);
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-01-28 22:44:12
|
Signed-off-by: Richard Cochran <ric...@gm...>
---
clock.c | 21 +++++++++++++++++++-
pmc.c | 9 +++++++++
pmc_common.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++-
tlv.c | 11 +++++++++++
tlv.h | 5 +++++
5 files changed, 100 insertions(+), 2 deletions(-)
diff --git a/clock.c b/clock.c
index 93f00b1..ab3b892 100644
--- a/clock.c
+++ b/clock.c
@@ -381,6 +381,7 @@ static int clock_management_fill_response(struct clock *c, struct port *p,
struct ptp_message *rsp, int id)
{
struct alternate_time_offset_properties *atop;
+ struct alternate_time_offset_name *aton;
struct grandmaster_settings_np *gsn;
struct management_tlv_datum *mtd;
struct subscribe_events_np *sen;
@@ -461,6 +462,16 @@ static int clock_management_fill_response(struct clock *c, struct port *p,
mtd->val = c->tds.flags & PTP_TIMESCALE;
datalen = sizeof(*mtd);
break;
+ case MID_ALTERNATE_TIME_OFFSET_NAME:
+ key = clock_alttime_offset_get_key(req);
+ if (key >= MAX_TIME_ZONES) {
+ break;
+ }
+ aton = (struct alternate_time_offset_name *) tlv->data;
+ aton->keyField = key;
+ ptp_text_copy(&aton->displayName, &c->tz[key].display_name);
+ datalen = sizeof(*aton) + aton->displayName.length;
+ break;
case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
key = clock_alttime_offset_get_key(req);
if (key >= MAX_TIME_ZONES) {
@@ -558,6 +569,7 @@ static int clock_management_set(struct clock *c, struct port *p,
int id, struct ptp_message *req, int *changed)
{
struct alternate_time_offset_properties *atop;
+ struct alternate_time_offset_name *aton;
struct grandmaster_settings_np *gsn;
struct management_tlv_datum *mtd;
struct subscribe_events_np *sen;
@@ -579,6 +591,14 @@ static int clock_management_set(struct clock *c, struct port *p,
*changed = 1;
respond = 1;
break;
+ case MID_ALTERNATE_TIME_OFFSET_NAME:
+ aton = (struct alternate_time_offset_name *) tlv->data;
+ key = aton->keyField;
+ if (key < MAX_TIME_ZONES &&
+ !static_ptp_text_copy(&c->tz[key].display_name, &aton->displayName)) {
+ respond = 1;
+ }
+ break;
case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
atop = (struct alternate_time_offset_properties *) tlv->data;
key = atop->keyField;
@@ -1590,7 +1610,6 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
case MID_ACCEPTABLE_MASTER_TABLE:
case MID_ACCEPTABLE_MASTER_MAX_TABLE_SIZE:
case MID_ALTERNATE_TIME_OFFSET_ENABLE:
- case MID_ALTERNATE_TIME_OFFSET_NAME:
case MID_ALTERNATE_TIME_OFFSET_MAX_KEY:
case MID_TRANSPARENT_CLOCK_DEFAULT_DATA_SET:
case MID_PRIMARY_DOMAIN:
diff --git a/pmc.c b/pmc.c
index fd8b978..35dddba 100644
--- a/pmc.c
+++ b/pmc.c
@@ -158,6 +158,7 @@ static void pmc_show_signaling(struct ptp_message *msg, FILE *fp)
static void pmc_show(struct ptp_message *msg, FILE *fp)
{
struct alternate_time_offset_properties *atop;
+ struct alternate_time_offset_name *aton;
struct ieee_c37_238_settings_np *pwr;
struct unicast_master_table_np *umtn;
struct grandmaster_settings_np *gsn;
@@ -361,6 +362,14 @@ static void pmc_show(struct ptp_message *msg, FILE *fp)
fprintf(fp, "TIMESCALE_PROPERTIES "
IFMT "ptpTimescale %d", mtd->val & PTP_TIMESCALE ? 1 : 0);
break;
+ case MID_ALTERNATE_TIME_OFFSET_NAME:
+ aton = (struct alternate_time_offset_name *) mgt->data;
+ fprintf(fp, "ALTERNATE_TIME_OFFSET_NAME "
+ IFMT "keyField %hhu"
+ IFMT "displayName %s",
+ aton->keyField,
+ text2str(&aton->displayName));
+ break;
case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
atop = (struct alternate_time_offset_properties *) mgt->data;
next_jump = atop->timeOfNextJump.seconds_msb;
diff --git a/pmc_common.c b/pmc_common.c
index 4ae9db0..1062c59 100644
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -79,6 +79,7 @@ static void do_get_action(struct pmc *pmc, int action, int index, char *str);
static void do_set_action(struct pmc *pmc, int action, int index, char *str);
static void not_supported(struct pmc *pmc, int action, int index, char *str);
static void null_management(struct pmc *pmc, int action, int index, char *str);
+static int send_set_aton(struct pmc *pmc, int id, uint8_t key, const char *name);
static const char *action_string[] = {
"GET",
@@ -121,7 +122,7 @@ struct management_id idtab[] = {
{ "ACCEPTABLE_MASTER_TABLE", MID_ACCEPTABLE_MASTER_TABLE, not_supported },
{ "ACCEPTABLE_MASTER_MAX_TABLE_SIZE", MID_ACCEPTABLE_MASTER_MAX_TABLE_SIZE, not_supported },
{ "ALTERNATE_TIME_OFFSET_ENABLE", MID_ALTERNATE_TIME_OFFSET_ENABLE, not_supported },
- { "ALTERNATE_TIME_OFFSET_NAME", MID_ALTERNATE_TIME_OFFSET_NAME, not_supported },
+ { "ALTERNATE_TIME_OFFSET_NAME", MID_ALTERNATE_TIME_OFFSET_NAME, do_set_action },
{ "ALTERNATE_TIME_OFFSET_MAX_KEY", MID_ALTERNATE_TIME_OFFSET_MAX_KEY, not_supported },
{ "ALTERNATE_TIME_OFFSET_PROPERTIES", MID_ALTERNATE_TIME_OFFSET_PROPERTIES, do_set_action },
{ "MASTER_ONLY", MID_MASTER_ONLY, do_get_action },
@@ -178,6 +179,8 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
struct port_ds_np pnp;
char onoff_port_state[4] = "off";
char onoff_time_status[4] = "off";
+ char display_name[11] = {0};
+ uint8_t key;
mtd.reserved = 0;
@@ -206,6 +209,19 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
}
pmc_send_set_action(pmc, code, &mtd, sizeof(mtd));
break;
+ case MID_ALTERNATE_TIME_OFFSET_NAME:
+ cnt = sscanf(str, " %*s %*s "
+ "keyField %hhu "
+ "displayName %10s ",
+ &key,
+ display_name);
+ if (cnt != 2) {
+ fprintf(stderr, "%s SET needs 2 values\n",
+ idtab[index].name);
+ break;
+ }
+ send_set_aton(pmc, code, key, display_name);
+ break;
case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
memset(&atop, 0, sizeof(atop));
cnt = sscanf(str, " %*s %*s "
@@ -594,6 +610,9 @@ static int pmc_tlv_datalen(struct pmc *pmc, int id)
case MID_TIME_STATUS_NP:
len += sizeof(struct time_status_np);
break;
+ case MID_ALTERNATE_TIME_OFFSET_NAME:
+ len += sizeof(struct alternate_time_offset_name);
+ break;
case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
len += sizeof(struct alternate_time_offset_properties);
break;
@@ -725,6 +744,41 @@ int pmc_send_set_action(struct pmc *pmc, int id, void *data, int datasize)
return 0;
}
+static int send_set_aton(struct pmc *pmc, int id, uint8_t key, const char *name)
+{
+ struct alternate_time_offset_name *aton;
+ struct management_tlv *mgt;
+ struct ptp_message *msg;
+ struct tlv_extra *extra;
+ int datasize;
+
+ datasize = sizeof(*aton) + strlen(name);
+ if (datasize % 2) {
+ datasize++;
+ }
+ msg = pmc_message(pmc, SET);
+ if (!msg) {
+ return -1;
+ }
+ extra = msg_tlv_append(msg, sizeof(*mgt) + datasize);
+ if (!extra) {
+ msg_put(msg);
+ return -ENOMEM;
+ }
+ mgt = (struct management_tlv *) extra->tlv;
+ mgt->type = TLV_MANAGEMENT;
+ mgt->length = 2 + datasize;
+ mgt->id = id;
+ aton = (struct alternate_time_offset_name *) mgt->data;
+ aton->keyField = key;
+ ptp_text_set(&aton->displayName, name);
+
+ pmc_send(pmc, msg);
+ msg_put(msg);
+
+ return 0;
+}
+
struct ptp_message *pmc_recv(struct pmc *pmc)
{
struct ptp_message *msg;
diff --git a/tlv.c b/tlv.c
index 740d57b..5ad5074 100644
--- a/tlv.c
+++ b/tlv.c
@@ -168,6 +168,7 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len,
struct tlv_extra *extra)
{
struct alternate_time_offset_properties *atop;
+ struct alternate_time_offset_name *aton;
struct ieee_c37_238_settings_np *pwr;
struct unicast_master_table_np *umtn;
struct grandmaster_settings_np *gsn;
@@ -338,6 +339,14 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len,
p->portIdentity.portNumber = ntohs(p->portIdentity.portNumber);
p->peerMeanPathDelay = net2host64(p->peerMeanPathDelay);
break;
+ case MID_ALTERNATE_TIME_OFFSET_NAME:
+ aton = (struct alternate_time_offset_name *) m->data;
+ if (data_len < sizeof(*aton)) {
+ goto bad_length;
+ }
+ extra_len = sizeof(*aton);
+ extra_len += aton->displayName.length;
+ break;
case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
atop = (struct alternate_time_offset_properties *) m->data;
if (data_len != sizeof(*atop)) {
@@ -561,6 +570,8 @@ static void mgt_pre_send(struct management_tlv *m, struct tlv_extra *extra)
p->portIdentity.portNumber = htons(p->portIdentity.portNumber);
p->peerMeanPathDelay = host2net64(p->peerMeanPathDelay);
break;
+ case MID_ALTERNATE_TIME_OFFSET_NAME:
+ break;
case MID_ALTERNATE_TIME_OFFSET_PROPERTIES:
atop = (struct alternate_time_offset_properties *) m->data;
/* Message alignment broken by design. */
diff --git a/tlv.h b/tlv.h
index a1a7dbc..ec91229 100644
--- a/tlv.h
+++ b/tlv.h
@@ -189,6 +189,11 @@ struct alternate_time_offset_indicator_tlv {
struct PTPText displayName;
} PACKED;
+struct alternate_time_offset_name {
+ UInteger8 keyField;
+ struct PTPText displayName;
+} PACKED;
+
struct alternate_time_offset_properties {
UInteger8 keyField;
/* Message alignment broken by design. */
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-01-28 22:44:17
|
The ptp4l program supports up to four time zones via the
ALTERNATE_TIME_OFFSET_INDICATOR TLV. Introduce a helper program that
leverages the local time zone database to monitor for changes in
daylight savings time and publishing them.
Signed-off-by: Richard Cochran <ric...@gm...>
---
makefile | 7 +-
tztool.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 382 insertions(+), 2 deletions(-)
create mode 100644 tztool.c
diff --git a/makefile b/makefile
index ba3fb38..f03939a 100644
--- a/makefile
+++ b/makefile
@@ -22,7 +22,7 @@ CC = $(CROSS_COMPILE)gcc
VER = -DVER=$(version)
CFLAGS = -Wall $(VER) $(incdefs) $(DEBUG) $(EXTRA_CFLAGS)
LDLIBS = -lm -lrt -pthread $(EXTRA_LDFLAGS)
-PRG = ptp4l hwstamp_ctl nsm phc2sys phc_ctl pmc timemaster ts2phc
+PRG = ptp4l hwstamp_ctl nsm phc2sys phc_ctl pmc timemaster ts2phc tztool
FILTERS = filter.o mave.o mmedian.o
SERVOS = linreg.o ntpshm.o nullf.o pi.o servo.o
TRANSP = raw.o transport.o udp.o udp6.o uds.o
@@ -35,7 +35,7 @@ OBJ = bmc.o clock.o clockadj.o clockcheck.o config.o designated_fsm.o \
unicast_fsm.o unicast_service.o util.o version.o
OBJECTS = $(OBJ) hwstamp_ctl.o nsm.o phc2sys.o phc_ctl.o pmc.o pmc_agent.o \
- pmc_common.o sysoff.o timemaster.o $(TS2PHC)
+ pmc_common.o sysoff.o timemaster.o $(TS2PHC) tztool.o
SRC = $(OBJECTS:.o=.c)
DEPEND = $(OBJECTS:.o=.d)
srcdir := $(dir $(lastword $(MAKEFILE_LIST)))
@@ -72,6 +72,9 @@ ts2phc: config.o clockadj.o hash.o interface.o msg.o phc.o pmc_agent.o \
pmc_common.o print.o $(SERVOS) sk.o $(TS2PHC) tlv.o transport.o raw.o \
udp.o udp6.o uds.o util.o version.o
+tztool: config.o hash.o interface.o lstab.o msg.o phc.o pmc_common.o print.o \
+ sk.o tlv.o $(TRANSP) tztool.o util.o version.o
+
version.o: .version version.sh $(filter-out version.d,$(DEPEND))
.version: force
diff --git a/tztool.c b/tztool.c
new file mode 100644
index 0000000..a7a2a69
--- /dev/null
+++ b/tztool.c
@@ -0,0 +1,377 @@
+/**
+ * @file tztool.c
+ * @note Copyright (C) 2021 Richard Cochran <ric...@gm...>
+ * @note SPDX-License-Identifier: GPL-2.0+
+ */
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "lstab.h"
+#include "pmc_common.h"
+#include "print.h"
+#include "version.h"
+#include "tz.h"
+
+#define DEFAULT_TZ "PST8PDT"
+#define DEFAULT_PERIOD 3600
+#define DEFAULT_WINDOW (3600 * 24 * 30 * 3)
+
+static int key_field, period = DEFAULT_PERIOD, window = DEFAULT_WINDOW;
+static char uds_local[MAX_IFNAME_SIZE + 1];
+static struct lstab *lstab;
+static struct config *cfg;
+
+struct tzinfo {
+ const char *name;
+ char display_name[MAX_TZ_DISPLAY_NAME + 1];
+ time_t timestamp;
+
+ /* Following fields populated by get_offsets. */
+
+ time_t local_utc_offset;
+ time_t local_tai_offset;
+ int tai_utc_offset;
+ enum lstab_result tai_result;
+};
+
+static int get_offsets(struct tzinfo *tz);
+
+static bool offsets_equal(struct tzinfo *a, struct tzinfo *b)
+{
+ return a->local_utc_offset == b->local_utc_offset;
+}
+
+static bool find_next_discontinuity(struct tzinfo *tz, struct tzinfo *next)
+{
+ time_t i, j, n;
+ bool gt;
+
+ next->timestamp = tz->timestamp + window;
+ get_offsets(next);
+ if (offsets_equal(tz, next)) {
+ return false;
+ }
+
+ i = 0;
+ j = window;
+
+ while (1) {
+ next->timestamp = tz->timestamp + i;
+ get_offsets(next);
+ gt = offsets_equal(tz, next);
+ if (gt) {
+ n = j - i - 1;
+ } else {
+ j = i;
+ i = 0;
+ n = j - i - 1;
+ }
+ if (!n) {
+ if (gt) {
+ next->timestamp++;
+ get_offsets(next);
+ }
+ break;
+ }
+ i += (n + 1) / 2;
+ }
+
+ return true;
+}
+
+static int get_offsets(struct tzinfo *tz)
+{
+ struct tm tm = {0};
+ time_t t2;
+
+ tz->tai_result = lstab_utc2tai(lstab, tz->timestamp,
+ &tz->tai_utc_offset);
+ if (tz->tai_result == LSTAB_UNKNOWN) {
+ pr_err("leap second table is stale");
+ return -1;
+ }
+
+ setenv("TZ", tz->name, 1);
+ tzset();
+ if (!localtime_r(&tz->timestamp, &tm)) {
+ return -1;
+ }
+
+ setenv("TZ", "UTC", 1);
+ tzset();
+ t2 = mktime(&tm);
+ tz->local_utc_offset = t2 - tz->timestamp;
+ tz->local_tai_offset = tz->local_utc_offset - tz->tai_utc_offset;
+
+ return 0;
+}
+
+static int get_unambiguous_time(struct tzinfo *tz)
+{
+ int err;
+
+ do {
+ tz->timestamp = time(NULL);
+ err = get_offsets(tz);
+ } while (tz->tai_result == LSTAB_AMBIGUOUS);
+
+ return err;
+}
+
+static void show_timezone_info(const char *label, struct tzinfo *tz)
+{
+ pr_debug("%s %s ts %ld local-utc %ld tai-utc %d local-tai %ld %s",
+ label,
+ tz->name,
+ tz->timestamp,
+ tz->local_utc_offset,
+ tz->tai_utc_offset,
+ tz->local_tai_offset,
+ tz->tai_result == LSTAB_OK ? "valid" : "invalid");
+}
+
+/* Returns true if display name was truncated. */
+static bool tz_set_name(struct tzinfo *tz, const char *name)
+{
+ const char *suffix;
+ int len;
+
+ memset(tz->display_name, 0, sizeof(tz->display_name));
+ tz->name = name;
+
+ len = strlen(name);
+ if (len <= MAX_TZ_DISPLAY_NAME) {
+ strncpy(tz->display_name, name, sizeof(tz->display_name) - 1);
+ return false;
+ }
+
+ /*
+ * The displayName field is limited to 10 characters, but
+ * there are many valid time zone names like "Europe/Vienna".
+ * Use the suffix if present.
+ */
+ suffix = strchr(name, '/');
+ if (suffix) {
+ suffix++;
+ len = strlen(suffix);
+ if (len > 0 && len <= MAX_TZ_DISPLAY_NAME) {
+ strncpy(tz->display_name, suffix,
+ sizeof(tz->display_name) - 1);
+ return true;
+ }
+ }
+
+ /* No nice suffix to be found, so just truncate. */
+ strncpy(tz->display_name, name, sizeof(tz->display_name) - 1);
+
+ return true;
+}
+
+static int update_ptp_serivce(struct tzinfo *tz, struct tzinfo *next)
+{
+ struct alternate_time_offset_properties atop;
+ struct management_tlv_datum mtd;
+ struct pmc *pmc;
+ int err;
+
+ pmc = pmc_create(cfg, TRANS_UDS, uds_local, 0,
+ config_get_int(cfg, NULL, "domainNumber"),
+ config_get_int(cfg, NULL, "transportSpecific") << 4, 1);
+ if (!pmc) {
+ return -1;
+ }
+ err = pmc_send_set_aton(pmc, MID_ALTERNATE_TIME_OFFSET_NAME,
+ key_field, tz->display_name);
+ if (err) {
+ return err;
+ }
+ memset(&atop, 0, sizeof(atop));
+ atop.keyField = key_field;
+ atop.currentOffset = tz->local_tai_offset;
+ if (next) {
+ atop.jumpSeconds = next->local_tai_offset - tz->local_tai_offset;
+ atop.timeOfNextJump.seconds_lsb = next->timestamp;
+ }
+ err = pmc_send_set_action(pmc, MID_ALTERNATE_TIME_OFFSET_PROPERTIES,
+ &atop, sizeof(atop));
+ if (err) {
+ return err;
+ }
+ mtd.val = key_field;
+ mtd.reserved = 1; /*enable field*/
+ err = pmc_send_set_action(pmc, MID_ALTERNATE_TIME_OFFSET_ENABLE,
+ &mtd, sizeof(mtd));
+ if (err) {
+ return err;
+ }
+
+ pmc_destroy(pmc);
+ return 0;
+}
+
+static int do_tztool(const char *timezone)
+{
+ struct tzinfo nx, tz;
+ const char *leapfile;
+ bool pending;
+ char buf[64];
+ int err;
+
+ if (key_field > MAX_TIME_ZONES - 1) {
+ pr_err("key field %d exceeds maximum of %d", key_field,
+ MAX_TIME_ZONES - 1);
+ return -1;
+ }
+
+ tz_set_name(&nx, timezone);
+ if (tz_set_name(&tz, timezone)) {
+ pr_info("truncating time zone display name from %s to %s",
+ tz.name, tz.display_name);
+ }
+
+ leapfile = config_get_string(cfg, NULL, "leapfile");
+ if (!leapfile) {
+ pr_err("please specify leap second table with --leapfile");
+ return -1;
+ }
+
+ while (is_running()) {
+
+ /* Read the leap seconds file again as it may have changed. */
+ lstab = lstab_create(leapfile);
+ if (!lstab) {
+ pr_err("failed to create leap second table");
+ return -1;
+ }
+
+ err = get_unambiguous_time(&tz);
+ if (err) {
+ return err;
+ }
+ show_timezone_info("current time = ", &tz);
+
+ pending = find_next_discontinuity(&tz, &nx);
+ if (pending) {
+ setenv("TZ", nx.name, 1);
+ tzset();
+ if (ctime_r(&nx.timestamp, buf)) {
+ buf[strlen(buf) - 1] = 0;
+ }
+ show_timezone_info("discontinuity = ", &nx);
+ pr_info("next discontinuity %s %s", buf, nx.name);
+ } else {
+ pr_info("no discontinuity within %d second window", window);
+ }
+
+ lstab_destroy(lstab);
+ lstab = NULL;
+
+ err = update_ptp_serivce(&tz, pending ? &nx : NULL);
+ if (err) {
+ pr_err("failed to update PTP service");
+ return err;
+ }
+ puts("");
+ sleep(period);
+ }
+ return 0;
+}
+
+static void usage(char *progname)
+{
+ fprintf(stderr,
+ "\nusage: %s [options]\n\n"
+ " -f [file] read configuration from 'file'\n"
+ " -h prints this message and exits\n"
+ " -k [num] key field for the ALTERNATE_TIME_OFFSET_INDICATOR TLV\n"
+ " -p [num] period between updates in seconds, default %d\n"
+ " -v prints the software version and exits\n"
+ " -w [num] look ahead time window in seconds, default %d\n"
+ " -z zone Time zone string, default '%s'\n"
+ " See /usr/share/zoneinfo for valid strings\n"
+ "\n",
+ progname, DEFAULT_PERIOD, DEFAULT_WINDOW, DEFAULT_TZ);
+}
+
+int main(int argc, char *argv[])
+{
+ char *config = NULL, *progname, *timezone = DEFAULT_TZ;
+ int c, err = 0, index;
+ struct option *opts;
+
+ if (handle_term_signals()) {
+ return -1;
+ }
+ cfg = config_create();
+ if (!cfg) {
+ return -1;
+ }
+ opts = config_long_options(cfg);
+ print_set_verbose(1);
+ print_set_syslog(0);
+
+ /* Process the command line arguments. */
+ progname = strrchr(argv[0], '/');
+ progname = progname ? 1+progname : argv[0];
+ while (EOF != (c = getopt_long(argc, argv, "f:hk:p:vw:z:", opts, &index))) {
+ switch (c) {
+ case 0:
+ if (config_parse_option(cfg, opts[index].name, optarg)) {
+ config_destroy(cfg);
+ return -1;
+ }
+ break;
+ case 'f':
+ config = optarg;
+ break;
+ case 'k':
+ key_field = atoi(optarg);
+ break;
+ case 'p':
+ period = atoi(optarg);
+ break;
+ case 'v':
+ version_show(stdout);
+ config_destroy(cfg);
+ return 0;
+ case 'w':
+ window = atoi(optarg);
+ break;
+ case 'z':
+ timezone = optarg;
+ break;
+ case 'h':
+ usage(progname);
+ config_destroy(cfg);
+ return 0;
+ case '?':
+ default:
+ usage(progname);
+ config_destroy(cfg);
+ return -1;
+ }
+ }
+
+ print_set_syslog(0);
+ print_set_verbose(1);
+
+ if (config && (err = config_read(config, cfg))) {
+ goto out;
+ }
+
+ print_set_progname(progname);
+ print_set_tag(config_get_string(cfg, NULL, "message_tag"));
+ print_set_level(config_get_int(cfg, NULL, "logging_level"));
+ snprintf(uds_local, sizeof(uds_local), "/var/run/tztool.%d", getpid());
+
+ err = do_tztool(timezone);
+out:
+ config_destroy(cfg);
+ return err;
+}
--
2.30.2
|
|
From: Magnus A. <mag...@fi...> - 2023-01-30 13:35:55
|
Hi, Good work on adding power profile support. On a general level, power profile 2011 states that VLAN IDs should be used. "All IEEE C37.238 messages shall be mapped into IEEE 802.1Q-tagged Ethernet frames with configurable priority and configurable VLAN ID. The default priority shall be 4. The default VID shall be 0. The full range of priority and VID values shall be supported per IEEE Std 802.1Q-2005 [B8]. Bridging devices shall follow the rules defined in IEEE Std 802.1Q-2005 [B8]. By default, all devices shall accept IEEE C37.238 messages that have had their IEEE 802.1Q tags removed, and tagged IEEE C37.238 messages with their configured VID value." Do you see this support already being available? BR, Magnus Armholt > -----Original Message----- > From: Richard Cochran <ric...@gm...> > Sent: sunnuntai 29. tammikuuta 2023 0.44 > To: lin...@li... > Subject: [Linuxptp-devel] [PATCH v4 00/11] Profile support for IEEE C37.238- > 2011 and IEEE C37.238-2017 > > > ChangeLog > ~~~~~~~~~ > v4: > Preserve all 48 bits of "next jump" (v3 review feedback from Erez Geva) > Accept the full range for domainNumber (suggested by v.nosikov) > v3: > Initial RFC > v2, v1: > never published > > The Power Profile specifies two new TLVs: > > 1. IEEE_C37_238 TLV > > - New configuration option to enable the TLV. > > - New configuration options for grandmasterID and default > totalTimeInaccuracy. > > - New custom management message for changing totalTimeInaccuracy at > run time. This message allows switching the TLV from the 2017 > format into the 2011 format by specifying grandmasterTimeInaccuracy > and networkTimeInaccuracy. > > 2. ALTERNATE_TIME_OFFSET_INDICATOR TLV > > - New custom management message for enabling the TLV and setting > the TLV values. > > - New helper program that computes the values from the local time > and the Linux time zone data base and then sends the values to > ptp4l. This method assumes that the local Linux system time and > the PHC clock are synchronized. > > > Thanks, > Richard |
|
From: Richard C. <ric...@gm...> - 2023-01-30 15:21:48
|
On Mon, Jan 30, 2023 at 01:03:09PM +0000, Magnus Armholt wrote: > "All IEEE C37.238 messages shall be mapped into IEEE 802.1Q-tagged Ethernet frames with configurable > priority and configurable VLAN ID. > The default priority shall be 4. The default VID shall be 0. > The full range of priority and VID values shall be supported per IEEE Std 802.1Q-2005 [B8]. > Bridging devices shall follow the rules defined in IEEE Std 802.1Q-2005 [B8]. > By default, all devices shall accept IEEE C37.238 messages that have had their IEEE 802.1Q tags removed, > and tagged IEEE C37.238 messages with their configured VID value." > > Do you see this support already being available? Sure, just set up a Linux vlan interface and use that. Thanks, Richard |
|
From: Miroslav L. <mli...@re...> - 2023-02-01 15:52:34
|
On Sat, Jan 28, 2023 at 02:43:52PM -0800, Richard Cochran wrote:
> +++ b/makefile
> @@ -22,7 +22,7 @@ CC = $(CROSS_COMPILE)gcc
> VER = -DVER=$(version)
> CFLAGS = -Wall $(VER) $(incdefs) $(DEBUG) $(EXTRA_CFLAGS)
> LDLIBS = -lm -lrt -pthread $(EXTRA_LDFLAGS)
> -PRG = ptp4l hwstamp_ctl nsm phc2sys phc_ctl pmc timemaster ts2phc
> +PRG = ptp4l hwstamp_ctl nsm phc2sys phc_ctl pmc timemaster ts2phc tztool
The new program doesn't have a man page and is listed here last,
which causes "make install" to fail. That "[ -f $$x ]" in the install
recipe needs to be followed by something returning zero, e.g. ":".
> +++ b/tztool.c
> +static int update_ptp_serivce(struct tzinfo *tz, struct tzinfo *next)
Typo in the function name ^^.
> + if (next) {
> + atop.jumpSeconds = next->local_tai_offset - tz->local_tai_offset;
> + atop.timeOfNextJump.seconds_lsb = next->timestamp;
> + }
Is this intentionally not setting the _msb field, ignoring distant future?
--
Miroslav Lichvar
|
|
From: Geva, E. <ere...@si...> - 2023-02-01 16:21:56
|
On Sat, 2023-01-28 at 14:43 -0800, Richard Cochran wrote:
> Signed-off-by: Richard Cochran <ric...@gm...>
> ---
> tlv.c | 58
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> tlv.h | 26 ++++++++++++++++++++++++++
> 2 files changed, 84 insertions(+)
>
> diff --git a/tlv.c b/tlv.c
> index 2e421ed..212414f 100644
> --- a/tlv.c
> +++ b/tlv.c
> @@ -77,6 +77,22 @@ static uint16_t flip16(void *p)
> return v;
> }
>
> +static void host2net32_unaligned(void *p)
> +{
> + int32_t v;
> + memcpy(&v, p, sizeof(v));
> + v = htonl(v);
> + memcpy(p, &v, sizeof(v));
> +}
> +
> +static void net2host32_unaligned(void *p)
> +{
> + int32_t v;
> + memcpy(&v, p, sizeof(v));
> + v = ntohl(v);
> + memcpy(p, &v, sizeof(v));
> +}
> +
> static int64_t host2net64_unaligned(void *p)
> {
> int64_t v;
> @@ -111,6 +127,43 @@ static bool tlv_array_invalid(struct TLV *tlv,
> size_t base_size, size_t item_siz
> return (tlv->length == expected_length) ? false : true;
> }
>
> +static int alttime_offset_post_recv(struct tlv_extra *extra)
> +{
> + struct TLV *tlv = extra->tlv;
> + struct alternate_time_offset_indicator_tlv *atoi =
> + (struct alternate_time_offset_indicator_tlv *) tlv;
> +
> + if (tlv->length < sizeof(struct
> alternate_time_offset_indicator_tlv) +
> + atoi->displayName.length - sizeof(struct TLV)) {
> + return -EBADMSG;
> + }
> +
> + NTOHS(atoi->type);
> + NTOHS(atoi->length);
> + /* Message alignment broken by design. */
> + net2host32_unaligned(&atoi->currentOffset);
> + net2host32_unaligned(&atoi->jumpSeconds);
> + flip16(&atoi->timeOfNextJump.seconds_msb);
> + net2host32_unaligned(&atoi->timeOfNextJump.seconds_lsb);
> +
> + return 0;
> +}
> +
> +static void alttime_offset_pre_send(struct tlv_extra *extra)
> +{
> + struct alternate_time_offset_indicator_tlv *atoi;
> +
> + atoi = (struct alternate_time_offset_indicator_tlv *) extra-
> >tlv;
> +
> + HTONS(atoi->type);
> + HTONS(atoi->length);
> + /* Message alignment broken by design. */
> + host2net32_unaligned(&atoi->currentOffset);
> + host2net32_unaligned(&atoi->jumpSeconds);
> + flip16(&atoi->timeOfNextJump.seconds_msb);
> + host2net32_unaligned(&atoi->timeOfNextJump.seconds_lsb);
> +}
> +
> static int mgt_post_recv(struct management_tlv *m, uint16_t
> data_len,
> struct tlv_extra *extra)
> {
> @@ -1035,6 +1088,8 @@ int tlv_post_recv(struct tlv_extra *extra)
> }
> break;
> case TLV_ALTERNATE_TIME_OFFSET_INDICATOR:
> + result = alttime_offset_post_recv(extra);
> + break;
> case TLV_AUTHENTICATION_2008:
> case TLV_AUTHENTICATION_CHALLENGE:
> case TLV_SECURITY_ASSOCIATION_UPDATE:
> @@ -1098,7 +1153,10 @@ void tlv_pre_send(struct TLV *tlv, struct
> tlv_extra *extra)
> unicast_negotiation_pre_send(tlv);
> break;
> case TLV_PATH_TRACE:
> + break;
> case TLV_ALTERNATE_TIME_OFFSET_INDICATOR:
> + alttime_offset_pre_send(extra);
> + break;
> case TLV_AUTHENTICATION_2008:
> case TLV_AUTHENTICATION_CHALLENGE:
> case TLV_SECURITY_ASSOCIATION_UPDATE:
> diff --git a/tlv.h b/tlv.h
> index 3dbce4f..a1a7dbc 100644
> --- a/tlv.h
> +++ b/tlv.h
> @@ -175,6 +175,32 @@ struct grant_unicast_xmit_tlv {
> uint8_t flags;
> } PACKED;
>
> +struct alternate_time_offset_indicator_tlv {
> + Enumeration16 type;
> + UInteger16 length;
> + UInteger8 keyField;
> + /* Message alignment broken by design. */
> + Integer32 currentOffset;
> + Integer32 jumpSeconds;
> + struct {
> + uint16_t seconds_msb; /* 16 bits + */
> + uint32_t seconds_lsb; /* 32 bits = 48 bits*/
> + } PACKED timeOfNextJump;
> + struct PTPText displayName;
> +} PACKED;
> +
> +struct alternate_time_offset_properties {
> + UInteger8 keyField;
> + /* Message alignment broken by design. */
> + Integer32 currentOffset;
> + Integer32 jumpSeconds;
> + struct {
> + uint16_t seconds_msb; /* 16 bits + */
> + uint32_t seconds_lsb; /* 32 bits = 48 bits*/
> + } PACKED timeOfNextJump;
> + uint8_t pad;
> +} PACKED;
> +
> struct management_tlv {
> Enumeration16 type;
> UInteger16 length;
I understand the idea in general.
And I understand the files in the TLVs are unaligned.
But Does htonl() and ntohl() have problem with alignment?
Or the point was using pointers?
Please add a short explanation for the solution.
The explanation on "alignment break by design" is very clear :-)
Erez
|
|
From: Richard C. <ric...@gm...> - 2023-02-11 15:41:26
|
On Wed, Feb 01, 2023 at 02:47:01PM +0000, Geva, Erez wrote: > I understand the idea in general. > And I understand the files in the TLVs are unaligned. right, not my fault. Profile authors are to blame. > But Does htonl() and ntohl() have problem with alignment? on some machines, yes. Thanks, Richard |
|
From: Geva, E. <ere...@si...> - 2023-02-01 19:13:00
|
On Sat, 2023-01-28 at 14:43 -0800, Richard Cochran wrote:
> Signed-off-by: Richard Cochran <ric...@gm...>
> ---
> clock.c | 19 ++++++++++++++++---
> tz.h | 26 ++++++++++++++++++++++++++
> 2 files changed, 42 insertions(+), 3 deletions(-)
> create mode 100644 tz.h
>
> diff --git a/clock.c b/clock.c
> index 134c7c3..767599b 100644
> --- a/clock.c
> +++ b/clock.c
> @@ -42,6 +42,7 @@
> #include "rtnl.h"
> #include "tlv.h"
> #include "tsproc.h"
> +#include "tz.h"
> #include "uds.h"
> #include "util.h"
>
> @@ -79,6 +80,15 @@ struct clock_subscriber {
> time_t expiration;
> };
>
> +struct time_zone {
> + bool enabled;
> + int32_t current_offset;
> + int32_t jump_seconds;
> + uint16_t next_jump_msb;
> + uint32_t next_jump_lsb;
> + struct static_ptp_text display_name;
> +};
> +
> struct clock {
> enum clock_type type;
> struct config *config;
> @@ -137,6 +147,7 @@ struct clock {
> struct monitor *slave_event_monitor;
> int step_window_counter;
> int step_window;
> + struct time_zone tz[MAX_TIME_ZONES];
> };
>
> struct clock the_clock;
> @@ -894,19 +905,17 @@ int clock_required_modes(struct clock *c)
> struct clock *clock_create(enum clock_type type, struct config
> *config,
> const char *phc_device)
> {
> + int conf_phc_index, i, max_adj = 0, phc_index, required_modes
> = 0, sfl, sw_ts;
> enum servo_type servo = config_get_int(config, NULL,
> "clock_servo");
> char ts_label[IF_NAMESIZE], phc[32], *tmp;
> enum timestamp_type timestamping;
> - int phc_index, conf_phc_index, required_modes = 0;
> struct clock *c = &the_clock;
> - int max_adj = 0, sw_ts;
> const char *uds_ifname;
> double fadj = 0.0;
> struct port *p;
> unsigned char oui[OUI_LEN];
> struct interface *iface;
> struct timespec ts;
> - int sfl;
>
> clock_gettime(CLOCK_REALTIME, &ts);
> srandom(ts.tv_sec ^ ts.tv_nsec);
> @@ -1201,6 +1210,10 @@ struct clock *clock_create(enum clock_type
> type, struct config *config,
> c->dad.pds.observedParentClockPhaseChangeRate =
> 0x7fffffff;
> c->dad.ptl = c->ptl;
>
> + for (i = 0; i < MAX_TIME_ZONES; i++) {
> + c->tz[i].display_name.max_symbols =
> MAX_TZ_DISPLAY_NAME;
> + }
> +
> clock_sync_interval(c, 0);
>
> LIST_INIT(&c->subscribers);
> diff --git a/tz.h b/tz.h
> new file mode 100644
> index 0000000..986f976
> --- /dev/null
> +++ b/tz.h
> @@ -0,0 +1,26 @@
> +/**
> + * @file tz.h
> + * @brief Implements time zone constants.
> + * @note Copyright (C) 2021 Richard Cochran <
> ric...@gm...>
> + *
> + * This program is free software; you can redistribute it and/or
> modify
> + * it under the terms of the GNU General Public License as published
> by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> along
> + * with this program; if not, write to the Free Software Foundation,
> Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
Perhaps we can use SPDX, like the Linux kernel do?
https://www.kernel.org/doc/html/latest/process/license-rules.html
https://spdx.dev/
> +#ifndef HAVE_TZ_H
> +#define HAVE_TZ_H
> +
> +#define MAX_TZ_DISPLAY_NAME 10
> +#define MAX_TIME_ZONES 4
> +
> +#endif
Erez
|
|
From: Richard C. <ric...@gm...> - 2023-02-11 15:42:48
|
On Wed, Feb 01, 2023 at 02:41:03PM +0000, Geva, Erez wrote: > Perhaps we can use SPDX, like the Linux kernel do? > https://www.kernel.org/doc/html/latest/process/license-rules.html > https://spdx.dev/ Yes, going forward, let's leave off the boilerplate. I'll fix that. Thanks, Richard |
|
From: Miroslav L. <mli...@re...> - 2023-02-02 10:52:23
|
On Sat, Jan 28, 2023 at 02:43:41PM -0800, Richard Cochran wrote: > The Power Profile specifies two new TLVs: It would be nice to have the new options documented in the ptp4l man page. Please consider renaming tztool to something more PTP-specific, (maybe tz2ptp4l?), to not confuse people that is does something with the system tz database. Other than that and the issues I pointed out in the other mail, the patches look good to me. I have no devices that support the power profile. I juts ran few tests and it seemed to work as expected. Wireshark prints the new TLV. No issues seen with valgrind and address sanitizer. -- Miroslav Lichvar |
|
From: Richard C. <ric...@gm...> - 2023-02-11 15:51:39
|
On Wed, Feb 01, 2023 at 04:52:15PM +0100, Miroslav Lichvar wrote:
> > + if (next) {
> > + atop.jumpSeconds = next->local_tai_offset - tz->local_tai_offset;
> > + atop.timeOfNextJump.seconds_lsb = next->timestamp;
> > + }
>
> Is this intentionally not setting the _msb field, ignoring distant future?
Yes, it is intentional. The LSB is 32 bits of seconds, so the range is
(/ (/ (/ 4294967295 3600) 24) 365) = 136 years
It is hard for me to understand why a time zone should change more
that one year in the future from a given date?
Thanks,
Richard
|
|
From: Richard C. <ric...@gm...> - 2023-02-11 16:04:37
|
On Thu, Feb 02, 2023 at 11:52:09AM +0100, Miroslav Lichvar wrote: > On Sat, Jan 28, 2023 at 02:43:41PM -0800, Richard Cochran wrote: > > The Power Profile specifies two new TLVs: > > It would be nice to have the new options documented in the ptp4l man > page. Please consider renaming tztool to something more PTP-specific, > (maybe tz2ptp4l?), to not confuse people that is does something with > the system tz database. How about "tz_alttime_tool" ? Thanks, Richard |
|
From: Richard C. <ric...@gm...> - 2023-02-13 03:37:47
|
On Sat, Feb 11, 2023 at 08:04:27AM -0800, Richard Cochran wrote: > On Thu, Feb 02, 2023 at 11:52:09AM +0100, Miroslav Lichvar wrote: > > On Sat, Jan 28, 2023 at 02:43:41PM -0800, Richard Cochran wrote: > > > The Power Profile specifies two new TLVs: > > > > It would be nice to have the new options documented in the ptp4l man > > page. Please consider renaming tztool to something more PTP-specific, > > (maybe tz2ptp4l?), to not confuse people that is does something with > > the system tz database. > > How about "tz_alttime_tool" ? I like "tz2alttime" ... Thanks, Richard |
|
From: Richard C. <ric...@gm...> - 2023-02-13 03:40:49
|
On Sun, Feb 12, 2023 at 07:37:38PM -0800, Richard Cochran wrote: > On Sat, Feb 11, 2023 at 08:04:27AM -0800, Richard Cochran wrote: > > On Thu, Feb 02, 2023 at 11:52:09AM +0100, Miroslav Lichvar wrote: > > > On Sat, Jan 28, 2023 at 02:43:41PM -0800, Richard Cochran wrote: > > > > The Power Profile specifies two new TLVs: > > > > > > It would be nice to have the new options documented in the ptp4l man > > > page. Please consider renaming tztool to something more PTP-specific, > > > (maybe tz2ptp4l?), to not confuse people that is does something with > > > the system tz database. > > > > How about "tz_alttime_tool" ? > > I like "tz2alttime" ... or even "tz2alt", short and sweet. Thanks, Richard |