Thread: Re: [Linuxptp-devel] [PATCH v4 00/11] Profile support for IEEE C37.238-2011 and IEEE C37.238-2017 (Page 2)
PTP IEEE 1588 stack for Linux
Brought to you by:
rcochran
|
From: Miroslav L. <mli...@re...> - 2023-02-13 09:30:40
|
On Sun, Feb 12, 2023 at 07:40:36PM -0800, Richard Cochran wrote: > > > On Thu, Feb 02, 2023 at 11:52:09AM +0100, Miroslav Lichvar wrote: > > > > 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. > or even "tz2alt", short and sweet. Sounds good to me. Thanks. -- Miroslav Lichvar |
|
From: Miroslav L. <mli...@re...> - 2023-02-13 09:29:54
|
On Sat, Feb 11, 2023 at 07:51:27AM -0800, Richard Cochran wrote:
> 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?
Isn't timeOfNextJump an absolute time, i.e. will it not overflow 136
years after the epoch?
--
Miroslav Lichvar
|
|
From: Erez <ere...@gm...> - 2023-02-13 10:33:28
|
On Mon, 13 Feb 2023 at 10:32, Miroslav Lichvar <mli...@re...> wrote:
> On Sat, Feb 11, 2023 at 07:51:27AM -0800, Richard Cochran wrote:
> > 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?
>
> Isn't timeOfNextJump an absolute time, i.e. will it not overflow 136
> years after the epoch?
>
>From IEEE 1558-2019
"16.3.3.7 timeOfNextJump (UInteger48)
The value of timeOfNextJump shall be the value of the seconds portion of
the PTP Instance Time of the transmitting PTP Instance at the time that the
next discontinuity will occur.
The discontinuity occurs at the start of the second indicated by the value
of timeOfNextJump.
NOTE—If the alternate timescale implements a leap second correction
(e.g., if the alternate timescale is a local timescale at the time of a
leap second,
or if the option of this subclause is being used to compute UTC time at
the time of a leap second),
timeOfNextJump is the time when <dLS> = TAI – UTC changes.
This time is specified by the IERS (see 7.2.4 and IERS Bulletin C).
..."
I agree with Miroslav.
POSIX also address the issue regarding the 'time_t' type:
https://pubs.opengroup.org/onlinepubs/9699919799/functions/time.html
"Implementations in which *time_t* is a 32-bit signed integer (many
historical implementations) fail in the year 2038.
POSIX.1-2017 does not address this problem.
However, the use of the *time_t* type is mandated in order to ease the
eventual fix."
"In a future version of this volume of POSIX.1-2017, *time_t* is likely to
be required to be capable of representing times far in the future.
Whether this will be mandated as a 64-bit type or a requirement that a
specific date in the future be representable (for example, 10000 AD) is not
yet determined.
Systems purchased after the approval of this volume of POSIX.1-2017 should
be evaluated to determine whether their lifetime will extend past 2038."
Seems that instead of 'BUG 2000', we will have 'Bug 2038' :-)
Erez
> --
> Miroslav Lichvar
>
>
>
> _______________________________________________
> Linuxptp-devel mailing list
> Lin...@li...
> https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
>
|
|
From: Miroslav L. <mli...@re...> - 2023-02-13 11:11:23
|
On Mon, Feb 13, 2023 at 11:32:42AM +0100, Erez wrote: > "Implementations in which *time_t* is a 32-bit signed integer (many > historical implementations) fail in the year 2038. > Seems that instead of 'BUG 2000', we will have 'Bug 2038' :-) This shouldn't be a problem for PTP. The lsb field of timeOfNextJump is unsigned, so it will overflow in year 2106 (in the TAI timescale). -- Miroslav Lichvar |
|
From: Richard C. <ric...@gm...> - 2023-02-14 15:10:57
|
On Mon, Feb 13, 2023 at 12:11:08PM +0100, Miroslav Lichvar wrote: > The lsb field of timeOfNextJump is unsigned, so it will overflow in > year 2106 (in the TAI timescale). Some of the power industry equipment lasts 30 or 40 years (except in California where they make it out of sugar, and it melts at the first rain). So who knows? Maybe someone will deploy the power profile today, and it will be still running in 83 years? I'll take care of it now, so our decendents have one less 2016 bug to fix... Thanks, Richard |
|
From: Richard C. <ric...@gm...> - 2023-02-15 05:01:10
|
ChangeLog
~~~~~~~~~
v5:
Rename tztool to tz2alt
Provide man page for tz2alt
Fix year 2106 bug
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
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 ++++
tz2alt.8 | 126 ++++++++++++++++
tz2alt.c | 379 ++++++++++++++++++++++++++++++++++++++++++++++++
util.h | 7 +
16 files changed, 1245 insertions(+), 17 deletions(-)
create mode 100644 power_profile.h
create mode 100644 tz.h
create mode 100644 tz2alt.8
create mode 100644 tz2alt.c
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-02-15 05:01:10
|
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 9b86b35..f028b88 100644
--- a/config.c
+++ b/config.c
@@ -248,7 +248,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-02-15 05:01:12
|
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 f028b88..cb4421f 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 */
@@ -190,6 +191,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 },
@@ -300,6 +308,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 92f3ee3..23697a5 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) {
@@ -3332,6 +3375,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 e5837b9..3b02d2f 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
@@ -153,6 +154,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 3d838b7..b973295 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-02-15 05:01:13
|
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 23697a5..f2aabfb 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 fb807e8..66d797a 100644
--- a/tlv.c
+++ b/tlv.c
@@ -115,6 +115,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;
@@ -400,6 +401,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:
@@ -423,6 +434,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;
@@ -571,6 +583,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 b973295..a08c74a 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-02-15 05:01:19
|
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 e9072ab..2c9e3f3 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;
@@ -896,19 +907,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);
@@ -1205,6 +1214,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-02-15 05:01:20
|
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 2c9e3f3..e09bd18 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;
@@ -1533,7 +1596,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 81982c6..c9c97ba 100644
--- a/tlv.c
+++ b/tlv.c
@@ -168,6 +168,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;
@@ -338,6 +339,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;
@@ -487,6 +499,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;
@@ -549,6 +562,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-02-15 05:01:11
|
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 7a2a4fa..fb807e8 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 };
uint8_t itu_t_id[3] = { ITU_T_COMMITTEE };
static TAILQ_HEAD(tlv_pool, tlv_extra) tlv_pool =
@@ -680,6 +681,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;
struct msg_interface_rate_tlv *m;
@@ -718,6 +720,24 @@ static int org_post_recv(struct organization_tlv *org)
}
}
+ 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;
@@ -725,6 +745,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;
struct msg_interface_rate_tlv *m;
@@ -754,6 +775,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 ec22e2f..3d838b7 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-02-15 05:01:15
|
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 66d797a..81982c6 100644
--- a/tlv.c
+++ b/tlv.c
@@ -78,6 +78,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;
@@ -112,6 +128,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)
{
@@ -1065,6 +1118,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:
@@ -1128,7 +1183,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 a08c74a..15df2bb 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-02-15 05:01:23
|
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 91eb5a1..611d977 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;
@@ -896,6 +957,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;
@@ -1613,7 +1690,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 f2aabfb..3453716 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-02-15 05:01:16
|
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 e09bd18..91eb5a1 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;
@@ -1594,7 +1614,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 c9c97ba..1d08560 100644
--- a/tlv.c
+++ b/tlv.c
@@ -169,6 +169,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;
@@ -339,6 +340,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)) {
@@ -562,6 +571,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 15df2bb..8b51ffd 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-02-15 05:01:25
|
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-02-15 05:01:29
|
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 +-
tz2alt.8 | 126 ++++++++++++++++++
tz2alt.c | 379 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 510 insertions(+), 2 deletions(-)
create mode 100644 tz2alt.8
create mode 100644 tz2alt.c
diff --git a/makefile b/makefile
index 0f8f185..3e3b8b3 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 tz2alt
FILTERS = filter.o mave.o mmedian.o
SERVOS = linreg.o ntpshm.o nullf.o pi.o refclock_sock.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) tz2alt.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
+tz2alt: config.o hash.o interface.o lstab.o msg.o phc.o pmc_common.o print.o \
+ sk.o tlv.o $(TRANSP) tz2alt.o util.o version.o
+
version.o: .version version.sh $(filter-out version.d,$(DEPEND))
.version: force
diff --git a/tz2alt.8 b/tz2alt.8
new file mode 100644
index 0000000..66a6605
--- /dev/null
+++ b/tz2alt.8
@@ -0,0 +1,126 @@
+.TH TS2ALT 8 "February 2023" "linuxptp"
+.SH NAME
+tz2alt - Monitors daylight savings time changes and publishes them to PTP stack.
+
+.SH SYNOPSIS
+.B ts2alt
+[
+.B \-hmqv
+] [
+.BI \-f " conf"
+] [
+.BI \-k " key"
+] [
+.BI \-p " period"
+] [
+.BI \-w " window"
+] [
+.BI \-z " timezone"
+] [
+.I long-options
+]
+.I .\|.\|.
+
+.SH DESCRIPTION
+.B tz2alt
+leverages the local time zone database to monitor for changes in
+daylight savings time and publishes the pending changes to the PTP
+stack.
+
+.SH OPTIONS
+.TP
+.BI \-f " config"
+Read configuration from the specified file.
+No configuration file is read by default.
+.TP
+.BI \-h
+Displays the command line help summary.
+.TP
+.BI \-l " print-level"
+Sets the maximum syslog level of messages which should be printed or
+sent to the system logger. The default is 6 (LOG_INFO).
+.TP
+.B \-m
+Prints log messages to the standard output.
+.TP
+.B \-q
+Prevents sending log messages to the system logger.
+.TP
+.B \-v
+Prints the software version and exits.
+
+.SH LONG OPTIONS
+
+Each and every configuration file option (see below) may also appear
+as a "long" style command line argument. For example, the use_syslog
+option may be set using either of these two forms.
+
+.RS
+\f(CW\-\-use_syslog 1 \-\-use_syslog=1\fP
+.RE
+
+Option values given on the command line override values in the global
+section of the configuration file.
+
+.SH CONFIGURATION FILE
+
+The configuration file is divided into sections. Each section starts with a
+line containing its name enclosed in brackets and it follows with settings.
+Each setting is placed on a separate line, it contains the name of the
+option and the value separated by whitespace characters. Empty lines and lines
+starting with # are ignored.
+
+.SH GLOBAL OPTIONS
+
+.TP
+.B domainNumber
+The domain attribute of the local clock.
+The default is 0.
+
+.TP
+.B leapfile
+The path to the current leap seconds definition file. In a Debian
+system this file is provided by the tzdata package and can be found at
+/usr/share/zoneinfo/leap-seconds.list. If a leapfile is configured it
+will be reloaded if modified. The default is an empty string, which
+causes the program to use a hard coded table that reflects the known
+leap seconds on the date of the software's release.
+
+.TP
+.B logging_level
+The maximum logging level of messages which should be printed.
+The default is 6 (LOG_INFO).
+
+.TP
+.B message_tag
+The tag which is added to all messages printed to the standard output
+or system log. The default is an empty string (which cannot be set in
+the configuration file as the option requires an argument).
+
+.TP
+.B transportSpecific
+The transport specific field. Must be in the range 0 to 255.
+The default is 0.
+
+.TP
+.B use_syslog
+Print messages to the system log if enabled. The default is 1 (enabled).
+
+.TP
+.B verbose
+Print messages to the standard output if enabled. The default is 0 (disabled).
+
+.SH WARNING
+
+Be cautious when sharing the same configuration file between ptp4l,
+phc2sys, and tz2alt. Keep in mind that values specified in the
+configuration file take precedence over the default values. If an
+option which is common to the other programs is set in the
+configuration file, then the value will be applied to all the programs
+using the file, and this might not be what is expected.
+
+It is recommended to use separate configuration files for ptp4l,
+phc2sys, and tz2alt in order to avoid any unexpected behavior.
+
+.SH SEE ALSO
+.BR ptp4l (8)
diff --git a/tz2alt.c b/tz2alt.c
new file mode 100644
index 0000000..ed06420
--- /dev/null
+++ b/tz2alt.c
@@ -0,0 +1,379 @@
+/**
+ * @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;
+ uint64_t time_of_next_jump;
+ 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;
+ time_of_next_jump = (uint64_t) next->timestamp;
+ atop.timeOfNextJump.seconds_lsb = time_of_next_jump & 0xffffffff;
+ atop.timeOfNextJump.seconds_msb = time_of_next_jump >> 32;
+ }
+ 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;
+ }
+ 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: Miroslav L. <mli...@re...> - 2023-02-15 14:15:29
|
On Tue, Feb 14, 2023 at 09:00:50PM -0800, Richard Cochran wrote:
> @@ -300,6 +308,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),
I'm sorry I didn't notice this earlier. Can you please add these to
configs/default.cfg?
--
Miroslav Lichvar
|
|
From: Richard C. <ric...@gm...> - 2023-02-17 04:16:55
|
On Wed, Feb 15, 2023 at 03:15:13PM +0100, Miroslav Lichvar wrote:
> On Tue, Feb 14, 2023 at 09:00:50PM -0800, Richard Cochran wrote:
> > @@ -300,6 +308,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),
>
> I'm sorry I didn't notice this earlier. Can you please add these to
> configs/default.cfg?
Sure, and the man page, too...
|
|
From: Miroslav L. <mli...@re...> - 2023-02-15 14:20:18
|
On Tue, Feb 14, 2023 at 09:00:54PM -0800, Richard Cochran wrote:
> @@ -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);
Another instance of the Y2106 problem :).
With this patch it works for me (new test in the testsuite):
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -179,6 +179,7 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
char onoff_port_state[4] = "off";
char onoff_time_status[4] = "off";
char display_name[11] = {0};
+ uint64_t jump;
uint8_t key;
int enable;
@@ -239,16 +240,18 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
"keyField %hhu "
"currentOffset %d "
"jumpSeconds %d "
- "timeOfNextJump %u ",
+ "timeOfNextJump %" SCNu64,
&atop.keyField,
&atop.currentOffset,
&atop.jumpSeconds,
- &atop.timeOfNextJump.seconds_lsb);
+ &jump);
if (cnt != 4) {
fprintf(stderr, "%s SET needs 4 values\n",
idtab[index].name);
break;
}
+ atop.timeOfNextJump.seconds_lsb = jump & 0xffffffff;
+ atop.timeOfNextJump.seconds_msb = jump >> 32;
pmc_send_set_action(pmc, code, &atop, sizeof(atop));
break;
case MID_GRANDMASTER_SETTINGS_NP:
The rest of the patchset looks good to me.
--
Miroslav Lichvar
|
|
From: Richard C. <ric...@gm...> - 2023-02-20 02:04:15
|
On Wed, Feb 15, 2023 at 03:20:06PM +0100, Miroslav Lichvar wrote: > With this patch it works for me (new test in the testsuite): Thanks for the patch, and thanks for the super awesome test suite! It lets us develop with confidence. Richard |
|
From: Richard C. <ric...@gm...> - 2023-02-20 20:58:11
|
ChangeLog
~~~~~~~~~
v6:
Add new configuration options into default.cfg and man page
Make pmc SET command ready for 2106 (Miroslav)
Use SPDX tag for new file tz.h
v5:
Rename tztool to tz2alt
Provide man page for tz2alt
Fix year 2106 bug
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
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 +-
configs/default.cfg | 5 +
makefile | 7 +-
pmc.c | 49 ++++++
pmc_common.c | 136 +++++++++++++++-
pmc_common.h | 2 +
port.c | 76 ++++++++-
port_private.h | 3 +
power_profile.h | 31 ++++
ptp4l.8 | 38 +++++
tlv.c | 146 +++++++++++++++++
tlv.h | 64 ++++++++
tz.h | 13 ++
tz2alt.8 | 126 +++++++++++++++
tz2alt.c | 379 ++++++++++++++++++++++++++++++++++++++++++++
util.h | 7 +
18 files changed, 1278 insertions(+), 17 deletions(-)
create mode 100644 power_profile.h
create mode 100644 tz.h
create mode 100644 tz2alt.8
create mode 100644 tz2alt.c
--
2.30.2
|
|
From: Richard C. <ric...@gm...> - 2023-02-20 20:58:09
|
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 9b86b35..f028b88 100644
--- a/config.c
+++ b/config.c
@@ -248,7 +248,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-02-20 20:58:12
|
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 7a2a4fa..fb807e8 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 };
uint8_t itu_t_id[3] = { ITU_T_COMMITTEE };
static TAILQ_HEAD(tlv_pool, tlv_extra) tlv_pool =
@@ -680,6 +681,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;
struct msg_interface_rate_tlv *m;
@@ -718,6 +720,24 @@ static int org_post_recv(struct organization_tlv *org)
}
}
+ 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;
@@ -725,6 +745,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;
struct msg_interface_rate_tlv *m;
@@ -754,6 +775,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 ec22e2f..3d838b7 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-02-20 20:58:14
|
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 66d797a..81982c6 100644
--- a/tlv.c
+++ b/tlv.c
@@ -78,6 +78,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;
@@ -112,6 +128,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)
{
@@ -1065,6 +1118,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:
@@ -1128,7 +1183,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 a08c74a..15df2bb 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
|