Redundant HA PTP timing clock sources support

Enhanced phc2sys to support multiple PTP timing clock sources, to
select the best clock source available according to the clocks
statuses.

A series of changes were patched back from a newer version of the
linuxptp package. They contain the support for multiple pmc nodes,
necessary to communicate with multiple ptp4l instances.

The phc2sys is now able to automatically select the best clock
according to the clocks statuses, and also monitors any clock
status change and act to keep the system synchronized to the
best clock source available.

A new set of configuration options were added to control the behavior
of the automatic clock selection algorithm and to configure the clock
source interfaces.

And a new command interface was added to phc2sys to gather statuses
about the clocks configured and the HA algorithm. This interface also
provides commands to control the clock source selection for debug and
maintenance proposes.

Test plan:
PASS: Verify the linuxptp package is built containing all the patches.
PASS: Verify the .deb package produced in the build install and that
all the PTP different deployments new and existing are OK.
PASS: Verify that a new image containing the linuxptp packed can be
installed and that all the PTP different deployments new and existing
are OK.

Story: 2010723
Task: 48642
Change-Id: Ic8c4d9bd335c582a91f1f4418947a81fc5e8b4f9
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
This commit is contained in:
Andre Mauricio Zelak 2023-08-16 17:46:32 -03:00
parent f491502929
commit deeacbcdf3
48 changed files with 11015 additions and 10 deletions

View File

@ -1,7 +1,7 @@
From 63b43924294da6cb177d0509120b2e957580441c Mon Sep 17 00:00:00 2001
From: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon, 31 May 2021 11:07:52 +0200
Subject: [PATCH 1/10] clock: Reset state when switching port with same best clock.
Subject: [PATCH 1/47] clock: Reset state when switching port with same best clock.
When the best port is changed, but the ID of the best clock doesn't
change (e.g. a passive port is activated on link failure), reset the

View File

@ -4,7 +4,7 @@ In-Reply-To: <0389752e3aecf8d2b2743f16ce1408a58088bea9.1630418391.git.Jim.Somerv
References: <0389752e3aecf8d2b2743f16ce1408a58088bea9.1630418391.git.Jim.Somerville@windriver.com>
From: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon, 31 May 2021 11:07:53 +0200
Subject: [PATCH 2/10] clock: Reset clock check on best clock/port change.
Subject: [PATCH 2/47] clock: Reset clock check on best clock/port change.
Reset the clock check when the best clock or port changes, together with
the other state like current estimated delay and frequency. This avoids

View File

@ -4,7 +4,7 @@ In-Reply-To: <0389752e3aecf8d2b2743f16ce1408a58088bea9.1630418391.git.Jim.Somerv
References: <0389752e3aecf8d2b2743f16ce1408a58088bea9.1630418391.git.Jim.Somerville@windriver.com>
From: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon, 31 May 2021 11:07:54 +0200
Subject: [PATCH 3/10] port: Don't check timestamps from non-slave ports.
Subject: [PATCH 3/47] port: Don't check timestamps from non-slave ports.
Don't perform the sanity check on receive timestamps from ports in
non-slave states to avoid false positives in the jbod mode, where

View File

@ -4,7 +4,7 @@ In-Reply-To: <0389752e3aecf8d2b2743f16ce1408a58088bea9.1630418391.git.Jim.Somerv
References: <0389752e3aecf8d2b2743f16ce1408a58088bea9.1630418391.git.Jim.Somerville@windriver.com>
From: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon, 31 May 2021 11:07:55 +0200
Subject: [PATCH 4/10] port: Don't renew raw transport.
Subject: [PATCH 4/47] port: Don't renew raw transport.
Renewing of the transport on announce/sync timeout is needed in the
client-only mode to avoid getting stuck with a broken multicast socket

View File

@ -4,7 +4,7 @@ In-Reply-To: <0389752e3aecf8d2b2743f16ce1408a58088bea9.1630611367.git.Jim.Somerv
References: <0389752e3aecf8d2b2743f16ce1408a58088bea9.1630611367.git.Jim.Somerville@windriver.com>
From: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon, 31 May 2021 11:07:56 +0200
Subject: [PATCH 5/10] clockcheck: Increase minimum interval.
Subject: [PATCH 5/47] clockcheck: Increase minimum interval.
Increase the minimum check interval to 1 second to measure the frequency
offset more accurately and with default configuration make false

View File

@ -4,7 +4,7 @@ In-Reply-To: <0389752e3aecf8d2b2743f16ce1408a58088bea9.1630418391.git.Jim.Somerv
References: <0389752e3aecf8d2b2743f16ce1408a58088bea9.1630418391.git.Jim.Somerville@windriver.com>
From: Cole Walker <cole.walker@windriver.com>
Date: Wed, 23 Jun 2021 11:14:41 -0400
Subject: [PATCH 6/10] Add option to disable default port selection in phc2sys
Subject: [PATCH 6/47] Add option to disable default port selection in phc2sys
This change serves to address an issue in phc2sys
where the local ptp clocks are not synced together properly if the local

View File

@ -1,7 +1,7 @@
From 6428c2628c013c408ec09355ad37eb12fa6bb20f Mon Sep 17 00:00:00 2001
From: Miroslav Lichvar <mlichvar@redhat.com>
Date: Wed, 18 May 2022 11:33:35 +0200
Subject: [PATCH 7/10] sysoff: Change sysoff_measure() to return errno.
Subject: [PATCH 7/47] sysoff: Change sysoff_measure() to return errno.
Return -errno from failed ioctl instead of the SYSOFF_* enum from the
measurement functions to allow the callers to check for specific errors.

View File

@ -1,7 +1,7 @@
From 38a530d94fc5aa73bde424d05e2e38348e64d7e5 Mon Sep 17 00:00:00 2001
From: Miroslav Lichvar <mlichvar@redhat.com>
Date: Wed, 18 May 2022 11:33:36 +0200
Subject: [PATCH 8/10] sysoff: Change log level of ioctl error messages.
Subject: [PATCH 8/47] sysoff: Change log level of ioctl error messages.
Change the log level of ioctl error messages to the error level to make
them visible in default configuration, with the exception of EOPNOTSUPP

View File

@ -1,7 +1,7 @@
From 11ae077e31d9957df01aacfa17eea5b5d548b249 Mon Sep 17 00:00:00 2001
From: Miroslav Lichvar <mlichvar@redhat.com>
Date: Wed, 18 May 2022 11:33:37 +0200
Subject: [PATCH 9/10] sysoff: Retry on EBUSY when probing supported ioctls.
Subject: [PATCH 9/47] sysoff: Retry on EBUSY when probing supported ioctls.
Handle EBUSY when probing support for a PTP_SYS_OFFSET ioctl. Try each
ioctl up to three times before giving up on it to make the detection

View File

@ -1,7 +1,7 @@
From e4fd6a930213e6f0f009eb070d51b1e14db60d1b Mon Sep 17 00:00:00 2001
From: Miroslav Lichvar <mlichvar@redhat.com>
Date: Wed, 18 May 2022 11:33:38 +0200
Subject: [PATCH 10/10] phc2sys: Don't exit when reading of PHC fails with EBUSY.
Subject: [PATCH 10/47] phc2sys: Don't exit when reading of PHC fails with EBUSY.
Reading of the PHC can occasionally fail with some drivers, e.g. the ice
driver returns EBUSY when it fails to get a lock. Continue in the loop

View File

@ -0,0 +1,641 @@
From 0c5c39a8cd3675d91e872a75d75854907950957d Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 13:47:47 -0300
Subject: [PATCH 11/47] phc2sys: extract PMC functionality into a smaller
struct pmc_node
This creates a smaller structure within phc2sys_private, which embeds
all properties related to the PMC. This structure is called "pmc_node",
which is somewhat reminiscent of the old name of phc2sys_private (struct
node). But the advantage is that struct pmc_node can be reused by other
modules.
The phc2sys code that is executed upon a subscription update,
recv_subscribed, is now refactored into a function pointer callback. It
is imaginable that other programs might to do other things in it.
Note that putting this function pointer in struct pmc_node is, long
term, maybe not the best of choices. It is only needed from the
run_pmc_events() code path, and could be therefore passed as a more
local callback to that function only. However, for that, further
refactoring is needed inside the common run_pmc() function, so that is
being left for another time.
Signed-off-by: Vladimir Oltean <olteanv@gmail.com>
[commit 1ca1419ad7e6cc04cf893f5a9ca449a90f39f4e0 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 228 ++++++++++++++++++++++++++++++------------------------
1 file changed, 125 insertions(+), 103 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 7959015..86b9822 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -39,6 +39,7 @@
#include "clockadj.h"
#include "clockcheck.h"
+#include "contain.h"
#include "ds.h"
#include "fsm.h"
#include "missing.h"
@@ -99,23 +100,34 @@ struct port {
struct clock *clock;
};
+struct pmc_node;
+
+typedef int pmc_node_recv_subscribed_t(struct pmc_node *node,
+ struct ptp_message *msg,
+ int excluded);
+
+struct pmc_node {
+ struct pmc *pmc;
+ int pmc_ds_requested;
+ uint64_t pmc_last_update;
+ int sync_offset;
+ int leap;
+ int utc_offset_traceable;
+ int clock_identity_set;
+ struct ClockIdentity clock_identity;
+ pmc_node_recv_subscribed_t *recv_subscribed;
+};
+
struct phc2sys_private {
unsigned int stats_max_count;
int sanity_freq_limit;
enum servo_type servo_type;
int phc_readings;
double phc_interval;
- int sync_offset;
int forced_sync_offset;
- int utc_offset_traceable;
- int leap;
int kernel_leap;
- struct pmc *pmc;
- int pmc_ds_requested;
- uint64_t pmc_last_update;
int state_changed;
- int clock_identity_set;
- struct ClockIdentity clock_identity;
+ struct pmc_node node;
LIST_HEAD(port_head, port) ports;
LIST_HEAD(clock_head, clock) clocks;
LIST_HEAD(dst_clock_head, clock) dst_clocks;
@@ -125,16 +137,16 @@ struct phc2sys_private {
static struct config *phc2sys_config;
-static int update_pmc(struct phc2sys_private *priv, int subscribe);
+static int update_pmc_node(struct pmc_node *node, int subscribe);
static int clock_handle_leap(struct phc2sys_private *priv,
struct clock *clock,
int64_t offset, uint64_t ts);
-static int run_pmc_get_utc_offset(struct phc2sys_private *priv,
+static int run_pmc_get_utc_offset(struct pmc_node *node,
int timeout);
-static void run_pmc_events(struct phc2sys_private *priv);
+static void run_pmc_events(struct pmc_node *node);
static int normalize_state(int state);
-static int run_pmc_port_properties(struct phc2sys_private *priv,
+static int run_pmc_port_properties(struct pmc_node *node,
int timeout, unsigned int port,
int *state, int *tstamping, char *iface);
@@ -325,7 +337,7 @@ static void clock_reinit(struct phc2sys_private *priv, struct clock *clock,
LIST_FOREACH(p, &priv->ports, list) {
if (p->clock == clock) {
- ret = run_pmc_port_properties(priv, 1000, p->number,
+ ret = run_pmc_port_properties(&priv->node, 1000, p->number,
&state, &timestamping,
iface);
if (ret > 0)
@@ -660,7 +672,7 @@ static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
if (src == CLOCK_INVALID) {
/* The sync offset can't be applied with PPS alone. */
- priv->sync_offset = 0;
+ priv->node.sync_offset = 0;
} else {
enable_pps_output(priv->master->clkid);
}
@@ -691,7 +703,7 @@ static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
pps_offset = pps_ts - phc_ts;
}
- if (update_pmc(priv, 0) < 0)
+ if (update_pmc_node(&priv->node, 0) < 0)
continue;
update_clock(priv, clock, pps_offset, pps_ts, -1);
}
@@ -729,15 +741,15 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
while (is_running()) {
clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL);
- if (update_pmc(priv, subscriptions) < 0)
+ if (update_pmc_node(&priv->node, subscriptions) < 0)
continue;
if (subscriptions) {
- run_pmc_events(priv);
+ run_pmc_events(&priv->node);
if (priv->state_changed) {
/* force getting offset, as it may have
* changed after the port state change */
- if (run_pmc_get_utc_offset(priv, 1000) <= 0) {
+ if (run_pmc_get_utc_offset(&priv->node, 1000) <= 0) {
pr_err("failed to get UTC offset");
continue;
}
@@ -800,13 +812,12 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
return 0;
}
-static int check_clock_identity(struct phc2sys_private *priv,
- struct ptp_message *msg)
+static int check_clock_identity(struct pmc_node *node, struct ptp_message *msg)
{
- if (!priv->clock_identity_set)
+ if (!node->clock_identity_set)
return 1;
- return cid_eq(&priv->clock_identity,
- &msg->header.sourcePortIdentity.clockIdentity);
+ return cid_eq(&node->clock_identity,
+ &msg->header.sourcePortIdentity.clockIdentity);
}
static int is_msg_mgt(struct ptp_message *msg)
@@ -876,9 +887,13 @@ static int clock_compute_state(struct phc2sys_private *priv,
return state;
}
-static int recv_subscribed(struct phc2sys_private *priv,
- struct ptp_message *msg, int excluded)
+#define node_to_phc2sys(node) \
+ container_of(node, struct phc2sys_private, node)
+
+static int phc2sys_recv_subscribed(struct pmc_node *node,
+ struct ptp_message *msg, int excluded)
{
+ struct phc2sys_private *priv = node_to_phc2sys(node);
int mgt_id, state;
struct portDS *pds;
struct port *port;
@@ -913,29 +928,28 @@ static int recv_subscribed(struct phc2sys_private *priv,
return 0;
}
-static void send_subscription(struct phc2sys_private *priv)
+static void send_subscription(struct pmc_node *node)
{
struct subscribe_events_np sen;
memset(&sen, 0, sizeof(sen));
sen.duration = PMC_SUBSCRIBE_DURATION;
sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
- pmc_send_set_action(priv->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
+ pmc_send_set_action(node->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
}
-static int init_pmc(struct config *cfg, struct phc2sys_private *priv)
+static int init_pmc_node(struct config *cfg, struct pmc_node *node,
+ const char *uds,
+ pmc_node_recv_subscribed_t *recv_subscribed)
{
- char uds_local[MAX_IFNAME_SIZE + 1];
-
- snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d",
- getpid());
- priv->pmc = pmc_create(cfg, TRANS_UDS, uds_local, 0,
+ node->pmc = pmc_create(cfg, TRANS_UDS, uds, 0,
config_get_int(cfg, NULL, "domainNumber"),
config_get_int(cfg, NULL, "transportSpecific") << 4, 1);
- if (!priv->pmc) {
+ if (!node->pmc) {
pr_err("failed to create pmc");
return -1;
}
+ node->recv_subscribed = recv_subscribed;
return 0;
}
@@ -946,7 +960,7 @@ static int init_pmc(struct config *cfg, struct phc2sys_private *priv)
* -1: error reported by the other side
* -2: local error, fatal
*/
-static int run_pmc(struct phc2sys_private *priv, int timeout, int ds_id,
+static int run_pmc(struct pmc_node *node, int timeout, int ds_id,
struct ptp_message **msg)
{
#define N_FD 1
@@ -954,9 +968,9 @@ static int run_pmc(struct phc2sys_private *priv, int timeout, int ds_id,
int cnt, res;
while (1) {
- pollfd[0].fd = pmc_get_transport_fd(priv->pmc);
+ pollfd[0].fd = pmc_get_transport_fd(node->pmc);
pollfd[0].events = POLLIN|POLLPRI;
- if (!priv->pmc_ds_requested && ds_id >= 0)
+ if (!node->pmc_ds_requested && ds_id >= 0)
pollfd[0].events |= POLLOUT;
cnt = poll(pollfd, N_FD, timeout);
@@ -966,7 +980,7 @@ static int run_pmc(struct phc2sys_private *priv, int timeout, int ds_id,
}
if (!cnt) {
/* Request the data set again in the next run. */
- priv->pmc_ds_requested = 0;
+ node->pmc_ds_requested = 0;
return 0;
}
@@ -975,24 +989,24 @@ static int run_pmc(struct phc2sys_private *priv, int timeout, int ds_id,
!(pollfd[0].revents & (POLLIN|POLLPRI))) {
switch (ds_id) {
case TLV_SUBSCRIBE_EVENTS_NP:
- send_subscription(priv);
+ send_subscription(node);
break;
default:
- pmc_send_get_action(priv->pmc, ds_id);
+ pmc_send_get_action(node->pmc, ds_id);
break;
}
- priv->pmc_ds_requested = 1;
+ node->pmc_ds_requested = 1;
}
if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
continue;
- *msg = pmc_recv(priv->pmc);
+ *msg = pmc_recv(node->pmc);
if (!*msg)
continue;
- if (!check_clock_identity(priv, *msg)) {
+ if (!check_clock_identity(node, *msg)) {
msg_put(*msg);
*msg = NULL;
continue;
@@ -1000,29 +1014,29 @@ static int run_pmc(struct phc2sys_private *priv, int timeout, int ds_id,
res = is_msg_mgt(*msg);
if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
- priv->pmc_ds_requested = 0;
+ node->pmc_ds_requested = 0;
return -1;
}
- if (res <= 0 || recv_subscribed(priv, *msg, ds_id) ||
+ if (res <= 0 || node->recv_subscribed(node, *msg, ds_id) ||
get_mgt_id(*msg) != ds_id) {
msg_put(*msg);
*msg = NULL;
continue;
}
- priv->pmc_ds_requested = 0;
+ node->pmc_ds_requested = 0;
return 1;
}
}
-static int run_pmc_wait_sync(struct phc2sys_private *priv, int timeout)
+static int run_pmc_wait_sync(struct pmc_node *node, int timeout)
{
struct ptp_message *msg;
- int res;
- void *data;
Enumeration8 portState;
+ void *data;
+ int res;
while (1) {
- res = run_pmc(priv, timeout, TLV_PORT_DATA_SET, &msg);
+ res = run_pmc(node, timeout, TLV_PORT_DATA_SET, &msg);
if (res <= 0)
return res;
@@ -1036,47 +1050,47 @@ static int run_pmc_wait_sync(struct phc2sys_private *priv, int timeout)
return 1;
}
/* try to get more data sets (for other ports) */
- priv->pmc_ds_requested = 1;
+ node->pmc_ds_requested = 1;
}
}
-static int run_pmc_get_utc_offset(struct phc2sys_private *priv, int timeout)
+static int run_pmc_get_utc_offset(struct pmc_node *node, int timeout)
{
struct ptp_message *msg;
int res;
struct timePropertiesDS *tds;
- res = run_pmc(priv, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
+ res = run_pmc(node, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
if (res <= 0)
return res;
tds = (struct timePropertiesDS *)get_mgt_data(msg);
if (tds->flags & PTP_TIMESCALE) {
- priv->sync_offset = tds->currentUtcOffset;
+ node->sync_offset = tds->currentUtcOffset;
if (tds->flags & LEAP_61)
- priv->leap = 1;
+ node->leap = 1;
else if (tds->flags & LEAP_59)
- priv->leap = -1;
+ node->leap = -1;
else
- priv->leap = 0;
- priv->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
+ node->leap = 0;
+ node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
tds->flags & TIME_TRACEABLE;
} else {
- priv->sync_offset = 0;
- priv->leap = 0;
- priv->utc_offset_traceable = 0;
+ node->sync_offset = 0;
+ node->leap = 0;
+ node->utc_offset_traceable = 0;
}
msg_put(msg);
return 1;
}
-static int run_pmc_get_number_ports(struct phc2sys_private *priv, int timeout)
+static int run_pmc_get_number_ports(struct pmc_node *node, int timeout)
{
struct ptp_message *msg;
int res;
struct defaultDS *dds;
- res = run_pmc(priv, timeout, TLV_DEFAULT_DATA_SET, &msg);
+ res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
if (res <= 0)
return res;
@@ -1086,36 +1100,36 @@ static int run_pmc_get_number_ports(struct phc2sys_private *priv, int timeout)
return res;
}
-static int run_pmc_subscribe(struct phc2sys_private *priv, int timeout)
+static int run_pmc_subscribe(struct pmc_node *node, int timeout)
{
struct ptp_message *msg;
int res;
- res = run_pmc(priv, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
+ res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
if (res <= 0)
return res;
msg_put(msg);
return 1;
}
-static void run_pmc_events(struct phc2sys_private *priv)
+static void run_pmc_events(struct pmc_node *node)
{
struct ptp_message *msg;
- run_pmc(priv, 0, -1, &msg);
+ run_pmc(node, 0, -1, &msg);
}
-static int run_pmc_port_properties(struct phc2sys_private *priv, int timeout,
- unsigned int port,
- int *state, int *tstamping, char *iface)
+static int run_pmc_port_properties(struct pmc_node *node, int timeout,
+ unsigned int port, int *state,
+ int *tstamping, char *iface)
{
struct ptp_message *msg;
int res, len;
struct port_properties_np *ppn;
- pmc_target_port(priv->pmc, port);
+ pmc_target_port(node->pmc, port);
while (1) {
- res = run_pmc(priv, timeout, TLV_PORT_PROPERTIES_NP, &msg);
+ res = run_pmc(node, timeout, TLV_PORT_PROPERTIES_NP, &msg);
if (res <= 0)
goto out;
@@ -1138,32 +1152,35 @@ static int run_pmc_port_properties(struct phc2sys_private *priv, int timeout,
break;
}
out:
- pmc_target_all(priv->pmc);
+ pmc_target_all(node->pmc);
return res;
}
-static int run_pmc_clock_identity(struct phc2sys_private *priv, int timeout)
+static int run_pmc_clock_identity(struct pmc_node *node, int timeout)
{
struct ptp_message *msg;
struct defaultDS *dds;
int res;
- res = run_pmc(priv, timeout, TLV_DEFAULT_DATA_SET, &msg);
+ res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
if (res <= 0)
return res;
dds = (struct defaultDS *)get_mgt_data(msg);
- memcpy(&priv->clock_identity, &dds->clockIdentity,
+ memcpy(&node->clock_identity, &dds->clockIdentity,
sizeof(struct ClockIdentity));
- priv->clock_identity_set = 1;
+ node->clock_identity_set = 1;
msg_put(msg);
return 1;
}
-static void close_pmc(struct phc2sys_private *priv)
+static void close_pmc_node(struct pmc_node *node)
{
- pmc_destroy(priv->pmc);
- priv->pmc = NULL;
+ if (!node->pmc)
+ return;
+
+ pmc_destroy(node->pmc);
+ node->pmc = NULL;
}
static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
@@ -1178,7 +1195,7 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
while (1) {
if (!is_running())
return -1;
- res = run_pmc_clock_identity(priv, 1000);
+ res = run_pmc_clock_identity(&priv->node, 1000);
if (res < 0)
return -1;
if (res > 0)
@@ -1187,20 +1204,20 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
pr_notice("Waiting for ptp4l...");
}
- number_ports = run_pmc_get_number_ports(priv, 1000);
+ number_ports = run_pmc_get_number_ports(&priv->node, 1000);
if (number_ports <= 0) {
pr_err("failed to get number of ports");
return -1;
}
- res = run_pmc_subscribe(priv, 1000);
+ res = run_pmc_subscribe(&priv->node, 1000);
if (res <= 0) {
pr_err("failed to subscribe");
return -1;
}
for (i = 1; i <= number_ports; i++) {
- res = run_pmc_port_properties(priv, 1000, i, &state,
+ res = run_pmc_port_properties(&priv->node, 1000, i, &state,
&timestamping, iface);
if (res == -1) {
/* port does not exist, ignore the port */
@@ -1237,7 +1254,7 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
}
/* get initial offset */
- if (run_pmc_get_utc_offset(priv, 1000) <= 0) {
+ if (run_pmc_get_utc_offset(&priv->node, 1000) <= 0) {
pr_err("failed to get UTC offset");
return -1;
}
@@ -1245,7 +1262,7 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
}
/* Returns: -1 in case of error, 0 otherwise */
-static int update_pmc(struct phc2sys_private *priv, int subscribe)
+static int update_pmc_node(struct pmc_node *node, int subscribe)
{
struct timespec tp;
uint64_t ts;
@@ -1256,13 +1273,13 @@ static int update_pmc(struct phc2sys_private *priv, int subscribe)
}
ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
- if (priv->pmc &&
- !(ts > priv->pmc_last_update &&
- ts - priv->pmc_last_update < PMC_UPDATE_INTERVAL)) {
+ if (node->pmc &&
+ !(ts > node->pmc_last_update &&
+ ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
if (subscribe)
- run_pmc_subscribe(priv, 0);
- if (run_pmc_get_utc_offset(priv, 0) > 0)
- priv->pmc_last_update = ts;
+ run_pmc_subscribe(node, 0);
+ if (run_pmc_get_utc_offset(node, 0) > 0)
+ node->pmc_last_update = ts;
}
return 0;
@@ -1272,9 +1289,9 @@ static int update_pmc(struct phc2sys_private *priv, int subscribe)
static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
int64_t offset, uint64_t ts)
{
- int clock_leap, node_leap = priv->leap;
+ int clock_leap, node_leap = priv->node.leap;
- clock->sync_offset = priv->sync_offset;
+ clock->sync_offset = priv->node.sync_offset;
if ((node_leap || clock->leap_set) &&
clock->is_utc != priv->master->is_utc) {
@@ -1315,7 +1332,7 @@ static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
}
}
- if (priv->utc_offset_traceable &&
+ if (priv->node.utc_offset_traceable &&
clock->utc_offset_set != clock->sync_offset) {
if (clock->clkid == CLOCK_REALTIME)
sysclk_set_tai_offset(clock->sync_offset);
@@ -1370,6 +1387,7 @@ static void usage(char *progname)
int main(int argc, char *argv[])
{
char *config = NULL, *dst_name = NULL, *progname, *src_name = NULL;
+ char uds_local[MAX_IFNAME_SIZE + 1];
struct clock *src, *dst;
struct config *cfg;
struct option *opts;
@@ -1478,7 +1496,7 @@ int main(int argc, char *argv[])
goto end;
break;
case 'O':
- if (get_arg_val_i(c, optarg, &priv.sync_offset,
+ if (get_arg_val_i(c, optarg, &priv.node.sync_offset,
INT_MIN, INT_MAX))
goto end;
priv.forced_sync_offset = -1;
@@ -1605,8 +1623,12 @@ int main(int argc, char *argv[])
priv.sanity_freq_limit = config_get_int(cfg, NULL, "sanity_freq_limit");
priv.default_sync = config_get_int(cfg, NULL, "default_sync");
+ snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d",
+ getpid());
+
if (autocfg) {
- if (init_pmc(cfg, &priv))
+ if (init_pmc_node(cfg, &priv.node, uds_local,
+ phc2sys_recv_subscribed))
goto end;
if (auto_init_ports(&priv, rt) < 0)
goto end;
@@ -1643,11 +1665,12 @@ int main(int argc, char *argv[])
r = -1;
if (wait_sync) {
- if (init_pmc(cfg, &priv))
+ if (init_pmc_node(cfg, &priv.node, uds_local,
+ phc2sys_recv_subscribed))
goto end;
while (is_running()) {
- r = run_pmc_wait_sync(&priv, 1000);
+ r = run_pmc_wait_sync(&priv.node, 1000);
if (r < 0)
goto end;
if (r > 0)
@@ -1657,7 +1680,7 @@ int main(int argc, char *argv[])
}
if (!priv.forced_sync_offset) {
- r = run_pmc_get_utc_offset(&priv, 1000);
+ r = run_pmc_get_utc_offset(&priv.node, 1000);
if (r <= 0) {
pr_err("failed to get UTC offset");
goto end;
@@ -1667,7 +1690,7 @@ int main(int argc, char *argv[])
if (priv.forced_sync_offset ||
(src->clkid != CLOCK_REALTIME && dst->clkid != CLOCK_REALTIME) ||
src->clkid == CLOCK_INVALID)
- close_pmc(&priv);
+ close_pmc_node(&priv.node);
}
if (pps_fd >= 0) {
@@ -1680,8 +1703,7 @@ int main(int argc, char *argv[])
}
end:
- if (priv.pmc)
- close_pmc(&priv);
+ close_pmc_node(&priv.node);
clock_cleanup(&priv);
port_cleanup(&priv);
config_destroy(cfg);
--
2.25.1

View File

@ -0,0 +1,143 @@
From 87d8e7281e3e66813d0c669bea0b5335a8cbb6b6 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 13:59:48 -0300
Subject: [PATCH 12/47] phc2sys: make PMC functions non-static
In preparation of a trivial movement of code to pmc_common.c, remove the
"static" keyword from the functions that will end up there, since they
will be still called from phc2sys.c for now.
Signed-off-by: Vladimir Oltean <olteanv@gmail.com>
[commit 2ccbb14450e1e96168a2604c0e8c96ae5a6a5bf0 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 40 +++++++++++++++++++---------------------
1 file changed, 19 insertions(+), 21 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 86b9822..d5b8e71 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -137,18 +137,17 @@ struct phc2sys_private {
static struct config *phc2sys_config;
-static int update_pmc_node(struct pmc_node *node, int subscribe);
+int update_pmc_node(struct pmc_node *node, int subscribe);
static int clock_handle_leap(struct phc2sys_private *priv,
struct clock *clock,
int64_t offset, uint64_t ts);
-static int run_pmc_get_utc_offset(struct pmc_node *node,
- int timeout);
-static void run_pmc_events(struct pmc_node *node);
+int run_pmc_get_utc_offset(struct pmc_node *node, int timeout);
+void run_pmc_events(struct pmc_node *node);
static int normalize_state(int state);
-static int run_pmc_port_properties(struct pmc_node *node,
- int timeout, unsigned int port,
- int *state, int *tstamping, char *iface);
+int run_pmc_port_properties(struct pmc_node *node, int timeout,
+ unsigned int port, int *state,
+ int *tstamping, char *iface);
static struct servo *servo_add(struct phc2sys_private *priv,
struct clock *clock)
@@ -838,13 +837,13 @@ static int is_msg_mgt(struct ptp_message *msg)
return 0;
}
-static int get_mgt_id(struct ptp_message *msg)
+int get_mgt_id(struct ptp_message *msg)
{
struct management_tlv *mgt = (struct management_tlv *) msg->management.suffix;
return mgt->id;
}
-static void *get_mgt_data(struct ptp_message *msg)
+void *get_mgt_data(struct ptp_message *msg)
{
struct management_tlv *mgt = (struct management_tlv *) msg->management.suffix;
return mgt->data;
@@ -938,9 +937,8 @@ static void send_subscription(struct pmc_node *node)
pmc_send_set_action(node->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
}
-static int init_pmc_node(struct config *cfg, struct pmc_node *node,
- const char *uds,
- pmc_node_recv_subscribed_t *recv_subscribed)
+int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
+ pmc_node_recv_subscribed_t *recv_subscribed)
{
node->pmc = pmc_create(cfg, TRANS_UDS, uds, 0,
config_get_int(cfg, NULL, "domainNumber"),
@@ -1054,7 +1052,7 @@ static int run_pmc_wait_sync(struct pmc_node *node, int timeout)
}
}
-static int run_pmc_get_utc_offset(struct pmc_node *node, int timeout)
+int run_pmc_get_utc_offset(struct pmc_node *node, int timeout)
{
struct ptp_message *msg;
int res;
@@ -1084,7 +1082,7 @@ static int run_pmc_get_utc_offset(struct pmc_node *node, int timeout)
return 1;
}
-static int run_pmc_get_number_ports(struct pmc_node *node, int timeout)
+int run_pmc_get_number_ports(struct pmc_node *node, int timeout)
{
struct ptp_message *msg;
int res;
@@ -1100,7 +1098,7 @@ static int run_pmc_get_number_ports(struct pmc_node *node, int timeout)
return res;
}
-static int run_pmc_subscribe(struct pmc_node *node, int timeout)
+int run_pmc_subscribe(struct pmc_node *node, int timeout)
{
struct ptp_message *msg;
int res;
@@ -1112,16 +1110,16 @@ static int run_pmc_subscribe(struct pmc_node *node, int timeout)
return 1;
}
-static void run_pmc_events(struct pmc_node *node)
+void run_pmc_events(struct pmc_node *node)
{
struct ptp_message *msg;
run_pmc(node, 0, -1, &msg);
}
-static int run_pmc_port_properties(struct pmc_node *node, int timeout,
- unsigned int port, int *state,
- int *tstamping, char *iface)
+int run_pmc_port_properties(struct pmc_node *node, int timeout,
+ unsigned int port, int *state,
+ int *tstamping, char *iface)
{
struct ptp_message *msg;
int res, len;
@@ -1174,7 +1172,7 @@ static int run_pmc_clock_identity(struct pmc_node *node, int timeout)
return 1;
}
-static void close_pmc_node(struct pmc_node *node)
+void close_pmc_node(struct pmc_node *node)
{
if (!node->pmc)
return;
@@ -1262,7 +1260,7 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
}
/* Returns: -1 in case of error, 0 otherwise */
-static int update_pmc_node(struct pmc_node *node, int subscribe)
+int update_pmc_node(struct pmc_node *node, int subscribe)
{
struct timespec tp;
uint64_t ts;
--
2.25.1

View File

@ -0,0 +1,841 @@
From ba9c2ea0e1f7a96093bca1147d4745a7d0ce17b6 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 14:34:19 -0300
Subject: [PATCH 13/47] phc2sys: break out pmc code into pmc_common.c
The code through which phc2sys sends various PTP management messages to
ptp4l via pmc can be reused.
This patch is a trivial movement of that code to a separate translation
module, outside of phc2sys. This makes it available to other programs
that want to subscribe to port state change events too, such as ts2phc.
Signed-off-by: Vladimir Oltean <olteanv@gmail.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
[commit abc75482332752b630b023178ccdf636f5fe7de7 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 354 ---------------------------------------------------
pmc_common.c | 337 ++++++++++++++++++++++++++++++++++++++++++++++++
pmc_common.h | 35 +++++
3 files changed, 372 insertions(+), 354 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index d5b8e71..9184db6 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -63,12 +63,6 @@
#define NS_PER_SEC 1000000000LL
#define PHC_PPS_OFFSET_LIMIT 10000000
-#define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC)
-#define PMC_SUBSCRIBE_DURATION 180 /* 3 minutes */
-/* Note that PMC_SUBSCRIBE_DURATION has to be longer than
- * PMC_UPDATE_INTERVAL otherwise subscription will time out before it is
- * renewed.
- */
struct clock {
LIST_ENTRY(clock) list;
@@ -100,24 +94,6 @@ struct port {
struct clock *clock;
};
-struct pmc_node;
-
-typedef int pmc_node_recv_subscribed_t(struct pmc_node *node,
- struct ptp_message *msg,
- int excluded);
-
-struct pmc_node {
- struct pmc *pmc;
- int pmc_ds_requested;
- uint64_t pmc_last_update;
- int sync_offset;
- int leap;
- int utc_offset_traceable;
- int clock_identity_set;
- struct ClockIdentity clock_identity;
- pmc_node_recv_subscribed_t *recv_subscribed;
-};
-
struct phc2sys_private {
unsigned int stats_max_count;
int sanity_freq_limit;
@@ -137,17 +113,11 @@ struct phc2sys_private {
static struct config *phc2sys_config;
-int update_pmc_node(struct pmc_node *node, int subscribe);
static int clock_handle_leap(struct phc2sys_private *priv,
struct clock *clock,
int64_t offset, uint64_t ts);
-int run_pmc_get_utc_offset(struct pmc_node *node, int timeout);
-void run_pmc_events(struct pmc_node *node);
static int normalize_state(int state);
-int run_pmc_port_properties(struct pmc_node *node, int timeout,
- unsigned int port, int *state,
- int *tstamping, char *iface);
static struct servo *servo_add(struct phc2sys_private *priv,
struct clock *clock)
@@ -811,52 +781,6 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
return 0;
}
-static int check_clock_identity(struct pmc_node *node, struct ptp_message *msg)
-{
- if (!node->clock_identity_set)
- return 1;
- return cid_eq(&node->clock_identity,
- &msg->header.sourcePortIdentity.clockIdentity);
-}
-
-static int is_msg_mgt(struct ptp_message *msg)
-{
- struct TLV *tlv;
-
- if (msg_type(msg) != MANAGEMENT)
- return 0;
- if (management_action(msg) != RESPONSE)
- return 0;
- if (msg_tlv_count(msg) != 1)
- return 0;
- tlv = (struct TLV *) msg->management.suffix;
- if (tlv->type == TLV_MANAGEMENT)
- return 1;
- if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS)
- return -1;
- return 0;
-}
-
-int get_mgt_id(struct ptp_message *msg)
-{
- struct management_tlv *mgt = (struct management_tlv *) msg->management.suffix;
- return mgt->id;
-}
-
-void *get_mgt_data(struct ptp_message *msg)
-{
- struct management_tlv *mgt = (struct management_tlv *) msg->management.suffix;
- return mgt->data;
-}
-
-static int get_mgt_err_id(struct ptp_message *msg)
-{
- struct management_error_status *mgt;
-
- mgt = (struct management_error_status *)msg->management.suffix;
- return mgt->id;
-}
-
static int normalize_state(int state)
{
if (state != PS_MASTER && state != PS_SLAVE &&
@@ -927,260 +851,6 @@ static int phc2sys_recv_subscribed(struct pmc_node *node,
return 0;
}
-static void send_subscription(struct pmc_node *node)
-{
- struct subscribe_events_np sen;
-
- memset(&sen, 0, sizeof(sen));
- sen.duration = PMC_SUBSCRIBE_DURATION;
- sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
- pmc_send_set_action(node->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
-}
-
-int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
- pmc_node_recv_subscribed_t *recv_subscribed)
-{
- node->pmc = pmc_create(cfg, TRANS_UDS, uds, 0,
- config_get_int(cfg, NULL, "domainNumber"),
- config_get_int(cfg, NULL, "transportSpecific") << 4, 1);
- if (!node->pmc) {
- pr_err("failed to create pmc");
- return -1;
- }
- node->recv_subscribed = recv_subscribed;
-
- return 0;
-}
-
-/* Return values:
- * 1: success
- * 0: timeout
- * -1: error reported by the other side
- * -2: local error, fatal
- */
-static int run_pmc(struct pmc_node *node, int timeout, int ds_id,
- struct ptp_message **msg)
-{
-#define N_FD 1
- struct pollfd pollfd[N_FD];
- int cnt, res;
-
- while (1) {
- pollfd[0].fd = pmc_get_transport_fd(node->pmc);
- pollfd[0].events = POLLIN|POLLPRI;
- if (!node->pmc_ds_requested && ds_id >= 0)
- pollfd[0].events |= POLLOUT;
-
- cnt = poll(pollfd, N_FD, timeout);
- if (cnt < 0) {
- pr_err("poll failed");
- return -2;
- }
- if (!cnt) {
- /* Request the data set again in the next run. */
- node->pmc_ds_requested = 0;
- return 0;
- }
-
- /* Send a new request if there are no pending messages. */
- if ((pollfd[0].revents & POLLOUT) &&
- !(pollfd[0].revents & (POLLIN|POLLPRI))) {
- switch (ds_id) {
- case TLV_SUBSCRIBE_EVENTS_NP:
- send_subscription(node);
- break;
- default:
- pmc_send_get_action(node->pmc, ds_id);
- break;
- }
- node->pmc_ds_requested = 1;
- }
-
- if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
- continue;
-
- *msg = pmc_recv(node->pmc);
-
- if (!*msg)
- continue;
-
- if (!check_clock_identity(node, *msg)) {
- msg_put(*msg);
- *msg = NULL;
- continue;
- }
-
- res = is_msg_mgt(*msg);
- if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
- node->pmc_ds_requested = 0;
- return -1;
- }
- if (res <= 0 || node->recv_subscribed(node, *msg, ds_id) ||
- get_mgt_id(*msg) != ds_id) {
- msg_put(*msg);
- *msg = NULL;
- continue;
- }
- node->pmc_ds_requested = 0;
- return 1;
- }
-}
-
-static int run_pmc_wait_sync(struct pmc_node *node, int timeout)
-{
- struct ptp_message *msg;
- Enumeration8 portState;
- void *data;
- int res;
-
- while (1) {
- res = run_pmc(node, timeout, TLV_PORT_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- data = get_mgt_data(msg);
- portState = ((struct portDS *)data)->portState;
- msg_put(msg);
-
- switch (portState) {
- case PS_MASTER:
- case PS_SLAVE:
- return 1;
- }
- /* try to get more data sets (for other ports) */
- node->pmc_ds_requested = 1;
- }
-}
-
-int run_pmc_get_utc_offset(struct pmc_node *node, int timeout)
-{
- struct ptp_message *msg;
- int res;
- struct timePropertiesDS *tds;
-
- res = run_pmc(node, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- tds = (struct timePropertiesDS *)get_mgt_data(msg);
- if (tds->flags & PTP_TIMESCALE) {
- node->sync_offset = tds->currentUtcOffset;
- if (tds->flags & LEAP_61)
- node->leap = 1;
- else if (tds->flags & LEAP_59)
- node->leap = -1;
- else
- node->leap = 0;
- node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
- tds->flags & TIME_TRACEABLE;
- } else {
- node->sync_offset = 0;
- node->leap = 0;
- node->utc_offset_traceable = 0;
- }
- msg_put(msg);
- return 1;
-}
-
-int run_pmc_get_number_ports(struct pmc_node *node, int timeout)
-{
- struct ptp_message *msg;
- int res;
- struct defaultDS *dds;
-
- res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- dds = (struct defaultDS *)get_mgt_data(msg);
- res = dds->numberPorts;
- msg_put(msg);
- return res;
-}
-
-int run_pmc_subscribe(struct pmc_node *node, int timeout)
-{
- struct ptp_message *msg;
- int res;
-
- res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
- if (res <= 0)
- return res;
- msg_put(msg);
- return 1;
-}
-
-void run_pmc_events(struct pmc_node *node)
-{
- struct ptp_message *msg;
-
- run_pmc(node, 0, -1, &msg);
-}
-
-int run_pmc_port_properties(struct pmc_node *node, int timeout,
- unsigned int port, int *state,
- int *tstamping, char *iface)
-{
- struct ptp_message *msg;
- int res, len;
- struct port_properties_np *ppn;
-
- pmc_target_port(node->pmc, port);
- while (1) {
- res = run_pmc(node, timeout, TLV_PORT_PROPERTIES_NP, &msg);
- if (res <= 0)
- goto out;
-
- ppn = get_mgt_data(msg);
- if (ppn->portIdentity.portNumber != port) {
- msg_put(msg);
- continue;
- }
-
- *state = ppn->port_state;
- *tstamping = ppn->timestamping;
- len = ppn->interface.length;
- if (len > IFNAMSIZ - 1)
- len = IFNAMSIZ - 1;
- memcpy(iface, ppn->interface.text, len);
- iface[len] = '\0';
-
- msg_put(msg);
- res = 1;
- break;
- }
-out:
- pmc_target_all(node->pmc);
- return res;
-}
-
-static int run_pmc_clock_identity(struct pmc_node *node, int timeout)
-{
- struct ptp_message *msg;
- struct defaultDS *dds;
- int res;
-
- res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- dds = (struct defaultDS *)get_mgt_data(msg);
- memcpy(&node->clock_identity, &dds->clockIdentity,
- sizeof(struct ClockIdentity));
- node->clock_identity_set = 1;
- msg_put(msg);
- return 1;
-}
-
-void close_pmc_node(struct pmc_node *node)
-{
- if (!node->pmc)
- return;
-
- pmc_destroy(node->pmc);
- node->pmc = NULL;
-}
-
static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
{
struct port *port;
@@ -1259,30 +929,6 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
return 0;
}
-/* Returns: -1 in case of error, 0 otherwise */
-int update_pmc_node(struct pmc_node *node, int subscribe)
-{
- struct timespec tp;
- uint64_t ts;
-
- if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
- pr_err("failed to read clock: %m");
- return -1;
- }
- ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
-
- if (node->pmc &&
- !(ts > node->pmc_last_update &&
- ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
- if (subscribe)
- run_pmc_subscribe(node, 0);
- if (run_pmc_get_utc_offset(node, 0) > 0)
- node->pmc_last_update = ts;
- }
-
- return 0;
-}
-
/* Returns: non-zero to skip clock update */
static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
int64_t offset, uint64_t ts)
diff --git a/pmc_common.c b/pmc_common.c
index f07f6f6..c9cdf18 100644
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -18,6 +18,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
+#include <net/if.h>
+#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@@ -56,6 +58,13 @@
/* Includes one extra byte to make length even. */
#define EMPTY_PTP_TEXT 2
+#define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC)
+#define PMC_SUBSCRIBE_DURATION 180 /* 3 minutes */
+/* Note that PMC_SUBSCRIBE_DURATION has to be longer than
+ * PMC_UPDATE_INTERVAL otherwise subscription will time out before it is
+ * renewed.
+ */
+
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);
@@ -711,3 +720,331 @@ int pmc_do_command(struct pmc *pmc, char *str)
return 0;
}
+
+static void send_subscription(struct pmc_node *node)
+{
+ struct subscribe_events_np sen;
+
+ memset(&sen, 0, sizeof(sen));
+ sen.duration = PMC_SUBSCRIBE_DURATION;
+ sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
+ pmc_send_set_action(node->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
+}
+
+static int check_clock_identity(struct pmc_node *node, struct ptp_message *msg)
+{
+ if (!node->clock_identity_set)
+ return 1;
+ return cid_eq(&node->clock_identity,
+ &msg->header.sourcePortIdentity.clockIdentity);
+}
+
+static int is_msg_mgt(struct ptp_message *msg)
+{
+ struct TLV *tlv;
+
+ if (msg_type(msg) != MANAGEMENT)
+ return 0;
+ if (management_action(msg) != RESPONSE)
+ return 0;
+ if (msg_tlv_count(msg) != 1)
+ return 0;
+ tlv = (struct TLV *) msg->management.suffix;
+ if (tlv->type == TLV_MANAGEMENT)
+ return 1;
+ if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS)
+ return -1;
+ return 0;
+}
+
+int get_mgt_id(struct ptp_message *msg)
+{
+ struct management_tlv *mgt;
+
+ mgt = (struct management_tlv *) msg->management.suffix;
+ return mgt->id;
+}
+
+void *get_mgt_data(struct ptp_message *msg)
+{
+ struct management_tlv *mgt;
+
+ mgt = (struct management_tlv *) msg->management.suffix;
+ return mgt->data;
+}
+
+static int get_mgt_err_id(struct ptp_message *msg)
+{
+ struct management_error_status *mgt;
+
+ mgt = (struct management_error_status *)msg->management.suffix;
+ return mgt->id;
+}
+
+/* Return values:
+ * 1: success
+ * 0: timeout
+ * -1: error reported by the other side
+ * -2: local error, fatal
+ */
+static int run_pmc(struct pmc_node *node, int timeout, int ds_id,
+ struct ptp_message **msg)
+{
+#define N_FD 1
+ struct pollfd pollfd[N_FD];
+ int cnt, res;
+
+ while (1) {
+ pollfd[0].fd = pmc_get_transport_fd(node->pmc);
+ pollfd[0].events = POLLIN|POLLPRI;
+ if (!node->pmc_ds_requested && ds_id >= 0)
+ pollfd[0].events |= POLLOUT;
+
+ cnt = poll(pollfd, N_FD, timeout);
+ if (cnt < 0) {
+ pr_err("poll failed");
+ return -2;
+ }
+ if (!cnt) {
+ /* Request the data set again in the next run. */
+ node->pmc_ds_requested = 0;
+ return 0;
+ }
+
+ /* Send a new request if there are no pending messages. */
+ if ((pollfd[0].revents & POLLOUT) &&
+ !(pollfd[0].revents & (POLLIN|POLLPRI))) {
+ switch (ds_id) {
+ case TLV_SUBSCRIBE_EVENTS_NP:
+ send_subscription(node);
+ break;
+ default:
+ pmc_send_get_action(node->pmc, ds_id);
+ break;
+ }
+ node->pmc_ds_requested = 1;
+ }
+
+ if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
+ continue;
+
+ *msg = pmc_recv(node->pmc);
+
+ if (!*msg)
+ continue;
+
+ if (!check_clock_identity(node, *msg)) {
+ msg_put(*msg);
+ *msg = NULL;
+ continue;
+ }
+
+ res = is_msg_mgt(*msg);
+ if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
+ node->pmc_ds_requested = 0;
+ return -1;
+ }
+ if (res <= 0 || node->recv_subscribed(node, *msg, ds_id) ||
+ get_mgt_id(*msg) != ds_id) {
+ msg_put(*msg);
+ *msg = NULL;
+ continue;
+ }
+ node->pmc_ds_requested = 0;
+ return 1;
+ }
+}
+
+int run_pmc_wait_sync(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ Enumeration8 portState;
+ void *data;
+ int res;
+
+ while (1) {
+ res = run_pmc(node, timeout, TLV_PORT_DATA_SET, &msg);
+ if (res <= 0)
+ return res;
+
+ data = get_mgt_data(msg);
+ portState = ((struct portDS *)data)->portState;
+ msg_put(msg);
+
+ switch (portState) {
+ case PS_MASTER:
+ case PS_SLAVE:
+ return 1;
+ }
+ /* try to get more data sets (for other ports) */
+ node->pmc_ds_requested = 1;
+ }
+}
+
+int run_pmc_get_utc_offset(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ int res;
+ struct timePropertiesDS *tds;
+
+ res = run_pmc(node, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
+ if (res <= 0)
+ return res;
+
+ tds = (struct timePropertiesDS *)get_mgt_data(msg);
+ if (tds->flags & PTP_TIMESCALE) {
+ node->sync_offset = tds->currentUtcOffset;
+ if (tds->flags & LEAP_61)
+ node->leap = 1;
+ else if (tds->flags & LEAP_59)
+ node->leap = -1;
+ else
+ node->leap = 0;
+ node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
+ tds->flags & TIME_TRACEABLE;
+ } else {
+ node->sync_offset = 0;
+ node->leap = 0;
+ node->utc_offset_traceable = 0;
+ }
+ msg_put(msg);
+ return 1;
+}
+
+int run_pmc_get_number_ports(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ int res;
+ struct defaultDS *dds;
+
+ res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
+ if (res <= 0)
+ return res;
+
+ dds = (struct defaultDS *)get_mgt_data(msg);
+ res = dds->numberPorts;
+ msg_put(msg);
+ return res;
+}
+
+int run_pmc_subscribe(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ int res;
+
+ res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
+ if (res <= 0)
+ return res;
+ msg_put(msg);
+ return 1;
+}
+
+void run_pmc_events(struct pmc_node *node)
+{
+ struct ptp_message *msg;
+
+ run_pmc(node, 0, -1, &msg);
+}
+
+int run_pmc_port_properties(struct pmc_node *node, int timeout,
+ unsigned int port, int *state,
+ int *tstamping, char *iface)
+{
+ struct ptp_message *msg;
+ int res, len;
+ struct port_properties_np *ppn;
+
+ pmc_target_port(node->pmc, port);
+ while (1) {
+ res = run_pmc(node, timeout, TLV_PORT_PROPERTIES_NP, &msg);
+ if (res <= 0)
+ goto out;
+
+ ppn = get_mgt_data(msg);
+ if (ppn->portIdentity.portNumber != port) {
+ msg_put(msg);
+ continue;
+ }
+
+ *state = ppn->port_state;
+ *tstamping = ppn->timestamping;
+ len = ppn->interface.length;
+ if (len > IFNAMSIZ - 1)
+ len = IFNAMSIZ - 1;
+ memcpy(iface, ppn->interface.text, len);
+ iface[len] = '\0';
+
+ msg_put(msg);
+ res = 1;
+ break;
+ }
+out:
+ pmc_target_all(node->pmc);
+ return res;
+}
+
+int run_pmc_clock_identity(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ struct defaultDS *dds;
+ int res;
+
+ res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
+ if (res <= 0)
+ return res;
+
+ dds = (struct defaultDS *)get_mgt_data(msg);
+ memcpy(&node->clock_identity, &dds->clockIdentity,
+ sizeof(struct ClockIdentity));
+ node->clock_identity_set = 1;
+ msg_put(msg);
+ return 1;
+}
+
+/* Returns: -1 in case of error, 0 otherwise */
+int update_pmc_node(struct pmc_node *node, int subscribe)
+{
+ struct timespec tp;
+ uint64_t ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
+ pr_err("failed to read clock: %m");
+ return -1;
+ }
+ ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
+
+ if (node->pmc &&
+ !(ts > node->pmc_last_update &&
+ ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
+ if (subscribe)
+ run_pmc_subscribe(node, 0);
+ if (run_pmc_get_utc_offset(node, 0) > 0)
+ node->pmc_last_update = ts;
+ }
+
+ return 0;
+}
+
+int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
+ pmc_node_recv_subscribed_t *recv_subscribed)
+{
+ node->pmc = pmc_create(cfg, TRANS_UDS, uds, 0,
+ config_get_int(cfg, NULL, "domainNumber"),
+ config_get_int(cfg, NULL, "transportSpecific") << 4, 1);
+ if (!node->pmc) {
+ pr_err("failed to create pmc");
+ return -1;
+ }
+ node->recv_subscribed = recv_subscribed;
+
+ return 0;
+}
+
+void close_pmc_node(struct pmc_node *node)
+{
+ if (!node->pmc)
+ return;
+
+ pmc_destroy(node->pmc);
+ node->pmc = NULL;
+}
diff --git a/pmc_common.h b/pmc_common.h
index 9fa72de..476ccea 100644
--- a/pmc_common.h
+++ b/pmc_common.h
@@ -22,6 +22,7 @@
#define HAVE_PMC_COMMON_H
#include "config.h"
+#include "fsm.h"
#include "msg.h"
#include "transport.h"
@@ -49,4 +50,38 @@ void pmc_target_all(struct pmc *pmc);
const char *pmc_action_string(int action);
int pmc_do_command(struct pmc *pmc, char *str);
+struct pmc_node;
+
+typedef int pmc_node_recv_subscribed_t(struct pmc_node *node,
+ struct ptp_message *msg,
+ int excluded);
+
+struct pmc_node {
+ struct pmc *pmc;
+ int pmc_ds_requested;
+ uint64_t pmc_last_update;
+ int sync_offset;
+ int leap;
+ int utc_offset_traceable;
+ int clock_identity_set;
+ struct ClockIdentity clock_identity;
+ pmc_node_recv_subscribed_t *recv_subscribed;
+};
+
+int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
+ pmc_node_recv_subscribed_t *recv_subscribed);
+void close_pmc_node(struct pmc_node *node);
+int update_pmc_node(struct pmc_node *node, int subscribe);
+int run_pmc_subscribe(struct pmc_node *node, int timeout);
+int run_pmc_clock_identity(struct pmc_node *node, int timeout);
+int run_pmc_wait_sync(struct pmc_node *node, int timeout);
+int run_pmc_get_number_ports(struct pmc_node *node, int timeout);
+void run_pmc_events(struct pmc_node *node);
+int run_pmc_port_properties(struct pmc_node *node, int timeout,
+ unsigned int port, int *state,
+ int *tstamping, char *iface);
+int run_pmc_get_utc_offset(struct pmc_node *node, int timeout);
+int get_mgt_id(struct ptp_message *msg);
+void *get_mgt_data(struct ptp_message *msg);
+
#endif
--
2.25.1

View File

@ -0,0 +1,913 @@
From c00e75286b2ad882cf8e89549ea58e438c877f95 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 14:40:59 -0300
Subject: [PATCH 14/47] Introduce the PMC agent module.
The logic for placing PTP management queries migrated out of phc2sys into
pmc_common in order to be shared with other programs in the future. This
logic uses pmc_common rather than extending it, and so it should live in
its own module stacked on top of pmc_common.
This patch moves the code into its own file verbatim without making any
other changes.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
[commit f266740e1a8aacc03f97205ae14fc43c59081433 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
makefile | 6 +-
phc2sys.c | 2 +-
pmc_agent.c | 361 +++++++++++++++++++++++++++++++++++++++++++++++++++
pmc_agent.h | 62 +++++++++
pmc_common.c | 338 -----------------------------------------------
pmc_common.h | 34 -----
6 files changed, 427 insertions(+), 376 deletions(-)
create mode 100644 pmc_agent.c
create mode 100644 pmc_agent.h
diff --git a/makefile b/makefile
index 27c4d78..33e7ca0 100644
--- a/makefile
+++ b/makefile
@@ -34,8 +34,8 @@ OBJ = bmc.o clock.o clockadj.o clockcheck.o config.o designated_fsm.o \
sk.o stats.o tc.o $(TRANSP) telecom.o tlv.o tsproc.o unicast_client.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_common.o \
- sysoff.o timemaster.o $(TS2PHC)
+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)
SRC = $(OBJECTS:.o=.c)
DEPEND = $(OBJECTS:.o=.d)
srcdir := $(dir $(lastword $(MAKEFILE_LIST)))
@@ -59,7 +59,7 @@ pmc: config.o hash.o interface.o msg.o phc.o pmc.o pmc_common.o print.o sk.o \
tlv.o $(TRANSP) util.o version.o
phc2sys: clockadj.o clockcheck.o config.o hash.o interface.o msg.o \
- phc.o phc2sys.o pmc_common.o print.o $(SERVOS) sk.o stats.o \
+ phc.o phc2sys.o pmc_agent.o pmc_common.o print.o $(SERVOS) sk.o stats.o \
sysoff.o tlv.o $(TRANSP) util.o version.o
hwstamp_ctl: hwstamp_ctl.o version.o
diff --git a/phc2sys.c b/phc2sys.c
index 9184db6..648ba61 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -47,7 +47,7 @@
#include "ntpshm.h"
#include "phc.h"
#include "pi.h"
-#include "pmc_common.h"
+#include "pmc_agent.h"
#include "print.h"
#include "servo.h"
#include "sk.h"
diff --git a/pmc_agent.c b/pmc_agent.c
new file mode 100644
index 0000000..774e94d
--- /dev/null
+++ b/pmc_agent.c
@@ -0,0 +1,361 @@
+/**
+ * @file pmc_agent.c
+ * @note Copyright (C) 2012 Richard Cochran <richardcochran@gmail.com>
+ * @note Copyright (C) 2013 Miroslav Lichvar <mlichvar@redhat.com>
+ *
+ * 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.
+ */
+#include <net/if.h>
+#include <poll.h>
+
+#include "notification.h"
+#include "pmc_agent.h"
+#include "print.h"
+#include "util.h"
+
+#define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC)
+#define PMC_SUBSCRIBE_DURATION 180 /* 3 minutes */
+/* Note that PMC_SUBSCRIBE_DURATION has to be longer than
+ * PMC_UPDATE_INTERVAL otherwise subscription will time out before it is
+ * renewed.
+ */
+
+static void send_subscription(struct pmc_node *node)
+{
+ struct subscribe_events_np sen;
+
+ memset(&sen, 0, sizeof(sen));
+ sen.duration = PMC_SUBSCRIBE_DURATION;
+ sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
+ pmc_send_set_action(node->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
+}
+
+static int check_clock_identity(struct pmc_node *node, struct ptp_message *msg)
+{
+ if (!node->clock_identity_set)
+ return 1;
+ return cid_eq(&node->clock_identity,
+ &msg->header.sourcePortIdentity.clockIdentity);
+}
+
+static int is_msg_mgt(struct ptp_message *msg)
+{
+ struct TLV *tlv;
+
+ if (msg_type(msg) != MANAGEMENT)
+ return 0;
+ if (management_action(msg) != RESPONSE)
+ return 0;
+ if (msg_tlv_count(msg) != 1)
+ return 0;
+ tlv = (struct TLV *) msg->management.suffix;
+ if (tlv->type == TLV_MANAGEMENT)
+ return 1;
+ if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS)
+ return -1;
+ return 0;
+}
+
+int get_mgt_id(struct ptp_message *msg)
+{
+ struct management_tlv *mgt;
+
+ mgt = (struct management_tlv *) msg->management.suffix;
+ return mgt->id;
+}
+
+void *get_mgt_data(struct ptp_message *msg)
+{
+ struct management_tlv *mgt;
+
+ mgt = (struct management_tlv *) msg->management.suffix;
+ return mgt->data;
+}
+
+static int get_mgt_err_id(struct ptp_message *msg)
+{
+ struct management_error_status *mgt;
+
+ mgt = (struct management_error_status *)msg->management.suffix;
+ return mgt->id;
+}
+
+/* Return values:
+ * 1: success
+ * 0: timeout
+ * -1: error reported by the other side
+ * -2: local error, fatal
+ */
+static int run_pmc(struct pmc_node *node, int timeout, int ds_id,
+ struct ptp_message **msg)
+{
+#define N_FD 1
+ struct pollfd pollfd[N_FD];
+ int cnt, res;
+
+ while (1) {
+ pollfd[0].fd = pmc_get_transport_fd(node->pmc);
+ pollfd[0].events = POLLIN|POLLPRI;
+ if (!node->pmc_ds_requested && ds_id >= 0)
+ pollfd[0].events |= POLLOUT;
+
+ cnt = poll(pollfd, N_FD, timeout);
+ if (cnt < 0) {
+ pr_err("poll failed");
+ return -2;
+ }
+ if (!cnt) {
+ /* Request the data set again in the next run. */
+ node->pmc_ds_requested = 0;
+ return 0;
+ }
+
+ /* Send a new request if there are no pending messages. */
+ if ((pollfd[0].revents & POLLOUT) &&
+ !(pollfd[0].revents & (POLLIN|POLLPRI))) {
+ switch (ds_id) {
+ case TLV_SUBSCRIBE_EVENTS_NP:
+ send_subscription(node);
+ break;
+ default:
+ pmc_send_get_action(node->pmc, ds_id);
+ break;
+ }
+ node->pmc_ds_requested = 1;
+ }
+
+ if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
+ continue;
+
+ *msg = pmc_recv(node->pmc);
+
+ if (!*msg)
+ continue;
+
+ if (!check_clock_identity(node, *msg)) {
+ msg_put(*msg);
+ *msg = NULL;
+ continue;
+ }
+
+ res = is_msg_mgt(*msg);
+ if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
+ node->pmc_ds_requested = 0;
+ return -1;
+ }
+ if (res <= 0 || node->recv_subscribed(node, *msg, ds_id) ||
+ get_mgt_id(*msg) != ds_id) {
+ msg_put(*msg);
+ *msg = NULL;
+ continue;
+ }
+ node->pmc_ds_requested = 0;
+ return 1;
+ }
+}
+
+int run_pmc_wait_sync(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ Enumeration8 portState;
+ void *data;
+ int res;
+
+ while (1) {
+ res = run_pmc(node, timeout, TLV_PORT_DATA_SET, &msg);
+ if (res <= 0)
+ return res;
+
+ data = get_mgt_data(msg);
+ portState = ((struct portDS *)data)->portState;
+ msg_put(msg);
+
+ switch (portState) {
+ case PS_MASTER:
+ case PS_SLAVE:
+ return 1;
+ }
+ /* try to get more data sets (for other ports) */
+ node->pmc_ds_requested = 1;
+ }
+}
+
+int run_pmc_get_utc_offset(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ int res;
+ struct timePropertiesDS *tds;
+
+ res = run_pmc(node, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
+ if (res <= 0)
+ return res;
+
+ tds = (struct timePropertiesDS *)get_mgt_data(msg);
+ if (tds->flags & PTP_TIMESCALE) {
+ node->sync_offset = tds->currentUtcOffset;
+ if (tds->flags & LEAP_61)
+ node->leap = 1;
+ else if (tds->flags & LEAP_59)
+ node->leap = -1;
+ else
+ node->leap = 0;
+ node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
+ tds->flags & TIME_TRACEABLE;
+ } else {
+ node->sync_offset = 0;
+ node->leap = 0;
+ node->utc_offset_traceable = 0;
+ }
+ msg_put(msg);
+ return 1;
+}
+
+int run_pmc_get_number_ports(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ int res;
+ struct defaultDS *dds;
+
+ res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
+ if (res <= 0)
+ return res;
+
+ dds = (struct defaultDS *)get_mgt_data(msg);
+ res = dds->numberPorts;
+ msg_put(msg);
+ return res;
+}
+
+int run_pmc_subscribe(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ int res;
+
+ res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
+ if (res <= 0)
+ return res;
+ msg_put(msg);
+ return 1;
+}
+
+void run_pmc_events(struct pmc_node *node)
+{
+ struct ptp_message *msg;
+
+ run_pmc(node, 0, -1, &msg);
+}
+
+int run_pmc_port_properties(struct pmc_node *node, int timeout,
+ unsigned int port, int *state,
+ int *tstamping, char *iface)
+{
+ struct ptp_message *msg;
+ int res, len;
+ struct port_properties_np *ppn;
+
+ pmc_target_port(node->pmc, port);
+ while (1) {
+ res = run_pmc(node, timeout, TLV_PORT_PROPERTIES_NP, &msg);
+ if (res <= 0)
+ goto out;
+
+ ppn = get_mgt_data(msg);
+ if (ppn->portIdentity.portNumber != port) {
+ msg_put(msg);
+ continue;
+ }
+
+ *state = ppn->port_state;
+ *tstamping = ppn->timestamping;
+ len = ppn->interface.length;
+ if (len > IFNAMSIZ - 1)
+ len = IFNAMSIZ - 1;
+ memcpy(iface, ppn->interface.text, len);
+ iface[len] = '\0';
+
+ msg_put(msg);
+ res = 1;
+ break;
+ }
+out:
+ pmc_target_all(node->pmc);
+ return res;
+}
+
+int run_pmc_clock_identity(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ struct defaultDS *dds;
+ int res;
+
+ res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
+ if (res <= 0)
+ return res;
+
+ dds = (struct defaultDS *)get_mgt_data(msg);
+ memcpy(&node->clock_identity, &dds->clockIdentity,
+ sizeof(struct ClockIdentity));
+ node->clock_identity_set = 1;
+ msg_put(msg);
+ return 1;
+}
+
+/* Returns: -1 in case of error, 0 otherwise */
+int update_pmc_node(struct pmc_node *node, int subscribe)
+{
+ struct timespec tp;
+ uint64_t ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
+ pr_err("failed to read clock: %m");
+ return -1;
+ }
+ ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
+
+ if (node->pmc &&
+ !(ts > node->pmc_last_update &&
+ ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
+ if (subscribe)
+ run_pmc_subscribe(node, 0);
+ if (run_pmc_get_utc_offset(node, 0) > 0)
+ node->pmc_last_update = ts;
+ }
+
+ return 0;
+}
+
+int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
+ pmc_node_recv_subscribed_t *recv_subscribed)
+{
+ node->pmc = pmc_create(cfg, TRANS_UDS, uds, 0,
+ config_get_int(cfg, NULL, "domainNumber"),
+ config_get_int(cfg, NULL, "transportSpecific") << 4, 1);
+ if (!node->pmc) {
+ pr_err("failed to create pmc");
+ return -1;
+ }
+ node->recv_subscribed = recv_subscribed;
+
+ return 0;
+}
+
+void close_pmc_node(struct pmc_node *node)
+{
+ if (!node->pmc)
+ return;
+
+ pmc_destroy(node->pmc);
+ node->pmc = NULL;
+}
diff --git a/pmc_agent.h b/pmc_agent.h
new file mode 100644
index 0000000..90245b1
--- /dev/null
+++ b/pmc_agent.h
@@ -0,0 +1,62 @@
+/**
+ * @file pmc_agent.h
+ * @brief Client code for making PTP management requests.
+ * @note Copyright (C) 2013 Miroslav Lichvar <mlichvar@redhat.com>
+ * @note Copyright (C) 2020 Richard Cochran <richardcochran@gmail.com>
+ *
+ * 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_PMC_AGENT_H
+#define HAVE_PMC_AGENT_H
+
+#include "pmc_common.h"
+
+struct pmc_node;
+
+typedef int pmc_node_recv_subscribed_t(struct pmc_node *node,
+ struct ptp_message *msg,
+ int excluded);
+
+struct pmc_node {
+ struct pmc *pmc;
+ int pmc_ds_requested;
+ uint64_t pmc_last_update;
+ int sync_offset;
+ int leap;
+ int utc_offset_traceable;
+ int clock_identity_set;
+ struct ClockIdentity clock_identity;
+ pmc_node_recv_subscribed_t *recv_subscribed;
+};
+
+int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
+ pmc_node_recv_subscribed_t *recv_subscribed);
+void close_pmc_node(struct pmc_node *node);
+int update_pmc_node(struct pmc_node *node, int subscribe);
+int run_pmc_subscribe(struct pmc_node *node, int timeout);
+int run_pmc_clock_identity(struct pmc_node *node, int timeout);
+int run_pmc_wait_sync(struct pmc_node *node, int timeout);
+int run_pmc_get_number_ports(struct pmc_node *node, int timeout);
+void run_pmc_events(struct pmc_node *node);
+int run_pmc_port_properties(struct pmc_node *node, int timeout,
+ unsigned int port, int *state,
+ int *tstamping, char *iface);
+int run_pmc_get_utc_offset(struct pmc_node *node, int timeout);
+int get_mgt_id(struct ptp_message *msg);
+void *get_mgt_data(struct ptp_message *msg);
+
+#endif
+
diff --git a/pmc_common.c b/pmc_common.c
index c9cdf18..a117904 100644
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -18,8 +18,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
-#include <net/if.h>
-#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@@ -29,7 +27,6 @@
#include "print.h"
#include "tlv.h"
#include "transport.h"
-#include "util.h"
#include "pmc_common.h"
#define BAD_ACTION -1
@@ -58,13 +55,6 @@
/* Includes one extra byte to make length even. */
#define EMPTY_PTP_TEXT 2
-#define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC)
-#define PMC_SUBSCRIBE_DURATION 180 /* 3 minutes */
-/* Note that PMC_SUBSCRIBE_DURATION has to be longer than
- * PMC_UPDATE_INTERVAL otherwise subscription will time out before it is
- * renewed.
- */
-
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);
@@ -720,331 +710,3 @@ int pmc_do_command(struct pmc *pmc, char *str)
return 0;
}
-
-static void send_subscription(struct pmc_node *node)
-{
- struct subscribe_events_np sen;
-
- memset(&sen, 0, sizeof(sen));
- sen.duration = PMC_SUBSCRIBE_DURATION;
- sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
- pmc_send_set_action(node->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
-}
-
-static int check_clock_identity(struct pmc_node *node, struct ptp_message *msg)
-{
- if (!node->clock_identity_set)
- return 1;
- return cid_eq(&node->clock_identity,
- &msg->header.sourcePortIdentity.clockIdentity);
-}
-
-static int is_msg_mgt(struct ptp_message *msg)
-{
- struct TLV *tlv;
-
- if (msg_type(msg) != MANAGEMENT)
- return 0;
- if (management_action(msg) != RESPONSE)
- return 0;
- if (msg_tlv_count(msg) != 1)
- return 0;
- tlv = (struct TLV *) msg->management.suffix;
- if (tlv->type == TLV_MANAGEMENT)
- return 1;
- if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS)
- return -1;
- return 0;
-}
-
-int get_mgt_id(struct ptp_message *msg)
-{
- struct management_tlv *mgt;
-
- mgt = (struct management_tlv *) msg->management.suffix;
- return mgt->id;
-}
-
-void *get_mgt_data(struct ptp_message *msg)
-{
- struct management_tlv *mgt;
-
- mgt = (struct management_tlv *) msg->management.suffix;
- return mgt->data;
-}
-
-static int get_mgt_err_id(struct ptp_message *msg)
-{
- struct management_error_status *mgt;
-
- mgt = (struct management_error_status *)msg->management.suffix;
- return mgt->id;
-}
-
-/* Return values:
- * 1: success
- * 0: timeout
- * -1: error reported by the other side
- * -2: local error, fatal
- */
-static int run_pmc(struct pmc_node *node, int timeout, int ds_id,
- struct ptp_message **msg)
-{
-#define N_FD 1
- struct pollfd pollfd[N_FD];
- int cnt, res;
-
- while (1) {
- pollfd[0].fd = pmc_get_transport_fd(node->pmc);
- pollfd[0].events = POLLIN|POLLPRI;
- if (!node->pmc_ds_requested && ds_id >= 0)
- pollfd[0].events |= POLLOUT;
-
- cnt = poll(pollfd, N_FD, timeout);
- if (cnt < 0) {
- pr_err("poll failed");
- return -2;
- }
- if (!cnt) {
- /* Request the data set again in the next run. */
- node->pmc_ds_requested = 0;
- return 0;
- }
-
- /* Send a new request if there are no pending messages. */
- if ((pollfd[0].revents & POLLOUT) &&
- !(pollfd[0].revents & (POLLIN|POLLPRI))) {
- switch (ds_id) {
- case TLV_SUBSCRIBE_EVENTS_NP:
- send_subscription(node);
- break;
- default:
- pmc_send_get_action(node->pmc, ds_id);
- break;
- }
- node->pmc_ds_requested = 1;
- }
-
- if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
- continue;
-
- *msg = pmc_recv(node->pmc);
-
- if (!*msg)
- continue;
-
- if (!check_clock_identity(node, *msg)) {
- msg_put(*msg);
- *msg = NULL;
- continue;
- }
-
- res = is_msg_mgt(*msg);
- if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
- node->pmc_ds_requested = 0;
- return -1;
- }
- if (res <= 0 || node->recv_subscribed(node, *msg, ds_id) ||
- get_mgt_id(*msg) != ds_id) {
- msg_put(*msg);
- *msg = NULL;
- continue;
- }
- node->pmc_ds_requested = 0;
- return 1;
- }
-}
-
-int run_pmc_wait_sync(struct pmc_node *node, int timeout)
-{
- struct ptp_message *msg;
- Enumeration8 portState;
- void *data;
- int res;
-
- while (1) {
- res = run_pmc(node, timeout, TLV_PORT_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- data = get_mgt_data(msg);
- portState = ((struct portDS *)data)->portState;
- msg_put(msg);
-
- switch (portState) {
- case PS_MASTER:
- case PS_SLAVE:
- return 1;
- }
- /* try to get more data sets (for other ports) */
- node->pmc_ds_requested = 1;
- }
-}
-
-int run_pmc_get_utc_offset(struct pmc_node *node, int timeout)
-{
- struct ptp_message *msg;
- int res;
- struct timePropertiesDS *tds;
-
- res = run_pmc(node, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- tds = (struct timePropertiesDS *)get_mgt_data(msg);
- if (tds->flags & PTP_TIMESCALE) {
- node->sync_offset = tds->currentUtcOffset;
- if (tds->flags & LEAP_61)
- node->leap = 1;
- else if (tds->flags & LEAP_59)
- node->leap = -1;
- else
- node->leap = 0;
- node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
- tds->flags & TIME_TRACEABLE;
- } else {
- node->sync_offset = 0;
- node->leap = 0;
- node->utc_offset_traceable = 0;
- }
- msg_put(msg);
- return 1;
-}
-
-int run_pmc_get_number_ports(struct pmc_node *node, int timeout)
-{
- struct ptp_message *msg;
- int res;
- struct defaultDS *dds;
-
- res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- dds = (struct defaultDS *)get_mgt_data(msg);
- res = dds->numberPorts;
- msg_put(msg);
- return res;
-}
-
-int run_pmc_subscribe(struct pmc_node *node, int timeout)
-{
- struct ptp_message *msg;
- int res;
-
- res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
- if (res <= 0)
- return res;
- msg_put(msg);
- return 1;
-}
-
-void run_pmc_events(struct pmc_node *node)
-{
- struct ptp_message *msg;
-
- run_pmc(node, 0, -1, &msg);
-}
-
-int run_pmc_port_properties(struct pmc_node *node, int timeout,
- unsigned int port, int *state,
- int *tstamping, char *iface)
-{
- struct ptp_message *msg;
- int res, len;
- struct port_properties_np *ppn;
-
- pmc_target_port(node->pmc, port);
- while (1) {
- res = run_pmc(node, timeout, TLV_PORT_PROPERTIES_NP, &msg);
- if (res <= 0)
- goto out;
-
- ppn = get_mgt_data(msg);
- if (ppn->portIdentity.portNumber != port) {
- msg_put(msg);
- continue;
- }
-
- *state = ppn->port_state;
- *tstamping = ppn->timestamping;
- len = ppn->interface.length;
- if (len > IFNAMSIZ - 1)
- len = IFNAMSIZ - 1;
- memcpy(iface, ppn->interface.text, len);
- iface[len] = '\0';
-
- msg_put(msg);
- res = 1;
- break;
- }
-out:
- pmc_target_all(node->pmc);
- return res;
-}
-
-int run_pmc_clock_identity(struct pmc_node *node, int timeout)
-{
- struct ptp_message *msg;
- struct defaultDS *dds;
- int res;
-
- res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- dds = (struct defaultDS *)get_mgt_data(msg);
- memcpy(&node->clock_identity, &dds->clockIdentity,
- sizeof(struct ClockIdentity));
- node->clock_identity_set = 1;
- msg_put(msg);
- return 1;
-}
-
-/* Returns: -1 in case of error, 0 otherwise */
-int update_pmc_node(struct pmc_node *node, int subscribe)
-{
- struct timespec tp;
- uint64_t ts;
-
- if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
- pr_err("failed to read clock: %m");
- return -1;
- }
- ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
-
- if (node->pmc &&
- !(ts > node->pmc_last_update &&
- ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
- if (subscribe)
- run_pmc_subscribe(node, 0);
- if (run_pmc_get_utc_offset(node, 0) > 0)
- node->pmc_last_update = ts;
- }
-
- return 0;
-}
-
-int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
- pmc_node_recv_subscribed_t *recv_subscribed)
-{
- node->pmc = pmc_create(cfg, TRANS_UDS, uds, 0,
- config_get_int(cfg, NULL, "domainNumber"),
- config_get_int(cfg, NULL, "transportSpecific") << 4, 1);
- if (!node->pmc) {
- pr_err("failed to create pmc");
- return -1;
- }
- node->recv_subscribed = recv_subscribed;
-
- return 0;
-}
-
-void close_pmc_node(struct pmc_node *node)
-{
- if (!node->pmc)
- return;
-
- pmc_destroy(node->pmc);
- node->pmc = NULL;
-}
diff --git a/pmc_common.h b/pmc_common.h
index 476ccea..8bea2e0 100644
--- a/pmc_common.h
+++ b/pmc_common.h
@@ -50,38 +50,4 @@ void pmc_target_all(struct pmc *pmc);
const char *pmc_action_string(int action);
int pmc_do_command(struct pmc *pmc, char *str);
-struct pmc_node;
-
-typedef int pmc_node_recv_subscribed_t(struct pmc_node *node,
- struct ptp_message *msg,
- int excluded);
-
-struct pmc_node {
- struct pmc *pmc;
- int pmc_ds_requested;
- uint64_t pmc_last_update;
- int sync_offset;
- int leap;
- int utc_offset_traceable;
- int clock_identity_set;
- struct ClockIdentity clock_identity;
- pmc_node_recv_subscribed_t *recv_subscribed;
-};
-
-int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
- pmc_node_recv_subscribed_t *recv_subscribed);
-void close_pmc_node(struct pmc_node *node);
-int update_pmc_node(struct pmc_node *node, int subscribe);
-int run_pmc_subscribe(struct pmc_node *node, int timeout);
-int run_pmc_clock_identity(struct pmc_node *node, int timeout);
-int run_pmc_wait_sync(struct pmc_node *node, int timeout);
-int run_pmc_get_number_ports(struct pmc_node *node, int timeout);
-void run_pmc_events(struct pmc_node *node);
-int run_pmc_port_properties(struct pmc_node *node, int timeout,
- unsigned int port, int *state,
- int *tstamping, char *iface);
-int run_pmc_get_utc_offset(struct pmc_node *node, int timeout);
-int get_mgt_id(struct ptp_message *msg);
-void *get_mgt_data(struct ptp_message *msg);
-
#endif
--
2.25.1

View File

@ -0,0 +1,212 @@
From 82258917b8de7110545f3d4f99d3ac88a609f019 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 14:47:36 -0300
Subject: [PATCH 15/47] pmc_agent: Rename pmc_node to something more
descriptive.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
[commit bb6865cdf59572fcb09c11d549828269281c6841 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 4 ++--
pmc_agent.c | 26 +++++++++++++-------------
pmc_agent.h | 26 +++++++++++++-------------
3 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 648ba61..74ee9d1 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -103,7 +103,7 @@ struct phc2sys_private {
int forced_sync_offset;
int kernel_leap;
int state_changed;
- struct pmc_node node;
+ struct pmc_agent node;
LIST_HEAD(port_head, port) ports;
LIST_HEAD(clock_head, clock) clocks;
LIST_HEAD(dst_clock_head, clock) dst_clocks;
@@ -813,7 +813,7 @@ static int clock_compute_state(struct phc2sys_private *priv,
#define node_to_phc2sys(node) \
container_of(node, struct phc2sys_private, node)
-static int phc2sys_recv_subscribed(struct pmc_node *node,
+static int phc2sys_recv_subscribed(struct pmc_agent *node,
struct ptp_message *msg, int excluded)
{
struct phc2sys_private *priv = node_to_phc2sys(node);
diff --git a/pmc_agent.c b/pmc_agent.c
index 774e94d..e83895c 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -32,7 +32,7 @@
* renewed.
*/
-static void send_subscription(struct pmc_node *node)
+static void send_subscription(struct pmc_agent *node)
{
struct subscribe_events_np sen;
@@ -42,7 +42,7 @@ static void send_subscription(struct pmc_node *node)
pmc_send_set_action(node->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
}
-static int check_clock_identity(struct pmc_node *node, struct ptp_message *msg)
+static int check_clock_identity(struct pmc_agent *node, struct ptp_message *msg)
{
if (!node->clock_identity_set)
return 1;
@@ -98,7 +98,7 @@ static int get_mgt_err_id(struct ptp_message *msg)
* -1: error reported by the other side
* -2: local error, fatal
*/
-static int run_pmc(struct pmc_node *node, int timeout, int ds_id,
+static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
struct ptp_message **msg)
{
#define N_FD 1
@@ -166,7 +166,7 @@ static int run_pmc(struct pmc_node *node, int timeout, int ds_id,
}
}
-int run_pmc_wait_sync(struct pmc_node *node, int timeout)
+int run_pmc_wait_sync(struct pmc_agent *node, int timeout)
{
struct ptp_message *msg;
Enumeration8 portState;
@@ -192,7 +192,7 @@ int run_pmc_wait_sync(struct pmc_node *node, int timeout)
}
}
-int run_pmc_get_utc_offset(struct pmc_node *node, int timeout)
+int run_pmc_get_utc_offset(struct pmc_agent *node, int timeout)
{
struct ptp_message *msg;
int res;
@@ -222,7 +222,7 @@ int run_pmc_get_utc_offset(struct pmc_node *node, int timeout)
return 1;
}
-int run_pmc_get_number_ports(struct pmc_node *node, int timeout)
+int run_pmc_get_number_ports(struct pmc_agent *node, int timeout)
{
struct ptp_message *msg;
int res;
@@ -238,7 +238,7 @@ int run_pmc_get_number_ports(struct pmc_node *node, int timeout)
return res;
}
-int run_pmc_subscribe(struct pmc_node *node, int timeout)
+int run_pmc_subscribe(struct pmc_agent *node, int timeout)
{
struct ptp_message *msg;
int res;
@@ -250,14 +250,14 @@ int run_pmc_subscribe(struct pmc_node *node, int timeout)
return 1;
}
-void run_pmc_events(struct pmc_node *node)
+void run_pmc_events(struct pmc_agent *node)
{
struct ptp_message *msg;
run_pmc(node, 0, -1, &msg);
}
-int run_pmc_port_properties(struct pmc_node *node, int timeout,
+int run_pmc_port_properties(struct pmc_agent *node, int timeout,
unsigned int port, int *state,
int *tstamping, char *iface)
{
@@ -294,7 +294,7 @@ out:
return res;
}
-int run_pmc_clock_identity(struct pmc_node *node, int timeout)
+int run_pmc_clock_identity(struct pmc_agent *node, int timeout)
{
struct ptp_message *msg;
struct defaultDS *dds;
@@ -313,7 +313,7 @@ int run_pmc_clock_identity(struct pmc_node *node, int timeout)
}
/* Returns: -1 in case of error, 0 otherwise */
-int update_pmc_node(struct pmc_node *node, int subscribe)
+int update_pmc_node(struct pmc_agent *node, int subscribe)
{
struct timespec tp;
uint64_t ts;
@@ -336,7 +336,7 @@ int update_pmc_node(struct pmc_node *node, int subscribe)
return 0;
}
-int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
+int init_pmc_node(struct config *cfg, struct pmc_agent *node, const char *uds,
pmc_node_recv_subscribed_t *recv_subscribed)
{
node->pmc = pmc_create(cfg, TRANS_UDS, uds, 0,
@@ -351,7 +351,7 @@ int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
return 0;
}
-void close_pmc_node(struct pmc_node *node)
+void close_pmc_node(struct pmc_agent *node)
{
if (!node->pmc)
return;
diff --git a/pmc_agent.h b/pmc_agent.h
index 90245b1..10ef4b5 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -24,13 +24,13 @@
#include "pmc_common.h"
-struct pmc_node;
+struct pmc_agent;
-typedef int pmc_node_recv_subscribed_t(struct pmc_node *node,
+typedef int pmc_node_recv_subscribed_t(struct pmc_agent *agent,
struct ptp_message *msg,
int excluded);
-struct pmc_node {
+struct pmc_agent {
struct pmc *pmc;
int pmc_ds_requested;
uint64_t pmc_last_update;
@@ -42,19 +42,19 @@ struct pmc_node {
pmc_node_recv_subscribed_t *recv_subscribed;
};
-int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
+int init_pmc_node(struct config *cfg, struct pmc_agent *agent, const char *uds,
pmc_node_recv_subscribed_t *recv_subscribed);
-void close_pmc_node(struct pmc_node *node);
-int update_pmc_node(struct pmc_node *node, int subscribe);
-int run_pmc_subscribe(struct pmc_node *node, int timeout);
-int run_pmc_clock_identity(struct pmc_node *node, int timeout);
-int run_pmc_wait_sync(struct pmc_node *node, int timeout);
-int run_pmc_get_number_ports(struct pmc_node *node, int timeout);
-void run_pmc_events(struct pmc_node *node);
-int run_pmc_port_properties(struct pmc_node *node, int timeout,
+void close_pmc_node(struct pmc_agent *agent);
+int update_pmc_node(struct pmc_agent *agent, int subscribe);
+int run_pmc_subscribe(struct pmc_agent *agent, int timeout);
+int run_pmc_clock_identity(struct pmc_agent *agent, int timeout);
+int run_pmc_wait_sync(struct pmc_agent *agent, int timeout);
+int run_pmc_get_number_ports(struct pmc_agent *agent, int timeout);
+void run_pmc_events(struct pmc_agent *agent);
+int run_pmc_port_properties(struct pmc_agent *agent, int timeout,
unsigned int port, int *state,
int *tstamping, char *iface);
-int run_pmc_get_utc_offset(struct pmc_node *node, int timeout);
+int run_pmc_get_utc_offset(struct pmc_agent *agent, int timeout);
int get_mgt_id(struct ptp_message *msg);
void *get_mgt_data(struct ptp_message *msg);
--
2.25.1

View File

@ -0,0 +1,448 @@
From f6d7bb0a62f15fcca0343c42891f7e056f502949 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 14:55:29 -0300
Subject: [PATCH 16/47] pmc_agent: Hide the implementation.
The PMC agent's implementation should not be exposed to its users. This
patch hides the details and provides a method to create an instance. In
addition, the signature of the receive callback is made generic, removing
the container_of pattern meant for sub-classing modules.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
[commit 826698791769e0ba4431fe98f02d4d09c109542e upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 76 +++++++++++++++++++++++++++++------------------------
pmc_agent.c | 58 +++++++++++++++++++++++++++++++++++-----
pmc_agent.h | 62 +++++++++++++++++++++++++++++++------------
3 files changed, 138 insertions(+), 58 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 74ee9d1..037b1b9 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -103,7 +103,7 @@ struct phc2sys_private {
int forced_sync_offset;
int kernel_leap;
int state_changed;
- struct pmc_agent node;
+ struct pmc_agent *node;
LIST_HEAD(port_head, port) ports;
LIST_HEAD(clock_head, clock) clocks;
LIST_HEAD(dst_clock_head, clock) dst_clocks;
@@ -306,7 +306,7 @@ static void clock_reinit(struct phc2sys_private *priv, struct clock *clock,
LIST_FOREACH(p, &priv->ports, list) {
if (p->clock == clock) {
- ret = run_pmc_port_properties(&priv->node, 1000, p->number,
+ ret = run_pmc_port_properties(priv->node, 1000, p->number,
&state, &timestamping,
iface);
if (ret > 0)
@@ -641,7 +641,7 @@ static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
if (src == CLOCK_INVALID) {
/* The sync offset can't be applied with PPS alone. */
- priv->node.sync_offset = 0;
+ pmc_agent_set_sync_offset(priv->node, 0);
} else {
enable_pps_output(priv->master->clkid);
}
@@ -672,7 +672,7 @@ static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
pps_offset = pps_ts - phc_ts;
}
- if (update_pmc_node(&priv->node, 0) < 0)
+ if (update_pmc_node(priv->node, 0) < 0)
continue;
update_clock(priv, clock, pps_offset, pps_ts, -1);
}
@@ -710,15 +710,15 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
while (is_running()) {
clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL);
- if (update_pmc_node(&priv->node, subscriptions) < 0)
+ if (update_pmc_node(priv->node, subscriptions) < 0)
continue;
if (subscriptions) {
- run_pmc_events(&priv->node);
+ run_pmc_events(priv->node);
if (priv->state_changed) {
/* force getting offset, as it may have
* changed after the port state change */
- if (run_pmc_get_utc_offset(&priv->node, 1000) <= 0) {
+ if (run_pmc_get_utc_offset(priv->node, 1000) <= 0) {
pr_err("failed to get UTC offset");
continue;
}
@@ -810,13 +810,10 @@ static int clock_compute_state(struct phc2sys_private *priv,
return state;
}
-#define node_to_phc2sys(node) \
- container_of(node, struct phc2sys_private, node)
-
-static int phc2sys_recv_subscribed(struct pmc_agent *node,
- struct ptp_message *msg, int excluded)
+static int phc2sys_recv_subscribed(void *context, struct ptp_message *msg,
+ int excluded)
{
- struct phc2sys_private *priv = node_to_phc2sys(node);
+ struct phc2sys_private *priv = (struct phc2sys_private *) context;
int mgt_id, state;
struct portDS *pds;
struct port *port;
@@ -863,7 +860,7 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
while (1) {
if (!is_running())
return -1;
- res = run_pmc_clock_identity(&priv->node, 1000);
+ res = run_pmc_clock_identity(priv->node, 1000);
if (res < 0)
return -1;
if (res > 0)
@@ -872,20 +869,20 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
pr_notice("Waiting for ptp4l...");
}
- number_ports = run_pmc_get_number_ports(&priv->node, 1000);
+ number_ports = run_pmc_get_number_ports(priv->node, 1000);
if (number_ports <= 0) {
pr_err("failed to get number of ports");
return -1;
}
- res = run_pmc_subscribe(&priv->node, 1000);
+ res = run_pmc_subscribe(priv->node, 1000);
if (res <= 0) {
pr_err("failed to subscribe");
return -1;
}
for (i = 1; i <= number_ports; i++) {
- res = run_pmc_port_properties(&priv->node, 1000, i, &state,
+ res = run_pmc_port_properties(priv->node, 1000, i, &state,
&timestamping, iface);
if (res == -1) {
/* port does not exist, ignore the port */
@@ -922,7 +919,7 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
}
/* get initial offset */
- if (run_pmc_get_utc_offset(&priv->node, 1000) <= 0) {
+ if (run_pmc_get_utc_offset(priv->node, 1000) <= 0) {
pr_err("failed to get UTC offset");
return -1;
}
@@ -933,9 +930,9 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
int64_t offset, uint64_t ts)
{
- int clock_leap, node_leap = priv->node.leap;
+ int clock_leap, node_leap = pmc_agent_get_leap(priv->node);
- clock->sync_offset = priv->node.sync_offset;
+ clock->sync_offset = pmc_agent_get_sync_offset(priv->node);
if ((node_leap || clock->leap_set) &&
clock->is_utc != priv->master->is_utc) {
@@ -976,7 +973,7 @@ static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
}
}
- if (priv->node.utc_offset_traceable &&
+ if (pmc_agent_utc_offset_traceable(priv->node) &&
clock->utc_offset_set != clock->sync_offset) {
if (clock->clkid == CLOCK_REALTIME)
sysclk_set_tai_offset(clock->sync_offset);
@@ -1032,11 +1029,13 @@ int main(int argc, char *argv[])
{
char *config = NULL, *dst_name = NULL, *progname, *src_name = NULL;
char uds_local[MAX_IFNAME_SIZE + 1];
+ int autocfg = 0, c, domain_number = 0, index, ntpshm_segment, offset;
+ int pps_fd = -1, print_level = LOG_INFO, r = -1, rt = 0;
+ int wait_sync = 0;
struct clock *src, *dst;
struct config *cfg;
struct option *opts;
- int autocfg = 0, c, domain_number = 0, default_sync = 1, index, ntpshm_segment;
- int pps_fd = -1, print_level = LOG_INFO, r = -1, rt = 0, wait_sync = 0;
+ int default_sync = 1;
double phc_rate, tmp;
struct phc2sys_private priv = {
.phc_readings = 5,
@@ -1049,6 +1048,10 @@ int main(int argc, char *argv[])
if (!cfg) {
return -1;
}
+ priv.node = pmc_agent_create();
+ if (!priv.node) {
+ return -1;
+ }
opts = config_long_options(cfg);
@@ -1140,9 +1143,10 @@ int main(int argc, char *argv[])
goto end;
break;
case 'O':
- if (get_arg_val_i(c, optarg, &priv.node.sync_offset,
- INT_MIN, INT_MAX))
+ if (get_arg_val_i(c, optarg, &offset, INT_MIN, INT_MAX)) {
goto end;
+ }
+ pmc_agent_set_sync_offset(priv.node, offset);
priv.forced_sync_offset = -1;
break;
case 'L':
@@ -1271,8 +1275,8 @@ int main(int argc, char *argv[])
getpid());
if (autocfg) {
- if (init_pmc_node(cfg, &priv.node, uds_local,
- phc2sys_recv_subscribed))
+ if (init_pmc_node(cfg, priv.node, uds_local,
+ phc2sys_recv_subscribed, &priv))
goto end;
if (auto_init_ports(&priv, rt) < 0)
goto end;
@@ -1309,12 +1313,12 @@ int main(int argc, char *argv[])
r = -1;
if (wait_sync) {
- if (init_pmc_node(cfg, &priv.node, uds_local,
- phc2sys_recv_subscribed))
+ if (init_pmc_node(cfg, priv.node, uds_local,
+ phc2sys_recv_subscribed, &priv))
goto end;
while (is_running()) {
- r = run_pmc_wait_sync(&priv.node, 1000);
+ r = run_pmc_wait_sync(priv.node, 1000);
if (r < 0)
goto end;
if (r > 0)
@@ -1324,7 +1328,7 @@ int main(int argc, char *argv[])
}
if (!priv.forced_sync_offset) {
- r = run_pmc_get_utc_offset(&priv.node, 1000);
+ r = run_pmc_get_utc_offset(priv.node, 1000);
if (r <= 0) {
pr_err("failed to get UTC offset");
goto end;
@@ -1333,8 +1337,10 @@ int main(int argc, char *argv[])
if (priv.forced_sync_offset ||
(src->clkid != CLOCK_REALTIME && dst->clkid != CLOCK_REALTIME) ||
- src->clkid == CLOCK_INVALID)
- close_pmc_node(&priv.node);
+ src->clkid == CLOCK_INVALID) {
+ pmc_agent_destroy(priv.node);
+ priv.node = NULL;
+ }
}
if (pps_fd >= 0) {
@@ -1347,7 +1353,9 @@ int main(int argc, char *argv[])
}
end:
- close_pmc_node(&priv.node);
+ if (priv.node) {
+ pmc_agent_destroy(priv.node);
+ }
clock_cleanup(&priv);
port_cleanup(&priv);
config_destroy(cfg);
diff --git a/pmc_agent.c b/pmc_agent.c
index e83895c..8ccafe2 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -19,6 +19,7 @@
*/
#include <net/if.h>
#include <poll.h>
+#include <stdlib.h>
#include "notification.h"
#include "pmc_agent.h"
@@ -32,6 +33,22 @@
* renewed.
*/
+struct pmc_agent {
+ struct pmc *pmc;
+ uint64_t pmc_last_update;
+
+ struct ClockIdentity clock_identity;
+ int clock_identity_set;
+ int leap;
+ int pmc_ds_requested;
+ int sync_offset;
+ int utc_offset_traceable;
+
+ /* Callback on message reception */
+ pmc_node_recv_subscribed_t *recv_subscribed;
+ void *recv_context;
+};
+
static void send_subscription(struct pmc_agent *node)
{
struct subscribe_events_np sen;
@@ -155,7 +172,8 @@ static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
node->pmc_ds_requested = 0;
return -1;
}
- if (res <= 0 || node->recv_subscribed(node, *msg, ds_id) ||
+ if (res <= 0 ||
+ node->recv_subscribed(node->recv_context, *msg, ds_id) ||
get_mgt_id(*msg) != ds_id) {
msg_put(*msg);
*msg = NULL;
@@ -337,7 +355,7 @@ int update_pmc_node(struct pmc_agent *node, int subscribe)
}
int init_pmc_node(struct config *cfg, struct pmc_agent *node, const char *uds,
- pmc_node_recv_subscribed_t *recv_subscribed)
+ pmc_node_recv_subscribed_t *recv_subscribed, void *context)
{
node->pmc = pmc_create(cfg, TRANS_UDS, uds, 0,
config_get_int(cfg, NULL, "domainNumber"),
@@ -347,15 +365,41 @@ int init_pmc_node(struct config *cfg, struct pmc_agent *node, const char *uds,
return -1;
}
node->recv_subscribed = recv_subscribed;
+ node->recv_context = context;
return 0;
}
-void close_pmc_node(struct pmc_agent *node)
+struct pmc_agent *pmc_agent_create(void)
+{
+ struct pmc_agent *agent = calloc(1, sizeof(*agent));
+ return agent;
+}
+
+void pmc_agent_destroy(struct pmc_agent *agent)
+{
+ if (agent->pmc) {
+ pmc_destroy(agent->pmc);
+ }
+ free(agent);
+}
+
+int pmc_agent_get_leap(struct pmc_agent *agent)
{
- if (!node->pmc)
- return;
+ return agent->leap;
+}
+
+int pmc_agent_get_sync_offset(struct pmc_agent *agent)
+{
+ return agent->sync_offset;
+}
- pmc_destroy(node->pmc);
- node->pmc = NULL;
+void pmc_agent_set_sync_offset(struct pmc_agent *agent, int offset)
+{
+ agent->sync_offset = offset;
+}
+
+bool pmc_agent_utc_offset_traceable(struct pmc_agent *agent)
+{
+ return agent->utc_offset_traceable;
}
diff --git a/pmc_agent.h b/pmc_agent.h
index 10ef4b5..c0b4525 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -22,29 +22,17 @@
#ifndef HAVE_PMC_AGENT_H
#define HAVE_PMC_AGENT_H
+#include <stdbool.h>
+
#include "pmc_common.h"
struct pmc_agent;
-typedef int pmc_node_recv_subscribed_t(struct pmc_agent *agent,
- struct ptp_message *msg,
+typedef int pmc_node_recv_subscribed_t(void *context, struct ptp_message *msg,
int excluded);
-struct pmc_agent {
- struct pmc *pmc;
- int pmc_ds_requested;
- uint64_t pmc_last_update;
- int sync_offset;
- int leap;
- int utc_offset_traceable;
- int clock_identity_set;
- struct ClockIdentity clock_identity;
- pmc_node_recv_subscribed_t *recv_subscribed;
-};
-
int init_pmc_node(struct config *cfg, struct pmc_agent *agent, const char *uds,
- pmc_node_recv_subscribed_t *recv_subscribed);
-void close_pmc_node(struct pmc_agent *agent);
+ pmc_node_recv_subscribed_t *recv_subscribed, void *context);
int update_pmc_node(struct pmc_agent *agent, int subscribe);
int run_pmc_subscribe(struct pmc_agent *agent, int timeout);
int run_pmc_clock_identity(struct pmc_agent *agent, int timeout);
@@ -58,5 +46,45 @@ int run_pmc_get_utc_offset(struct pmc_agent *agent, int timeout);
int get_mgt_id(struct ptp_message *msg);
void *get_mgt_data(struct ptp_message *msg);
-#endif
+/**
+ * Creates an instance of a PMC agent.
+ * @return Pointer to a PMC instance on success, NULL otherwise.
+ */
+struct pmc_agent *pmc_agent_create(void);
+
+/**
+ * Destroys an instance of a PMC agent.
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ */
+void pmc_agent_destroy(struct pmc_agent *agent);
+
+/**
+ * Gets the current leap adjustment.
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ * @return The leap adjustment in seconds, either 1, 0, or -1.
+ */
+int pmc_agent_get_leap(struct pmc_agent *agent);
+
+/**
+ * Gets the TAI-UTC offset.
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ * @return Current offset in seconds.
+ */
+int pmc_agent_get_sync_offset(struct pmc_agent *agent);
+
+/**
+ * Sets the TAI-UTC offset.
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ * @param offset Desired offset in seconds.
+ */
+void pmc_agent_set_sync_offset(struct pmc_agent *agent, int offset);
+
+/**
+ * Tests whether the current UTC offset is traceable.
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ * @return True is the offset is traceable, false otherwise.
+ */
+bool pmc_agent_utc_offset_traceable(struct pmc_agent *agent);
+
+#endif
--
2.25.1

View File

@ -0,0 +1,96 @@
From 4ebb69f5c55e7f1f08d1a73df87d42fe70147ec9 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 14:58:09 -0300
Subject: [PATCH 17/47] Find a better home for the management TLV ID helper
function.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
[commit d95bb9f9d62f4f372934905e97e052aa68dcfc58 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
msg.h | 12 ++++++++++++
phc2sys.c | 2 +-
pmc_agent.c | 10 +---------
pmc_agent.h | 1 -
4 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/msg.h b/msg.h
index e71d3ce..b600ff0 100644
--- a/msg.h
+++ b/msg.h
@@ -247,6 +247,18 @@ static inline uint8_t management_action(struct ptp_message *m)
return m->management.flags & 0x0f;
}
+/**
+ * Obtain the ID field from the TLV in a management message.
+ * @param m A management message.
+ * @return The value of the ID field.
+ */
+static inline int management_tlv_id(struct ptp_message *m)
+{
+ struct management_tlv *mgt;
+ mgt = (struct management_tlv *) m->management.suffix;
+ return mgt->id;
+}
+
/**
* Test a given bit in a message's flag field.
* @param m Message to test.
diff --git a/phc2sys.c b/phc2sys.c
index 037b1b9..1f74f27 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -819,7 +819,7 @@ static int phc2sys_recv_subscribed(void *context, struct ptp_message *msg,
struct port *port;
struct clock *clock;
- mgt_id = get_mgt_id(msg);
+ mgt_id = management_tlv_id(msg);
if (mgt_id == excluded)
return 0;
switch (mgt_id) {
diff --git a/pmc_agent.c b/pmc_agent.c
index 8ccafe2..6dfb3ca 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -85,14 +85,6 @@ static int is_msg_mgt(struct ptp_message *msg)
return 0;
}
-int get_mgt_id(struct ptp_message *msg)
-{
- struct management_tlv *mgt;
-
- mgt = (struct management_tlv *) msg->management.suffix;
- return mgt->id;
-}
-
void *get_mgt_data(struct ptp_message *msg)
{
struct management_tlv *mgt;
@@ -174,7 +166,7 @@ static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
}
if (res <= 0 ||
node->recv_subscribed(node->recv_context, *msg, ds_id) ||
- get_mgt_id(*msg) != ds_id) {
+ management_tlv_id(*msg) != ds_id) {
msg_put(*msg);
*msg = NULL;
continue;
diff --git a/pmc_agent.h b/pmc_agent.h
index c0b4525..09249ff 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -43,7 +43,6 @@ int run_pmc_port_properties(struct pmc_agent *agent, int timeout,
unsigned int port, int *state,
int *tstamping, char *iface);
int run_pmc_get_utc_offset(struct pmc_agent *agent, int timeout);
-int get_mgt_id(struct ptp_message *msg);
void *get_mgt_data(struct ptp_message *msg);
--
2.25.1

View File

@ -0,0 +1,132 @@
From 6e4f8ea8531b7678a44a9b3ed021fda94eccdc27 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 14:59:57 -0300
Subject: [PATCH 18/47] Find a better home for the management TLV data helper
function.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
[commit 5dd47c873cae8e0a2815b43c1ef3a86b9aca9dac upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
msg.h | 12 ++++++++++++
phc2sys.c | 2 +-
pmc_agent.c | 18 +++++-------------
pmc_agent.h | 1 -
4 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/msg.h b/msg.h
index b600ff0..84380da 100644
--- a/msg.h
+++ b/msg.h
@@ -247,6 +247,18 @@ static inline uint8_t management_action(struct ptp_message *m)
return m->management.flags & 0x0f;
}
+/**
+ * Obtain the data field from the TLV in a management message.
+ * @param m A management message.
+ * @return A pointer to the TLV data field.
+ */
+static inline void *management_tlv_data(struct ptp_message *msg)
+{
+ struct management_tlv *mgt;
+ mgt = (struct management_tlv *) msg->management.suffix;
+ return mgt->data;
+}
+
/**
* Obtain the ID field from the TLV in a management message.
* @param m A management message.
diff --git a/phc2sys.c b/phc2sys.c
index 1f74f27..280e249 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -824,7 +824,7 @@ static int phc2sys_recv_subscribed(void *context, struct ptp_message *msg,
return 0;
switch (mgt_id) {
case TLV_PORT_DATA_SET:
- pds = get_mgt_data(msg);
+ pds = management_tlv_data(msg);
port = port_get(priv, pds->portIdentity.portNumber);
if (!port) {
pr_info("received data for unknown port %s",
diff --git a/pmc_agent.c b/pmc_agent.c
index 6dfb3ca..6e9c023 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -85,14 +85,6 @@ static int is_msg_mgt(struct ptp_message *msg)
return 0;
}
-void *get_mgt_data(struct ptp_message *msg)
-{
- struct management_tlv *mgt;
-
- mgt = (struct management_tlv *) msg->management.suffix;
- return mgt->data;
-}
-
static int get_mgt_err_id(struct ptp_message *msg)
{
struct management_error_status *mgt;
@@ -188,7 +180,7 @@ int run_pmc_wait_sync(struct pmc_agent *node, int timeout)
if (res <= 0)
return res;
- data = get_mgt_data(msg);
+ data = management_tlv_data(msg);
portState = ((struct portDS *)data)->portState;
msg_put(msg);
@@ -212,7 +204,7 @@ int run_pmc_get_utc_offset(struct pmc_agent *node, int timeout)
if (res <= 0)
return res;
- tds = (struct timePropertiesDS *)get_mgt_data(msg);
+ tds = (struct timePropertiesDS *) management_tlv_data(msg);
if (tds->flags & PTP_TIMESCALE) {
node->sync_offset = tds->currentUtcOffset;
if (tds->flags & LEAP_61)
@@ -242,7 +234,7 @@ int run_pmc_get_number_ports(struct pmc_agent *node, int timeout)
if (res <= 0)
return res;
- dds = (struct defaultDS *)get_mgt_data(msg);
+ dds = (struct defaultDS *) management_tlv_data(msg);
res = dds->numberPorts;
msg_put(msg);
return res;
@@ -281,7 +273,7 @@ int run_pmc_port_properties(struct pmc_agent *node, int timeout,
if (res <= 0)
goto out;
- ppn = get_mgt_data(msg);
+ ppn = management_tlv_data(msg);
if (ppn->portIdentity.portNumber != port) {
msg_put(msg);
continue;
@@ -314,7 +306,7 @@ int run_pmc_clock_identity(struct pmc_agent *node, int timeout)
if (res <= 0)
return res;
- dds = (struct defaultDS *)get_mgt_data(msg);
+ dds = (struct defaultDS *) management_tlv_data(msg);
memcpy(&node->clock_identity, &dds->clockIdentity,
sizeof(struct ClockIdentity));
node->clock_identity_set = 1;
diff --git a/pmc_agent.h b/pmc_agent.h
index 09249ff..f3a26fe 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -43,7 +43,6 @@ int run_pmc_port_properties(struct pmc_agent *agent, int timeout,
unsigned int port, int *state,
int *tstamping, char *iface);
int run_pmc_get_utc_offset(struct pmc_agent *agent, int timeout);
-void *get_mgt_data(struct ptp_message *msg);
/**
--
2.25.1

View File

@ -0,0 +1,81 @@
From 95e4983c9ab517b9dda1faf171721f0dd877e076 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 15:04:11 -0300
Subject: [PATCH 19/47] Introduce error codes for the run_pmc method.
The run_pmc function is used by several of the PMC agent methods, but it
breaks the pattern of returning zero on success. However, the user facing
PMC agent methods will need to conform to the return code convention used
throughout the stack.
In order to migrate to proper return codes, this patch replaces the hard
coded result values with macros so that the interface methods can translate
them to the required semantics of zero on success.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
[commit 802259bbe40faa5f8bdebab36e6fbcbc51c3c2a2 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
pmc_agent.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/pmc_agent.c b/pmc_agent.c
index 6e9c023..22d9c5b 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -93,12 +93,11 @@ static int get_mgt_err_id(struct ptp_message *msg)
return mgt->id;
}
-/* Return values:
- * 1: success
- * 0: timeout
- * -1: error reported by the other side
- * -2: local error, fatal
- */
+#define RUN_PMC_OKAY 1
+#define RUN_PMC_TMO 0
+#define RUN_PMC_NODEV -1
+#define RUN_PMC_INTR -2
+
static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
struct ptp_message **msg)
{
@@ -115,12 +114,12 @@ static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
cnt = poll(pollfd, N_FD, timeout);
if (cnt < 0) {
pr_err("poll failed");
- return -2;
+ return RUN_PMC_INTR;
}
if (!cnt) {
/* Request the data set again in the next run. */
node->pmc_ds_requested = 0;
- return 0;
+ return RUN_PMC_TMO;
}
/* Send a new request if there are no pending messages. */
@@ -154,7 +153,7 @@ static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
res = is_msg_mgt(*msg);
if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
node->pmc_ds_requested = 0;
- return -1;
+ return RUN_PMC_NODEV;
}
if (res <= 0 ||
node->recv_subscribed(node->recv_context, *msg, ds_id) ||
@@ -164,7 +163,7 @@ static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
continue;
}
node->pmc_ds_requested = 0;
- return 1;
+ return RUN_PMC_OKAY;
}
}
--
2.25.1

View File

@ -0,0 +1,153 @@
From 8c1dd261683d27acba49e047d9f6da52dada3c98 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 15:08:01 -0300
Subject: [PATCH 20/47] pmc_agent: Convert the subscribe method into the
canonical form.
This patch renames the function to have the module prefix and corrects the
return code semantics.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
[commit cc98d39f58adc1fd05db0038acfdcc5669f2ba8c upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 4 ++--
pmc_agent.c | 48 +++++++++++++++++++++++++++++++++++-------------
pmc_agent.h | 9 ++++++++-
3 files changed, 45 insertions(+), 16 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 280e249..f61e699 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -875,8 +875,8 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
return -1;
}
- res = run_pmc_subscribe(priv->node, 1000);
- if (res <= 0) {
+ res = pmc_agent_subscribe(priv->node, 1000);
+ if (res) {
pr_err("failed to subscribe");
return -1;
}
diff --git a/pmc_agent.c b/pmc_agent.c
index 22d9c5b..9c5eb71 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -17,6 +17,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <errno.h>
#include <net/if.h>
#include <poll.h>
#include <stdlib.h>
@@ -98,6 +99,26 @@ static int get_mgt_err_id(struct ptp_message *msg)
#define RUN_PMC_NODEV -1
#define RUN_PMC_INTR -2
+static bool is_run_pmc_error(int code)
+{
+ return code != RUN_PMC_OKAY;
+}
+
+static int run_pmc_err2errno(int code)
+{
+ switch (code) {
+ case RUN_PMC_TMO:
+ return -ETIMEDOUT;
+ case RUN_PMC_NODEV:
+ return -ENODEV;
+ case RUN_PMC_INTR:
+ return -EINTR;
+ case RUN_PMC_OKAY:
+ default:
+ return 0;
+ }
+}
+
static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
struct ptp_message **msg)
{
@@ -239,18 +260,6 @@ int run_pmc_get_number_ports(struct pmc_agent *node, int timeout)
return res;
}
-int run_pmc_subscribe(struct pmc_agent *node, int timeout)
-{
- struct ptp_message *msg;
- int res;
-
- res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
- if (res <= 0)
- return res;
- msg_put(msg);
- return 1;
-}
-
void run_pmc_events(struct pmc_agent *node)
{
struct ptp_message *msg;
@@ -329,7 +338,7 @@ int update_pmc_node(struct pmc_agent *node, int subscribe)
!(ts > node->pmc_last_update &&
ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
if (subscribe)
- run_pmc_subscribe(node, 0);
+ pmc_agent_subscribe(node, 0);
if (run_pmc_get_utc_offset(node, 0) > 0)
node->pmc_last_update = ts;
}
@@ -382,6 +391,19 @@ void pmc_agent_set_sync_offset(struct pmc_agent *agent, int offset)
agent->sync_offset = offset;
}
+int pmc_agent_subscribe(struct pmc_agent *node, int timeout)
+{
+ struct ptp_message *msg;
+ int res;
+
+ res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
+ if (is_run_pmc_error(res)) {
+ return run_pmc_err2errno(res);
+ }
+ msg_put(msg);
+ return 0;
+}
+
bool pmc_agent_utc_offset_traceable(struct pmc_agent *agent)
{
return agent->utc_offset_traceable;
diff --git a/pmc_agent.h b/pmc_agent.h
index f3a26fe..9dc684e 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -34,7 +34,6 @@ typedef int pmc_node_recv_subscribed_t(void *context, struct ptp_message *msg,
int init_pmc_node(struct config *cfg, struct pmc_agent *agent, const char *uds,
pmc_node_recv_subscribed_t *recv_subscribed, void *context);
int update_pmc_node(struct pmc_agent *agent, int subscribe);
-int run_pmc_subscribe(struct pmc_agent *agent, int timeout);
int run_pmc_clock_identity(struct pmc_agent *agent, int timeout);
int run_pmc_wait_sync(struct pmc_agent *agent, int timeout);
int run_pmc_get_number_ports(struct pmc_agent *agent, int timeout);
@@ -78,6 +77,14 @@ int pmc_agent_get_sync_offset(struct pmc_agent *agent);
*/
void pmc_agent_set_sync_offset(struct pmc_agent *agent, int offset);
+/**
+ * Subscribes to push notifications of changes in port state.
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ * @param timeout Transmit and receive timeout in milliseconds.
+ * @return Zero on success, negative error code otherwise.
+ */
+int pmc_agent_subscribe(struct pmc_agent *agent, int timeout);
+
/**
* Tests whether the current UTC offset is traceable.
* @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
--
2.25.1

View File

@ -0,0 +1,133 @@
From 82a369b4fe44a7cea41fb0ccf408c02b1b6aa694 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 15:17:26 -0300
Subject: [PATCH 21/47] pmc_agent: Simplify the update method.
The main method that causes the PMC agent to update its status takes a flag
that results in different behavior when push notifications are active.
This patch simplifies the interface by letting the agent remember whether
or not the caller subscribed to the notifications in the first place.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
[commit 1126f8f67e853199f05a7c993c910ebc7807bd3d upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 6 ++++--
pmc_agent.c | 32 ++++++++++++++++++++------------
pmc_agent.h | 2 +-
3 files changed, 25 insertions(+), 15 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index f61e699..b155961 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -672,7 +672,7 @@ static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
pps_offset = pps_ts - phc_ts;
}
- if (update_pmc_node(priv->node, 0) < 0)
+ if (update_pmc_node(priv->node) < 0)
continue;
update_clock(priv, clock, pps_offset, pps_ts, -1);
}
@@ -710,8 +710,10 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
while (is_running()) {
clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL);
- if (update_pmc_node(priv->node, subscriptions) < 0)
+
+ if (update_pmc_node(priv->node) < 0) {
continue;
+ }
if (subscriptions) {
run_pmc_events(priv->node);
diff --git a/pmc_agent.c b/pmc_agent.c
index 9c5eb71..dd509af 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -42,6 +42,7 @@ struct pmc_agent {
int clock_identity_set;
int leap;
int pmc_ds_requested;
+ bool stay_subscribed;
int sync_offset;
int utc_offset_traceable;
@@ -188,6 +189,19 @@ static int run_pmc(struct pmc_agent *node, int timeout, int ds_id,
}
}
+static int renew_subscription(struct pmc_agent *node, int timeout)
+{
+ struct ptp_message *msg;
+ int res;
+
+ res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
+ if (is_run_pmc_error(res)) {
+ return run_pmc_err2errno(res);
+ }
+ msg_put(msg);
+ return 0;
+}
+
int run_pmc_wait_sync(struct pmc_agent *node, int timeout)
{
struct ptp_message *msg;
@@ -323,7 +337,7 @@ int run_pmc_clock_identity(struct pmc_agent *node, int timeout)
}
/* Returns: -1 in case of error, 0 otherwise */
-int update_pmc_node(struct pmc_agent *node, int subscribe)
+int update_pmc_node(struct pmc_agent *node)
{
struct timespec tp;
uint64_t ts;
@@ -337,8 +351,9 @@ int update_pmc_node(struct pmc_agent *node, int subscribe)
if (node->pmc &&
!(ts > node->pmc_last_update &&
ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
- if (subscribe)
- pmc_agent_subscribe(node, 0);
+ if (node->stay_subscribed) {
+ renew_subscription(node, 0);
+ }
if (run_pmc_get_utc_offset(node, 0) > 0)
node->pmc_last_update = ts;
}
@@ -393,15 +408,8 @@ void pmc_agent_set_sync_offset(struct pmc_agent *agent, int offset)
int pmc_agent_subscribe(struct pmc_agent *node, int timeout)
{
- struct ptp_message *msg;
- int res;
-
- res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
- if (is_run_pmc_error(res)) {
- return run_pmc_err2errno(res);
- }
- msg_put(msg);
- return 0;
+ node->stay_subscribed = true;
+ return renew_subscription(node, timeout);
}
bool pmc_agent_utc_offset_traceable(struct pmc_agent *agent)
diff --git a/pmc_agent.h b/pmc_agent.h
index 9dc684e..743818f 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -33,7 +33,7 @@ typedef int pmc_node_recv_subscribed_t(void *context, struct ptp_message *msg,
int init_pmc_node(struct config *cfg, struct pmc_agent *agent, const char *uds,
pmc_node_recv_subscribed_t *recv_subscribed, void *context);
-int update_pmc_node(struct pmc_agent *agent, int subscribe);
+int update_pmc_node(struct pmc_agent *agent);
int run_pmc_clock_identity(struct pmc_agent *agent, int timeout);
int run_pmc_wait_sync(struct pmc_agent *agent, int timeout);
int run_pmc_get_number_ports(struct pmc_agent *agent, int timeout);
--
2.25.1

View File

@ -0,0 +1,45 @@
From 731e8938953e56578007a679dbaa29e9471650ac Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 15:18:36 -0300
Subject: [PATCH 22/47] pmc_agent: Simplify logic in update method.
If the pmc pointer is not set, then there is no need to read the time only
to later discard the result. This patch simplifies the flow by returning
early if there is no work to be done.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
[commit 956b7eeb8247e3f0658b1205dfd3bea3e1011ee2 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
pmc_agent.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/pmc_agent.c b/pmc_agent.c
index dd509af..f30f174 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -342,14 +342,16 @@ int update_pmc_node(struct pmc_agent *node)
struct timespec tp;
uint64_t ts;
+ if (!node->pmc) {
+ return 0;
+ }
if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
pr_err("failed to read clock: %m");
return -1;
}
ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
- if (node->pmc &&
- !(ts > node->pmc_last_update &&
+ if (!(ts > node->pmc_last_update &&
ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
if (node->stay_subscribed) {
renew_subscription(node, 0);
--
2.25.1

View File

@ -0,0 +1,40 @@
From 357e24c897e1e2d29cf011b3a38c3a6b2a7943c3 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 15:33:43 -0300
Subject: [PATCH 23/47] pmc_agent: Remove bogus comparison between last update
and now.
The monotonic clock can never go backwards. If you take T1 and later T2
from that clock, then (T2 > T1) is always true.
This patch removes the useless test.
[ This test evolved over the years. Originally the time stamp in question
came from a PHC. ]
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
[commit 2f2f7fc5881a88295350430edaf4505dc03b1602 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
pmc_agent.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pmc_agent.c b/pmc_agent.c
index f30f174..df3a562 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -351,8 +351,7 @@ int update_pmc_node(struct pmc_agent *node)
}
ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
- if (!(ts > node->pmc_last_update &&
- ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
+ if (!(ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
if (node->stay_subscribed) {
renew_subscription(node, 0);
}
--
2.25.1

View File

@ -0,0 +1,43 @@
From d5421e4d4d86907648a59810ab9c27e739591971 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 15:35:23 -0300
Subject: [PATCH 24/47] pmc_agent: Perform time comparison using positive
logic.
In the update_pmc_node() method, reduce the expression
!(x < y) to (x >= y).
While we're at it, clean the coding style as well.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
[commit fb92fec7cef9ee3345950c2633a7781b8bd3ca08 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
pmc_agent.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/pmc_agent.c b/pmc_agent.c
index df3a562..ea6b3b7 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -351,12 +351,13 @@ int update_pmc_node(struct pmc_agent *node)
}
ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
- if (!(ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
+ if (ts - node->pmc_last_update >= PMC_UPDATE_INTERVAL) {
if (node->stay_subscribed) {
renew_subscription(node, 0);
}
- if (run_pmc_get_utc_offset(node, 0) > 0)
+ if (run_pmc_get_utc_offset(node, 0) > 0) {
node->pmc_last_update = ts;
+ }
}
return 0;
--
2.25.1

View File

@ -0,0 +1,155 @@
From a304d4df86a76c187fc7074755fe9b5ad349efbe Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 15:36:38 -0300
Subject: [PATCH 25/47] pmc_agent: Rename the update method and attempt to
document it.
This patch renames the function to have the module prefix and tries to
put into words what it does.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
[commit 9a2dae984e0d355d751913e3308f9a954da11aa3 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 4 ++--
pmc_agent.c | 53 ++++++++++++++++++++++++++---------------------------
pmc_agent.h | 21 ++++++++++++++++++++-
3 files changed, 48 insertions(+), 30 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index b155961..cbe80f2 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -672,7 +672,7 @@ static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
pps_offset = pps_ts - phc_ts;
}
- if (update_pmc_node(priv->node) < 0)
+ if (pmc_agent_update(priv->node) < 0)
continue;
update_clock(priv, clock, pps_offset, pps_ts, -1);
}
@@ -711,7 +711,7 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
while (is_running()) {
clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL);
- if (update_pmc_node(priv->node) < 0) {
+ if (pmc_agent_update(priv->node) < 0) {
continue;
}
diff --git a/pmc_agent.c b/pmc_agent.c
index ea6b3b7..22af306 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -336,33 +336,6 @@ int run_pmc_clock_identity(struct pmc_agent *node, int timeout)
return 1;
}
-/* Returns: -1 in case of error, 0 otherwise */
-int update_pmc_node(struct pmc_agent *node)
-{
- struct timespec tp;
- uint64_t ts;
-
- if (!node->pmc) {
- return 0;
- }
- if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
- pr_err("failed to read clock: %m");
- return -1;
- }
- ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
-
- if (ts - node->pmc_last_update >= PMC_UPDATE_INTERVAL) {
- if (node->stay_subscribed) {
- renew_subscription(node, 0);
- }
- if (run_pmc_get_utc_offset(node, 0) > 0) {
- node->pmc_last_update = ts;
- }
- }
-
- return 0;
-}
-
int init_pmc_node(struct config *cfg, struct pmc_agent *node, const char *uds,
pmc_node_recv_subscribed_t *recv_subscribed, void *context)
{
@@ -414,6 +387,32 @@ int pmc_agent_subscribe(struct pmc_agent *node, int timeout)
return renew_subscription(node, timeout);
}
+int pmc_agent_update(struct pmc_agent *node)
+{
+ struct timespec tp;
+ uint64_t ts;
+
+ if (!node->pmc) {
+ return 0;
+ }
+ if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
+ pr_err("failed to read clock: %m");
+ return -errno;
+ }
+ ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
+
+ if (ts - node->pmc_last_update >= PMC_UPDATE_INTERVAL) {
+ if (node->stay_subscribed) {
+ renew_subscription(node, 0);
+ }
+ if (run_pmc_get_utc_offset(node, 0) > 0) {
+ node->pmc_last_update = ts;
+ }
+ }
+
+ return 0;
+}
+
bool pmc_agent_utc_offset_traceable(struct pmc_agent *agent)
{
return agent->utc_offset_traceable;
diff --git a/pmc_agent.h b/pmc_agent.h
index 743818f..483a21b 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -33,7 +33,6 @@ typedef int pmc_node_recv_subscribed_t(void *context, struct ptp_message *msg,
int init_pmc_node(struct config *cfg, struct pmc_agent *agent, const char *uds,
pmc_node_recv_subscribed_t *recv_subscribed, void *context);
-int update_pmc_node(struct pmc_agent *agent);
int run_pmc_clock_identity(struct pmc_agent *agent, int timeout);
int run_pmc_wait_sync(struct pmc_agent *agent, int timeout);
int run_pmc_get_number_ports(struct pmc_agent *agent, int timeout);
@@ -85,6 +84,26 @@ void pmc_agent_set_sync_offset(struct pmc_agent *agent, int offset);
*/
int pmc_agent_subscribe(struct pmc_agent *agent, int timeout);
+/**
+ * Queries the local ptp4l instance to update the TAI-UTC offset and
+ * the current leap second flags.
+ *
+ * In addition:
+ *
+ * - Any active port state subscription will be renewed.
+ * - The port state notification callback might be invoked.
+ *
+ * This function should be called periodically at least once per
+ * minute to keep both the port state and the leap second flags up to
+ * date. Note that the PMC agent rate limits the query to once per
+ * minute, and so the caller may safely invoke this method more often
+ * than that.
+ *
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ * @return Zero on success, negative error code otherwise.
+ */
+int pmc_agent_update(struct pmc_agent *agent);
+
/**
* Tests whether the current UTC offset is traceable.
* @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
--
2.25.1

View File

@ -0,0 +1,91 @@
From 5aacbe319db97907a15741005e2790bbf4c742a0 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 15:37:46 -0300
Subject: [PATCH 26/47] phc2sys: Fix null pointer de-reference in manual mode.
If both the -w and -O command line options are specified (or when
using -w when both source and destination clocks are PHCs), then
pointer to the PMC agent will be incorrectly freed.
Fix the segfault by introducing a method to "disable" the agent as was
done before the PMC agent code was introduced.
Unfortunately the resulting PMC agent API now has both create/destroy
and init/disable methods. This clunky arrangement can be cleaned up
later on, but it entails re-factoring the phc2sys program even more.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Fixes: 8266987 ("pmc_agent: Hide the implementation.")
[commit 68fd0b010e9761e3dc580026eb6f2366c7c8e82d upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 7 ++-----
pmc_agent.c | 8 ++++++++
pmc_agent.h | 6 ++++++
3 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index cbe80f2..3cafbb2 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -1340,8 +1340,7 @@ int main(int argc, char *argv[])
if (priv.forced_sync_offset ||
(src->clkid != CLOCK_REALTIME && dst->clkid != CLOCK_REALTIME) ||
src->clkid == CLOCK_INVALID) {
- pmc_agent_destroy(priv.node);
- priv.node = NULL;
+ pmc_agent_disable(priv.node);
}
}
@@ -1355,9 +1354,7 @@ int main(int argc, char *argv[])
}
end:
- if (priv.node) {
- pmc_agent_destroy(priv.node);
- }
+ pmc_agent_destroy(priv.node);
clock_cleanup(&priv);
port_cleanup(&priv);
config_destroy(cfg);
diff --git a/pmc_agent.c b/pmc_agent.c
index 22af306..833d1c1 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -366,6 +366,14 @@ void pmc_agent_destroy(struct pmc_agent *agent)
free(agent);
}
+void pmc_agent_disable(struct pmc_agent *agent)
+{
+ if (agent->pmc) {
+ pmc_destroy(agent->pmc);
+ }
+ agent->pmc = NULL;
+}
+
int pmc_agent_get_leap(struct pmc_agent *agent)
{
return agent->leap;
diff --git a/pmc_agent.h b/pmc_agent.h
index 483a21b..0ed10f8 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -55,6 +55,12 @@ struct pmc_agent *pmc_agent_create(void);
*/
void pmc_agent_destroy(struct pmc_agent *agent);
+/**
+ * Disconnects the PMC agent from the ptp4l service.
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ */
+void pmc_agent_disable(struct pmc_agent *agent);
+
/**
* Gets the current leap adjustment.
* @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
--
2.25.1

View File

@ -0,0 +1,182 @@
From b8188a4fd51bc8983e5d19f18fe37b8ca39d03a6 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 17:20:04 -0300
Subject: [PATCH 27/47] pmc_agent: Convert the method that queries TAI-UTC
offset into the canonical form.
This patch renames the function to have the module prefix and corrects the
return code semantics.
The active word in the function's name is "query" rather that "get" in
order to distinguish methods that send and receive over the network
from those that merely return a cached value.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
[commit 943c8f51c56acb72277d1a9459bbf7b7a5ac5fe7 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 8 +++----
pmc_agent.c | 63 +++++++++++++++++++++++++++--------------------------
pmc_agent.h | 16 ++++++++++++--
3 files changed, 50 insertions(+), 37 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 3cafbb2..78d662b 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -720,7 +720,7 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
if (priv->state_changed) {
/* force getting offset, as it may have
* changed after the port state change */
- if (run_pmc_get_utc_offset(priv->node, 1000) <= 0) {
+ if (pmc_agent_query_utc_offset(priv->node, 1000)) {
pr_err("failed to get UTC offset");
continue;
}
@@ -921,7 +921,7 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
}
/* get initial offset */
- if (run_pmc_get_utc_offset(priv->node, 1000) <= 0) {
+ if (pmc_agent_query_utc_offset(priv->node, 1000)) {
pr_err("failed to get UTC offset");
return -1;
}
@@ -1330,8 +1330,8 @@ int main(int argc, char *argv[])
}
if (!priv.forced_sync_offset) {
- r = run_pmc_get_utc_offset(priv.node, 1000);
- if (r <= 0) {
+ r = pmc_agent_query_utc_offset(priv.node, 1000);
+ if (r) {
pr_err("failed to get UTC offset");
goto end;
}
diff --git a/pmc_agent.c b/pmc_agent.c
index 833d1c1..7a57a2f 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -228,36 +228,6 @@ int run_pmc_wait_sync(struct pmc_agent *node, int timeout)
}
}
-int run_pmc_get_utc_offset(struct pmc_agent *node, int timeout)
-{
- struct ptp_message *msg;
- int res;
- struct timePropertiesDS *tds;
-
- res = run_pmc(node, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- tds = (struct timePropertiesDS *) management_tlv_data(msg);
- if (tds->flags & PTP_TIMESCALE) {
- node->sync_offset = tds->currentUtcOffset;
- if (tds->flags & LEAP_61)
- node->leap = 1;
- else if (tds->flags & LEAP_59)
- node->leap = -1;
- else
- node->leap = 0;
- node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
- tds->flags & TIME_TRACEABLE;
- } else {
- node->sync_offset = 0;
- node->leap = 0;
- node->utc_offset_traceable = 0;
- }
- msg_put(msg);
- return 1;
-}
-
int run_pmc_get_number_ports(struct pmc_agent *node, int timeout)
{
struct ptp_message *msg;
@@ -384,6 +354,37 @@ int pmc_agent_get_sync_offset(struct pmc_agent *agent)
return agent->sync_offset;
}
+int pmc_agent_query_utc_offset(struct pmc_agent *node, int timeout)
+{
+ struct timePropertiesDS *tds;
+ struct ptp_message *msg;
+ int res;
+
+ res = run_pmc(node, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
+ if (is_run_pmc_error(res)) {
+ return run_pmc_err2errno(res);
+ }
+
+ tds = (struct timePropertiesDS *) management_tlv_data(msg);
+ if (tds->flags & PTP_TIMESCALE) {
+ node->sync_offset = tds->currentUtcOffset;
+ if (tds->flags & LEAP_61)
+ node->leap = 1;
+ else if (tds->flags & LEAP_59)
+ node->leap = -1;
+ else
+ node->leap = 0;
+ node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
+ tds->flags & TIME_TRACEABLE;
+ } else {
+ node->sync_offset = 0;
+ node->leap = 0;
+ node->utc_offset_traceable = 0;
+ }
+ msg_put(msg);
+ return 0;
+}
+
void pmc_agent_set_sync_offset(struct pmc_agent *agent, int offset)
{
agent->sync_offset = offset;
@@ -413,7 +414,7 @@ int pmc_agent_update(struct pmc_agent *node)
if (node->stay_subscribed) {
renew_subscription(node, 0);
}
- if (run_pmc_get_utc_offset(node, 0) > 0) {
+ if (!pmc_agent_query_utc_offset(node, 0)) {
node->pmc_last_update = ts;
}
}
diff --git a/pmc_agent.h b/pmc_agent.h
index 0ed10f8..44326d2 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -40,8 +40,6 @@ void run_pmc_events(struct pmc_agent *agent);
int run_pmc_port_properties(struct pmc_agent *agent, int timeout,
unsigned int port, int *state,
int *tstamping, char *iface);
-int run_pmc_get_utc_offset(struct pmc_agent *agent, int timeout);
-
/**
* Creates an instance of a PMC agent.
@@ -75,6 +73,20 @@ int pmc_agent_get_leap(struct pmc_agent *agent);
*/
int pmc_agent_get_sync_offset(struct pmc_agent *agent);
+/**
+ * Queries the TAI-UTC offset and the current leap adjustment from the
+ * ptp4l service.
+ *
+ * In addition:
+ *
+ * - The port state notification callback might be invoked.
+ *
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ * @param timeout Transmit and receive timeout in milliseconds.
+ * @return Zero on success, negative error code otherwise.
+ */
+int pmc_agent_query_utc_offset(struct pmc_agent *agent, int timeout);
+
/**
* Sets the TAI-UTC offset.
* @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
--
2.25.1

View File

@ -0,0 +1,244 @@
From acdf74df9fa69b81c1e9332f10d4efcd3e9bae48 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 17:23:29 -0300
Subject: [PATCH 28/47] pmc_agent: Convert the method that queries the port
properties.
Prefix the function with the module name and correct the return code
semantics.
The active word in the function's name is "query" rather that "get" in
order to distinguish methods that send and receive over the network
from those that merely return a cached value.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
[commit ac7d69bbc476b94d76e5cee4992b9682f003feaf upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 41 +++++++++++++++--------------
pmc_agent.c | 74 ++++++++++++++++++++++++++---------------------------
pmc_agent.h | 22 +++++++++++++---
3 files changed, 78 insertions(+), 59 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 78d662b..32e6e13 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -296,8 +296,7 @@ static struct port *port_add(struct phc2sys_private *priv, unsigned int number,
static void clock_reinit(struct phc2sys_private *priv, struct clock *clock,
int new_state)
{
- int phc_index = -1, phc_switched = 0;
- int state, timestamping, ret = -1;
+ int err = -1, phc_index = -1, phc_switched = 0, state, timestamping;
struct port *p;
struct servo *servo;
struct sk_ts_info ts_info;
@@ -305,16 +304,19 @@ static void clock_reinit(struct phc2sys_private *priv, struct clock *clock,
clockid_t clkid = CLOCK_INVALID;
LIST_FOREACH(p, &priv->ports, list) {
- if (p->clock == clock) {
- ret = run_pmc_port_properties(priv->node, 1000, p->number,
- &state, &timestamping,
- iface);
- if (ret > 0)
- p->state = normalize_state(state);
+ if (p->clock != clock) {
+ continue;
+ }
+ err = pmc_agent_query_port_properties(priv->node, 1000,
+ p->number, &state,
+ &timestamping, iface);
+ if (!err) {
+ p->state = normalize_state(state);
}
+ break;
}
- if (ret > 0 && timestamping != TS_SOFTWARE) {
+ if (!err && timestamping != TS_SOFTWARE) {
/* Check if device changed */
if (strcmp(clock->device, iface)) {
free(clock->device);
@@ -852,12 +854,12 @@ static int phc2sys_recv_subscribed(void *context, struct ptp_message *msg,
static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
{
- struct port *port;
- struct clock *clock;
- int number_ports, res;
- unsigned int i;
+ int err, number_ports, res;
int state, timestamping;
char iface[IFNAMSIZ];
+ struct clock *clock;
+ struct port *port;
+ unsigned int i;
while (1) {
if (!is_running())
@@ -877,20 +879,21 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
return -1;
}
- res = pmc_agent_subscribe(priv->node, 1000);
- if (res) {
+ err = pmc_agent_subscribe(priv->node, 1000);
+ if (err) {
pr_err("failed to subscribe");
return -1;
}
for (i = 1; i <= number_ports; i++) {
- res = run_pmc_port_properties(priv->node, 1000, i, &state,
- &timestamping, iface);
- if (res == -1) {
+ err = pmc_agent_query_port_properties(priv->node, 1000, i,
+ &state, &timestamping,
+ iface);
+ if (err == -ENODEV) {
/* port does not exist, ignore the port */
continue;
}
- if (res <= 0) {
+ if (err) {
pr_err("failed to get port properties");
return -1;
}
diff --git a/pmc_agent.c b/pmc_agent.c
index 7a57a2f..cc729ab 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -251,43 +251,6 @@ void run_pmc_events(struct pmc_agent *node)
run_pmc(node, 0, -1, &msg);
}
-int run_pmc_port_properties(struct pmc_agent *node, int timeout,
- unsigned int port, int *state,
- int *tstamping, char *iface)
-{
- struct ptp_message *msg;
- int res, len;
- struct port_properties_np *ppn;
-
- pmc_target_port(node->pmc, port);
- while (1) {
- res = run_pmc(node, timeout, TLV_PORT_PROPERTIES_NP, &msg);
- if (res <= 0)
- goto out;
-
- ppn = management_tlv_data(msg);
- if (ppn->portIdentity.portNumber != port) {
- msg_put(msg);
- continue;
- }
-
- *state = ppn->port_state;
- *tstamping = ppn->timestamping;
- len = ppn->interface.length;
- if (len > IFNAMSIZ - 1)
- len = IFNAMSIZ - 1;
- memcpy(iface, ppn->interface.text, len);
- iface[len] = '\0';
-
- msg_put(msg);
- res = 1;
- break;
- }
-out:
- pmc_target_all(node->pmc);
- return res;
-}
-
int run_pmc_clock_identity(struct pmc_agent *node, int timeout)
{
struct ptp_message *msg;
@@ -354,6 +317,43 @@ int pmc_agent_get_sync_offset(struct pmc_agent *agent)
return agent->sync_offset;
}
+int pmc_agent_query_port_properties(struct pmc_agent *node, int timeout,
+ unsigned int port, int *state,
+ int *tstamping, char *iface)
+{
+ struct port_properties_np *ppn;
+ struct ptp_message *msg;
+ int res, len;
+
+ pmc_target_port(node->pmc, port);
+ while (1) {
+ res = run_pmc(node, timeout, TLV_PORT_PROPERTIES_NP, &msg);
+ if (is_run_pmc_error(res)) {
+ goto out;
+ }
+ ppn = management_tlv_data(msg);
+ if (ppn->portIdentity.portNumber != port) {
+ msg_put(msg);
+ continue;
+ }
+ *state = ppn->port_state;
+ *tstamping = ppn->timestamping;
+ len = ppn->interface.length;
+ if (len > IFNAMSIZ - 1) {
+ len = IFNAMSIZ - 1;
+ }
+ memcpy(iface, ppn->interface.text, len);
+ iface[len] = '\0';
+
+ msg_put(msg);
+ res = 0;
+ break;
+ }
+out:
+ pmc_target_all(node->pmc);
+ return run_pmc_err2errno(res);
+}
+
int pmc_agent_query_utc_offset(struct pmc_agent *node, int timeout)
{
struct timePropertiesDS *tds;
diff --git a/pmc_agent.h b/pmc_agent.h
index 44326d2..ea37bf9 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -37,9 +37,6 @@ int run_pmc_clock_identity(struct pmc_agent *agent, int timeout);
int run_pmc_wait_sync(struct pmc_agent *agent, int timeout);
int run_pmc_get_number_ports(struct pmc_agent *agent, int timeout);
void run_pmc_events(struct pmc_agent *agent);
-int run_pmc_port_properties(struct pmc_agent *agent, int timeout,
- unsigned int port, int *state,
- int *tstamping, char *iface);
/**
* Creates an instance of a PMC agent.
@@ -73,6 +70,25 @@ int pmc_agent_get_leap(struct pmc_agent *agent);
*/
int pmc_agent_get_sync_offset(struct pmc_agent *agent);
+/**
+ * Queries the port properties of a given port from the ptp4l service.
+ *
+ * In addition:
+ *
+ * - The port state notification callback might be invoked.
+ *
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ * @param timeout Transmit and receive timeout in milliseconds.
+ * @param port The port index of interest.
+ * @param state Buffer to hold the returned port state.
+ * @param tstamping Buffer to hold the returned time stamping flavor.
+ * @param iface Buffer to hold the returned interface name.
+ * @return Zero on success, negative error code otherwise.
+ */
+int pmc_agent_query_port_properties(struct pmc_agent *agent, int timeout,
+ unsigned int port, int *state,
+ int *tstamping, char *iface);
+
/**
* Queries the TAI-UTC offset and the current leap adjustment from the
* ptp4l service.
--
2.25.1

View File

@ -0,0 +1,183 @@
From 3e6dd047083625ca03df9b4bbdc781e7dd079ff2 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 17:29:30 -0300
Subject: [PATCH 29/47] pmc_agent: Generalize the method that queries the local
clock identity.
When started in automatic mode, the phc2sys program first queries the
local clock identification and then the number of ports immediately
afterwords. However, both of those values come from the default data
set. Make code both simpler and more efficient by caching the entire
data set inside of the agent.
A subsequent patch will fix the run_pmc_get_number_ports() method to
return the cached result.
The active word in the function's name is "query" rather that "get" in
order to distinguish methods that send and receive over the network
from those that merely return a cached value.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
[commit 919703eb06b7ee9679308597e01e1da0162736d7 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 20 +++++++++++---------
pmc_agent.c | 46 +++++++++++++++++++++++-----------------------
pmc_agent.h | 15 ++++++++++++++-
3 files changed, 48 insertions(+), 33 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 32e6e13..0f33630 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -854,23 +854,25 @@ static int phc2sys_recv_subscribed(void *context, struct ptp_message *msg,
static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
{
- int err, number_ports, res;
- int state, timestamping;
+ int err, number_ports, state, timestamping;
char iface[IFNAMSIZ];
struct clock *clock;
struct port *port;
unsigned int i;
while (1) {
- if (!is_running())
+ if (!is_running()) {
return -1;
- res = run_pmc_clock_identity(priv->node, 1000);
- if (res < 0)
- return -1;
- if (res > 0)
+ }
+ err = pmc_agent_query_dds(priv->node, 1000);
+ if (!err) {
break;
- /* res == 0, timeout */
- pr_notice("Waiting for ptp4l...");
+ }
+ if (err == -ETIMEDOUT) {
+ pr_notice("Waiting for ptp4l...");
+ } else {
+ return -1;
+ }
}
number_ports = run_pmc_get_number_ports(priv->node, 1000);
diff --git a/pmc_agent.c b/pmc_agent.c
index cc729ab..51023d1 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -38,8 +38,8 @@ struct pmc_agent {
struct pmc *pmc;
uint64_t pmc_last_update;
- struct ClockIdentity clock_identity;
- int clock_identity_set;
+ struct defaultDS dds;
+ bool dds_valid;
int leap;
int pmc_ds_requested;
bool stay_subscribed;
@@ -63,10 +63,11 @@ static void send_subscription(struct pmc_agent *node)
static int check_clock_identity(struct pmc_agent *node, struct ptp_message *msg)
{
- if (!node->clock_identity_set)
+ if (!node->dds_valid) {
return 1;
- return cid_eq(&node->clock_identity,
- &msg->header.sourcePortIdentity.clockIdentity);
+ }
+ return cid_eq(&node->dds.clockIdentity,
+ &msg->header.sourcePortIdentity.clockIdentity);
}
static int is_msg_mgt(struct ptp_message *msg)
@@ -251,24 +252,6 @@ void run_pmc_events(struct pmc_agent *node)
run_pmc(node, 0, -1, &msg);
}
-int run_pmc_clock_identity(struct pmc_agent *node, int timeout)
-{
- struct ptp_message *msg;
- struct defaultDS *dds;
- int res;
-
- res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- dds = (struct defaultDS *) management_tlv_data(msg);
- memcpy(&node->clock_identity, &dds->clockIdentity,
- sizeof(struct ClockIdentity));
- node->clock_identity_set = 1;
- msg_put(msg);
- return 1;
-}
-
int init_pmc_node(struct config *cfg, struct pmc_agent *node, const char *uds,
pmc_node_recv_subscribed_t *recv_subscribed, void *context)
{
@@ -317,6 +300,23 @@ int pmc_agent_get_sync_offset(struct pmc_agent *agent)
return agent->sync_offset;
}
+int pmc_agent_query_dds(struct pmc_agent *node, int timeout)
+{
+ struct ptp_message *msg;
+ struct defaultDS *dds;
+ int res;
+
+ res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
+ if (is_run_pmc_error(res)) {
+ return run_pmc_err2errno(res);
+ }
+ dds = (struct defaultDS *) management_tlv_data(msg);
+ memcpy(&node->dds, dds, sizeof(node->dds));
+ node->dds_valid = true;
+ msg_put(msg);
+ return 0;
+}
+
int pmc_agent_query_port_properties(struct pmc_agent *node, int timeout,
unsigned int port, int *state,
int *tstamping, char *iface)
diff --git a/pmc_agent.h b/pmc_agent.h
index ea37bf9..9d8bd1c 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -33,7 +33,6 @@ typedef int pmc_node_recv_subscribed_t(void *context, struct ptp_message *msg,
int init_pmc_node(struct config *cfg, struct pmc_agent *agent, const char *uds,
pmc_node_recv_subscribed_t *recv_subscribed, void *context);
-int run_pmc_clock_identity(struct pmc_agent *agent, int timeout);
int run_pmc_wait_sync(struct pmc_agent *agent, int timeout);
int run_pmc_get_number_ports(struct pmc_agent *agent, int timeout);
void run_pmc_events(struct pmc_agent *agent);
@@ -70,6 +69,20 @@ int pmc_agent_get_leap(struct pmc_agent *agent);
*/
int pmc_agent_get_sync_offset(struct pmc_agent *agent);
+/**
+ * Queries the local clock's default data set from the ptp4l service.
+ * The result of the query will be cached inside of the agent.
+ *
+ * In addition:
+ *
+ * - The port state notification callback might be invoked.
+ *
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ * @param timeout Transmit and receive timeout in milliseconds.
+ * @return Zero on success, negative error code otherwise.
+ */
+int pmc_agent_query_dds(struct pmc_agent *agent, int timeout);
+
/**
* Queries the port properties of a given port from the ptp4l service.
*
--
2.25.1

View File

@ -0,0 +1,106 @@
From d3b877cae9576beddb00d4c5db67bf49c944b222 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 17:30:57 -0300
Subject: [PATCH 30/47] pmc_agent: Simplify the method that gets of the number
of local ports.
The number of ports is already available in the cached default data
set. Use it directly.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
[commit 6bc9eb81dd254d90b5fe059684271b9beebf6b9b upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 2 +-
pmc_agent.c | 24 ++++++++----------------
pmc_agent.h | 11 ++++++++++-
3 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 0f33630..569544e 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -875,7 +875,7 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
}
}
- number_ports = run_pmc_get_number_ports(priv->node, 1000);
+ number_ports = pmc_agent_get_number_ports(priv->node);
if (number_ports <= 0) {
pr_err("failed to get number of ports");
return -1;
diff --git a/pmc_agent.c b/pmc_agent.c
index 51023d1..aa2347d 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -229,22 +229,6 @@ int run_pmc_wait_sync(struct pmc_agent *node, int timeout)
}
}
-int run_pmc_get_number_ports(struct pmc_agent *node, int timeout)
-{
- struct ptp_message *msg;
- int res;
- struct defaultDS *dds;
-
- res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- dds = (struct defaultDS *) management_tlv_data(msg);
- res = dds->numberPorts;
- msg_put(msg);
- return res;
-}
-
void run_pmc_events(struct pmc_agent *node)
{
struct ptp_message *msg;
@@ -300,6 +284,14 @@ int pmc_agent_get_sync_offset(struct pmc_agent *agent)
return agent->sync_offset;
}
+int pmc_agent_get_number_ports(struct pmc_agent *node)
+{
+ if (!node->dds_valid) {
+ return -1;
+ }
+ return node->dds.numberPorts;
+}
+
int pmc_agent_query_dds(struct pmc_agent *node, int timeout)
{
struct ptp_message *msg;
diff --git a/pmc_agent.h b/pmc_agent.h
index 9d8bd1c..f0e2c7a 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -34,7 +34,6 @@ typedef int pmc_node_recv_subscribed_t(void *context, struct ptp_message *msg,
int init_pmc_node(struct config *cfg, struct pmc_agent *agent, const char *uds,
pmc_node_recv_subscribed_t *recv_subscribed, void *context);
int run_pmc_wait_sync(struct pmc_agent *agent, int timeout);
-int run_pmc_get_number_ports(struct pmc_agent *agent, int timeout);
void run_pmc_events(struct pmc_agent *agent);
/**
@@ -62,6 +61,16 @@ void pmc_agent_disable(struct pmc_agent *agent);
*/
int pmc_agent_get_leap(struct pmc_agent *agent);
+/**
+ * Gets the number of local ports from the default data set. Users
+ * should first call pmc_agent_query_dds() before invoking this
+ * function.
+ *
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ * @return The non-negative number of ports, or -1 if unknown.
+ */
+int pmc_agent_get_number_ports(struct pmc_agent *agent);
+
/**
* Gets the TAI-UTC offset.
* @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
--
2.25.1

View File

@ -0,0 +1,57 @@
From 156728d14591dd2b3131bcff49959e806523c1bb Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 17:32:27 -0300
Subject: [PATCH 31/47] pmc_agent: Let the update method poll for push events.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
[commit c4a5eef1f4763805e6e2a2d25eb1d436018d4745 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
pmc_agent.c | 3 +++
pmc_agent.h | 5 +++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/pmc_agent.c b/pmc_agent.c
index aa2347d..6e6627d 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -390,6 +390,7 @@ int pmc_agent_subscribe(struct pmc_agent *node, int timeout)
int pmc_agent_update(struct pmc_agent *node)
{
+ struct ptp_message *msg;
struct timespec tp;
uint64_t ts;
@@ -411,6 +412,8 @@ int pmc_agent_update(struct pmc_agent *node)
}
}
+ run_pmc(node, 0, -1, &msg);
+
return 0;
}
diff --git a/pmc_agent.h b/pmc_agent.h
index f0e2c7a..dd34d30 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -141,11 +141,12 @@ void pmc_agent_set_sync_offset(struct pmc_agent *agent, int offset);
int pmc_agent_subscribe(struct pmc_agent *agent, int timeout);
/**
- * Queries the local ptp4l instance to update the TAI-UTC offset and
- * the current leap second flags.
+ * Polls for push notifications from the local ptp4l service.
*
* In addition:
*
+ * - Queries the local ptp4l instance to update the TAI-UTC offset and
+ * the current leap second flags.
* - Any active port state subscription will be renewed.
* - The port state notification callback might be invoked.
*
--
2.25.1

View File

@ -0,0 +1,37 @@
From 0e504e57af6c576202bbe1abe5a99eb24a981b73 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 17:51:10 -0300
Subject: [PATCH 32/47] phc2sys: Fix regression in the automatic mode.
Commit ac7d69bbc476 ("pmc_agent: Convert the method that queries the
port properties.") had the well meant intention of the cleaning up the
error code semantics of the port properties query function. However,
that commit mixed up the normal, external semantics of zero meaning
success with the internal semantics where zero is an error. Correct
the issue by replacing the hard coded number with the proper macro.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Fixes: ac7d69bbc476 ("pmc_agent: Convert the method that queries the port properties.")
[commit 0fb1be2f5c4d6905f33a2b1c31e7496d52296748 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
pmc_agent.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pmc_agent.c b/pmc_agent.c
index 6e6627d..623f300 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -338,7 +338,7 @@ int pmc_agent_query_port_properties(struct pmc_agent *node, int timeout,
iface[len] = '\0';
msg_put(msg);
- res = 0;
+ res = RUN_PMC_OKAY;
break;
}
out:
--
2.25.1

View File

@ -0,0 +1,188 @@
From 06a6734e3350e4020b4bb7b24a15d43aa42b4ca7 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 17:57:11 -0300
Subject: [PATCH 33/47] Implement push notification for TIME_STATUS_NP
Subscribers to NOTIFY_TIME_SYNC will be notified on every clock
synchronization.
[ RC:
- Don't subscribe this in pmc_agent.
- Use stdbool/stdint types in event_bitmask_get/set. ]
Signed-off-by: Juergen Werner <pogojotz@gmx.net>
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
[commit 6d7c090706e76af334185ffcec9cc56d0570e215 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
clock.c | 14 +++++++++-----
notification.h | 22 ++++++++++++++++++++++
pmc.c | 6 ++++--
pmc_agent.c | 2 +-
pmc_common.c | 23 +++++++++++++++--------
5 files changed, 51 insertions(+), 16 deletions(-)
diff --git a/clock.c b/clock.c
index 437cd1c..f048771 100644
--- a/clock.c
+++ b/clock.c
@@ -243,13 +243,11 @@ static void clock_prune_subscriptions(struct clock *c)
void clock_send_notification(struct clock *c, struct ptp_message *msg,
enum notification event)
{
- unsigned int event_pos = event / 8;
- uint8_t mask = 1 << (event % 8);
struct port *uds = c->uds_port;
struct clock_subscriber *s;
LIST_FOREACH(s, &c->subscribers, list) {
- if (!(s->events[event_pos] & mask))
+ if (!event_bitmask_get(s->events, event))
continue;
/* send event */
msg->header.sequenceId = htons(s->sequenceId);
@@ -1501,7 +1499,9 @@ void clock_notify_event(struct clock *c, enum notification event)
int id;
switch (event) {
- /* set id */
+ case NOTIFY_TIME_SYNC:
+ id = TLV_TIME_STATUS_NP;
+ break;
default:
return;
}
@@ -1731,7 +1731,9 @@ enum servo_state clock_synchronize(struct clock *c, tmv_t ingress, tmv_t origin)
c->cur.offsetFromMaster = tmv_to_TimeInterval(c->master_offset);
if (c->free_running) {
- return clock_no_adjust(c, ingress, origin);
+ state = clock_no_adjust(c, ingress, origin);
+ clock_notify_event(c, NOTIFY_TIME_SYNC);
+ return state;
}
offset = tmv_to_nanoseconds(c->master_offset);
@@ -1777,6 +1779,8 @@ enum servo_state clock_synchronize(struct clock *c, tmv_t ingress, tmv_t origin)
tmv_to_nanoseconds(c->path_delay));
}
+ clock_notify_event(c, NOTIFY_TIME_SYNC);
+
return state;
}
diff --git a/notification.h b/notification.h
index 47c9b56..115f864 100644
--- a/notification.h
+++ b/notification.h
@@ -20,8 +20,30 @@
#ifndef HAVE_NOTIFICATION_H
#define HAVE_NOTIFICATION_H
+#include <stdbool.h>
+#include <stdint.h>
+
+static inline void event_bitmask_set(uint8_t *bitmask, unsigned int event,
+ bool value)
+{
+ unsigned int event_pos = event / 8;
+ uint8_t event_bit = 1 << (event % 8);
+
+ if (value) {
+ bitmask[event_pos] |= event_bit;
+ } else {
+ bitmask[event_pos] &= ~(event_bit);
+ }
+}
+
+static inline bool event_bitmask_get(uint8_t *bitmask, unsigned int event)
+{
+ return (bitmask[event / 8] & (1 << (event % 8))) ? true : false;
+}
+
enum notification {
NOTIFY_PORT_STATE,
+ NOTIFY_TIME_SYNC,
};
#endif
diff --git a/pmc.c b/pmc.c
index 65d1d61..3678800 100644
--- a/pmc.c
+++ b/pmc.c
@@ -387,9 +387,11 @@ static void pmc_show(struct ptp_message *msg, FILE *fp)
sen = (struct subscribe_events_np *) mgt->data;
fprintf(fp, "SUBSCRIBE_EVENTS_NP "
IFMT "duration %hu"
- IFMT "NOTIFY_PORT_STATE %s",
+ IFMT "NOTIFY_PORT_STATE %s"
+ IFMT "NOTIFY_TIME_SYNC %s",
sen->duration,
- (sen->bitmask[0] & 1 << NOTIFY_PORT_STATE) ? "on" : "off");
+ event_bitmask_get(sen->bitmask, NOTIFY_PORT_STATE) ? "on" : "off",
+ event_bitmask_get(sen->bitmask, NOTIFY_TIME_SYNC) ? "on" : "off");
break;
case TLV_SYNCHRONIZATION_UNCERTAIN_NP:
mtd = (struct management_tlv_datum *) mgt->data;
diff --git a/pmc_agent.c b/pmc_agent.c
index 623f300..37910b3 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -57,7 +57,7 @@ static void send_subscription(struct pmc_agent *node)
memset(&sen, 0, sizeof(sen));
sen.duration = PMC_SUBSCRIBE_DURATION;
- sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
+ event_bitmask_set(sen.bitmask, NOTIFY_PORT_STATE, TRUE);
pmc_send_set_action(node->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
}
diff --git a/pmc_common.c b/pmc_common.c
index a117904..c5cd992 100644
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -149,7 +149,8 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
struct management_tlv_datum mtd;
struct subscribe_events_np sen;
struct port_ds_np pnp;
- char onoff[4] = {0};
+ char onoff_port_state[4] = "off";
+ char onoff_time_status[4] = "off";
switch (action) {
case GET:
@@ -223,16 +224,22 @@ static void do_set_action(struct pmc *pmc, int action, int index, char *str)
case TLV_SUBSCRIBE_EVENTS_NP:
memset(&sen, 0, sizeof(sen));
cnt = sscanf(str, " %*s %*s "
- "duration %hu "
- "NOTIFY_PORT_STATE %3s ",
- &sen.duration, onoff);
- if (cnt != 2) {
- fprintf(stderr, "%s SET needs 2 values\n",
+ "duration %hu "
+ "NOTIFY_PORT_STATE %3s "
+ "NOTIFY_TIME_SYNC %3s ",
+ &sen.duration,
+ onoff_port_state,
+ onoff_time_status);
+ if (cnt != 3) {
+ fprintf(stderr, "%s SET needs 3 values\n",
idtab[index].name);
break;
}
- if (!strcasecmp(onoff, "on")) {
- sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
+ if (!strcasecmp(onoff_port_state, "on")) {
+ event_bitmask_set(sen.bitmask, NOTIFY_PORT_STATE, TRUE);
+ }
+ if (!strcasecmp(onoff_time_status, "on")) {
+ event_bitmask_set(sen.bitmask, NOTIFY_TIME_SYNC, TRUE);
}
pmc_send_set_action(pmc, code, &sen, sizeof(sen));
break;
--
2.25.1

View File

@ -0,0 +1,214 @@
From babbe47ab091071e16fcd527bf1aad06e5aec377 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 18:16:31 -0300
Subject: [PATCH 34/47] clock: Rename UDS variables to read-write.
In preparation for a new read-only UDS port, rename variables of the
current UDS port to make it clear it is read-write, as opposed to
read-only.
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
[commit 1b781a5a086571859b0cfba687706d8fdc764d7f upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
clock.c | 52 +++++++++++++++++++++++++++++-----------------------
1 file changed, 29 insertions(+), 23 deletions(-)
diff --git a/clock.c b/clock.c
index f048771..d653c33 100644
--- a/clock.c
+++ b/clock.c
@@ -95,7 +95,7 @@ struct clock {
struct foreign_clock *best;
struct ClockIdentity best_id;
LIST_HEAD(ports_head, port) ports;
- struct port *uds_port;
+ struct port *uds_rw_port;
struct pollfd *pollfd;
int pollfd_valid;
int nports; /* does not include the UDS port */
@@ -129,7 +129,7 @@ struct clock {
struct clock_stats stats;
int stats_interval;
struct clockcheck *sanity_check;
- struct interface *udsif;
+ struct interface *uds_rw_if;
LIST_HEAD(clock_subscribers_head, clock_subscriber) subscribers;
struct monitor *slave_event_monitor;
};
@@ -243,7 +243,7 @@ static void clock_prune_subscriptions(struct clock *c)
void clock_send_notification(struct clock *c, struct ptp_message *msg,
enum notification event)
{
- struct port *uds = c->uds_port;
+ struct port *uds = c->uds_rw_port;
struct clock_subscriber *s;
LIST_FOREACH(s, &c->subscribers, list) {
@@ -265,13 +265,13 @@ void clock_destroy(struct clock *c)
{
struct port *p, *tmp;
- interface_destroy(c->udsif);
+ interface_destroy(c->uds_rw_if);
clock_flush_subscriptions(c);
LIST_FOREACH_SAFE(p, &c->ports, list, tmp) {
clock_remove_port(c, p);
}
monitor_destroy(c->slave_event_monitor);
- port_close(c->uds_port);
+ port_close(c->uds_rw_port);
free(c->pollfd);
if (c->clkid != CLOCK_REALTIME) {
phc_close(c->clkid);
@@ -440,7 +440,7 @@ static int clock_management_fill_response(struct clock *c, struct port *p,
datalen = sizeof(*gsn);
break;
case TLV_SUBSCRIBE_EVENTS_NP:
- if (p != c->uds_port) {
+ if (p != c->uds_rw_port) {
/* Only the UDS port allowed. */
break;
}
@@ -782,7 +782,7 @@ static int forwarding(struct clock *c, struct port *p)
default:
break;
}
- if (p == c->uds_port && ps != PS_FAULTY) {
+ if (p == c->uds_rw_port && ps != PS_FAULTY) {
return 1;
}
return 0;
@@ -1042,20 +1042,20 @@ struct clock *clock_create(enum clock_type type, struct config *config,
/* Configure the UDS. */
uds_ifname = config_get_string(config, NULL, "uds_address");
- c->udsif = interface_create(uds_ifname);
- if (config_set_section_int(config, interface_name(c->udsif),
+ c->uds_rw_if = interface_create(uds_ifname);
+ if (config_set_section_int(config, interface_name(c->uds_rw_if),
"announceReceiptTimeout", 0)) {
return NULL;
}
- if (config_set_section_int(config, interface_name(c->udsif),
+ if (config_set_section_int(config, interface_name(c->uds_rw_if),
"delay_mechanism", DM_AUTO)) {
return NULL;
}
- if (config_set_section_int(config, interface_name(c->udsif),
+ if (config_set_section_int(config, interface_name(c->uds_rw_if),
"network_transport", TRANS_UDS)) {
return NULL;
}
- if (config_set_section_int(config, interface_name(c->udsif),
+ if (config_set_section_int(config, interface_name(c->uds_rw_if),
"delay_filter_length", 1)) {
return NULL;
}
@@ -1178,14 +1178,15 @@ struct clock *clock_create(enum clock_type type, struct config *config,
}
/* Create the UDS interface. */
- c->uds_port = port_open(phc_device, phc_index, timestamping, 0, c->udsif, c);
- if (!c->uds_port) {
+ c->uds_rw_port = port_open(phc_device, phc_index, timestamping, 0,
+ c->uds_rw_if, c);
+ if (!c->uds_rw_port) {
pr_err("failed to open the UDS port");
return NULL;
}
clock_fda_changed(c);
- c->slave_event_monitor = monitor_create(config, c->uds_port);
+ c->slave_event_monitor = monitor_create(config, c->uds_rw_port);
if (!c->slave_event_monitor) {
pr_err("failed to create slave event monitor");
return NULL;
@@ -1204,7 +1205,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
LIST_FOREACH(p, &c->ports, list) {
port_dispatch(p, EV_INITIALIZE, 0);
}
- port_dispatch(c->uds_port, EV_INITIALIZE, 0);
+ port_dispatch(c->uds_rw_port, EV_INITIALIZE, 0);
return c;
}
@@ -1312,7 +1313,7 @@ static void clock_check_pollfd(struct clock *c)
clock_fill_pollfd(dest, p);
dest += N_CLOCK_PFD;
}
- clock_fill_pollfd(dest, c->uds_port);
+ clock_fill_pollfd(dest, c->uds_rw_port);
c->pollfd_valid = 1;
}
@@ -1329,7 +1330,7 @@ static int clock_do_forward_mgmt(struct clock *c,
return 0;
/* Don't forward any requests to the UDS port. */
- if (out == c->uds_port) {
+ if (out == c->uds_rw_port) {
switch (management_action(msg)) {
case GET:
case SET:
@@ -1360,7 +1361,7 @@ static void clock_forward_mgmt_msg(struct clock *c, struct port *p, struct ptp_m
pr_err("port %d: management forward failed",
port_number(piter));
}
- if (clock_do_forward_mgmt(c, p, c->uds_port, msg, &msg_ready))
+ if (clock_do_forward_mgmt(c, p, c->uds_rw_port, msg, &msg_ready))
pr_err("uds port: management forward failed");
if (msg_ready) {
msg_post_recv(msg, pdulen);
@@ -1412,7 +1413,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
clock_management_send_error(p, msg, TLV_WRONG_LENGTH);
return changed;
}
- if (p != c->uds_port) {
+ if (p != c->uds_rw_port) {
/* Sorry, only allowed on the UDS port. */
clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
return changed;
@@ -1421,6 +1422,11 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
return changed;
break;
case COMMAND:
+ if (p != c->uds_rw_port) {
+ /* Sorry, only allowed on the UDS port. */
+ clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
+ return changed;
+ }
break;
default:
return changed;
@@ -1428,7 +1434,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
switch (mgt->id) {
case TLV_PORT_PROPERTIES_NP:
- if (p != c->uds_port) {
+ if (p != c->uds_rw_port) {
/* Only the UDS port allowed. */
clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
return 0;
@@ -1493,7 +1499,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
void clock_notify_event(struct clock *c, enum notification event)
{
- struct port *uds = c->uds_port;
+ struct port *uds = c->uds_rw_port;
struct PortIdentity pid = port_identity(uds);
struct ptp_message *msg;
int id;
@@ -1599,7 +1605,7 @@ int clock_poll(struct clock *c)
/* Check the UDS port. */
for (i = 0; i < N_POLLFD; i++) {
if (cur[i].revents & (POLLIN|POLLPRI)) {
- event = port_event(c->uds_port, i);
+ event = port_event(c->uds_rw_port, i);
if (EV_STATE_DECISION_EVENT == event) {
c->sde = 1;
}
--
2.25.1

View File

@ -0,0 +1,292 @@
From 4af24949b94eda84b4b74d77b9164cf3fe0eccf9 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 12 Jun 2023 18:18:29 -0300
Subject: [PATCH 35/47] clock: Add read-only UDS port for monitoring.
Add a second UDS port to allow untrusted applications to monitor ptp4l.
On this "read-only" UDS port disable non-GET actions and forwarding.
The path can be configured with the uds_ro_address option (default is
/var/run/ptp4lro).
Forwarding is disabled to limit the access to the local ptp4l instance.
Subscriptions are not enabled to prevent the applications from making a
large number of subscriptions or interfere with applications that have
access to the read-write UDS port.
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
[commit 6823e077b2466dcc3c7cbce8ab384b0ef9a62811 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
clock.c | 72 +++++++++++++++++++++++++++++++++++++--------
config.c | 1 +
configs/default.cfg | 1 +
ptp4l.8 | 6 ++++
4 files changed, 67 insertions(+), 13 deletions(-)
diff --git a/clock.c b/clock.c
index d653c33..869e35d 100644
--- a/clock.c
+++ b/clock.c
@@ -96,9 +96,10 @@ struct clock {
struct ClockIdentity best_id;
LIST_HEAD(ports_head, port) ports;
struct port *uds_rw_port;
+ struct port *uds_ro_port;
struct pollfd *pollfd;
int pollfd_valid;
- int nports; /* does not include the UDS port */
+ int nports; /* does not include the two UDS ports */
int last_port_number;
int sde;
int free_running;
@@ -130,6 +131,7 @@ struct clock {
int stats_interval;
struct clockcheck *sanity_check;
struct interface *uds_rw_if;
+ struct interface *uds_ro_if;
LIST_HEAD(clock_subscribers_head, clock_subscriber) subscribers;
struct monitor *slave_event_monitor;
};
@@ -266,12 +268,14 @@ void clock_destroy(struct clock *c)
struct port *p, *tmp;
interface_destroy(c->uds_rw_if);
+ interface_destroy(c->uds_ro_if);
clock_flush_subscriptions(c);
LIST_FOREACH_SAFE(p, &c->ports, list, tmp) {
clock_remove_port(c, p);
}
monitor_destroy(c->slave_event_monitor);
port_close(c->uds_rw_port);
+ port_close(c->uds_ro_port);
free(c->pollfd);
if (c->clkid != CLOCK_REALTIME) {
phc_close(c->clkid);
@@ -441,7 +445,7 @@ static int clock_management_fill_response(struct clock *c, struct port *p,
break;
case TLV_SUBSCRIBE_EVENTS_NP:
if (p != c->uds_rw_port) {
- /* Only the UDS port allowed. */
+ /* Only the UDS-RW port allowed. */
break;
}
sen = (struct subscribe_events_np *)tlv->data;
@@ -772,6 +776,10 @@ static int clock_utc_correct(struct clock *c, tmv_t ingress)
static int forwarding(struct clock *c, struct port *p)
{
enum port_state ps = port_state(p);
+
+ if (p == c->uds_ro_port)
+ return 0;
+
switch (ps) {
case PS_MASTER:
case PS_GRAND_MASTER:
@@ -816,7 +824,7 @@ static int clock_add_port(struct clock *c, const char *phc_device,
{
struct port *p, *piter, *lastp = NULL;
- if (clock_resize_pollfd(c, c->nports + 1)) {
+ if (clock_resize_pollfd(c, c->nports + 2)) {
return -1;
}
p = port_open(phc_device, phc_index, timestamping,
@@ -1041,6 +1049,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
}
/* Configure the UDS. */
+
uds_ifname = config_get_string(config, NULL, "uds_address");
c->uds_rw_if = interface_create(uds_ifname);
if (config_set_section_int(config, interface_name(c->uds_rw_if),
@@ -1060,6 +1069,25 @@ struct clock *clock_create(enum clock_type type, struct config *config,
return NULL;
}
+ uds_ifname = config_get_string(config, NULL, "uds_ro_address");
+ c->uds_ro_if = interface_create(uds_ifname);
+ if (config_set_section_int(config, interface_name(c->uds_ro_if),
+ "announceReceiptTimeout", 0)) {
+ return NULL;
+ }
+ if (config_set_section_int(config, interface_name(c->uds_ro_if),
+ "delay_mechanism", DM_AUTO)) {
+ return NULL;
+ }
+ if (config_set_section_int(config, interface_name(c->uds_ro_if),
+ "network_transport", TRANS_UDS)) {
+ return NULL;
+ }
+ if (config_set_section_int(config, interface_name(c->uds_ro_if),
+ "delay_filter_length", 1)) {
+ return NULL;
+ }
+
c->config = config;
c->free_running = config_get_int(config, NULL, "free_running");
c->freq_est_interval = config_get_int(config, NULL, "freq_est_interval");
@@ -1177,11 +1205,18 @@ struct clock *clock_create(enum clock_type type, struct config *config,
return NULL;
}
- /* Create the UDS interface. */
+ /* Create the UDS interfaces. */
+
c->uds_rw_port = port_open(phc_device, phc_index, timestamping, 0,
c->uds_rw_if, c);
if (!c->uds_rw_port) {
- pr_err("failed to open the UDS port");
+ pr_err("failed to open the UDS-RW port");
+ return NULL;
+ }
+ c->uds_ro_port = port_open(phc_device, phc_index, timestamping, 0,
+ c->uds_ro_if, c);
+ if (!c->uds_ro_port) {
+ pr_err("failed to open the UDS-RO port");
return NULL;
}
clock_fda_changed(c);
@@ -1206,6 +1241,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
port_dispatch(p, EV_INITIALIZE, 0);
}
port_dispatch(c->uds_rw_port, EV_INITIALIZE, 0);
+ port_dispatch(c->uds_ro_port, EV_INITIALIZE, 0);
return c;
}
@@ -1276,9 +1312,9 @@ static int clock_resize_pollfd(struct clock *c, int new_nports)
{
struct pollfd *new_pollfd;
- /* Need to allocate one whole extra block of fds for UDS. */
+ /* Need to allocate two whole extra blocks of fds for UDS ports. */
new_pollfd = realloc(c->pollfd,
- (new_nports + 1) * N_CLOCK_PFD *
+ (new_nports + 2) * N_CLOCK_PFD *
sizeof(struct pollfd));
if (!new_pollfd) {
return -1;
@@ -1314,6 +1350,8 @@ static void clock_check_pollfd(struct clock *c)
dest += N_CLOCK_PFD;
}
clock_fill_pollfd(dest, c->uds_rw_port);
+ dest += N_CLOCK_PFD;
+ clock_fill_pollfd(dest, c->uds_ro_port);
c->pollfd_valid = 1;
}
@@ -1329,7 +1367,8 @@ static int clock_do_forward_mgmt(struct clock *c,
if (in == out || !forwarding(c, out))
return 0;
- /* Don't forward any requests to the UDS port. */
+ /* Don't forward any requests to the UDS-RW port
+ (the UDS-RO port doesn't allow any forwarding). */
if (out == c->uds_rw_port) {
switch (management_action(msg)) {
case GET:
@@ -1414,7 +1453,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
return changed;
}
if (p != c->uds_rw_port) {
- /* Sorry, only allowed on the UDS port. */
+ /* Sorry, only allowed on the UDS-RW port. */
clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
return changed;
}
@@ -1423,7 +1462,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
break;
case COMMAND:
if (p != c->uds_rw_port) {
- /* Sorry, only allowed on the UDS port. */
+ /* Sorry, only allowed on the UDS-RW port. */
clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
return changed;
}
@@ -1435,7 +1474,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
switch (mgt->id) {
case TLV_PORT_PROPERTIES_NP:
if (p != c->uds_rw_port) {
- /* Only the UDS port allowed. */
+ /* Only the UDS-RW port allowed. */
clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
return 0;
}
@@ -1548,7 +1587,7 @@ int clock_poll(struct clock *c)
struct port *p;
clock_check_pollfd(c);
- cnt = poll(c->pollfd, (c->nports + 1) * N_CLOCK_PFD, -1);
+ cnt = poll(c->pollfd, (c->nports + 2) * N_CLOCK_PFD, -1);
if (cnt < 0) {
if (EINTR == errno) {
return 0;
@@ -1602,7 +1641,7 @@ int clock_poll(struct clock *c)
cur += N_CLOCK_PFD;
}
- /* Check the UDS port. */
+ /* Check the UDS ports. */
for (i = 0; i < N_POLLFD; i++) {
if (cur[i].revents & (POLLIN|POLLPRI)) {
event = port_event(c->uds_rw_port, i);
@@ -1611,6 +1650,13 @@ int clock_poll(struct clock *c)
}
}
}
+ cur += N_CLOCK_PFD;
+ for (i = 0; i < N_POLLFD; i++) {
+ if (cur[i].revents & (POLLIN|POLLPRI)) {
+ event = port_event(c->uds_ro_port, i);
+ /* sde is not expected on the UDS-RO port */
+ }
+ }
if (c->sde) {
handle_state_decision_event(c);
diff --git a/config.c b/config.c
index fea7f67..d45e948 100644
--- a/config.c
+++ b/config.c
@@ -323,6 +323,7 @@ struct config_item config_tab[] = {
PORT_ITEM_INT("udp_ttl", 1, 1, 255),
PORT_ITEM_INT("udp6_scope", 0x0E, 0x00, 0x0F),
GLOB_ITEM_STR("uds_address", "/var/run/ptp4l"),
+ GLOB_ITEM_STR("uds_ro_address", "/var/run/ptp4lro"),
PORT_ITEM_INT("unicast_listen", 0, 0, 1),
PORT_ITEM_INT("unicast_master_table", 0, 0, INT_MAX),
PORT_ITEM_INT("unicast_req_duration", 3600, 10, INT_MAX),
diff --git a/configs/default.cfg b/configs/default.cfg
index 8c19129..d5bab7d 100644
--- a/configs/default.cfg
+++ b/configs/default.cfg
@@ -90,6 +90,7 @@ p2p_dst_mac 01:80:C2:00:00:0E
udp_ttl 1
udp6_scope 0x0E
uds_address /var/run/ptp4l
+uds_ro_address /var/run/ptp4lro
#
# Default interface options
#
diff --git a/ptp4l.8 b/ptp4l.8
index b179b81..f9bd228 100644
--- a/ptp4l.8
+++ b/ptp4l.8
@@ -615,6 +615,12 @@ is only relevant with IPv6 transport. See RFC 4291. The default is
Specifies the address of the UNIX domain socket for receiving local
management messages. The default is /var/run/ptp4l.
.TP
+.B uds_ro_address
+Specifies the address of the second UNIX domain socket for receiving local
+management messages, which is restricted to GET actions and does not forward
+messages to other ports. Access to this socket can be given to untrusted
+applications for monitoring purposes. The default is /var/run/ptp4lro.
+.TP
.B dscp_event
Defines the Differentiated Services Codepoint (DSCP) to be used for PTP
event messages. Must be a value between 0 and 63. There are several media
--
2.25.1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,764 @@
From 2a6ddfe1b9700ce8e0c62da8a7a4f2edcd4e1cad Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Sun, 18 Jun 2023 20:58:34 -0300
Subject: [PATCH 37/47] Enhance phc2sys to accept multiple ptp4l inputs
A new configuration option called ha_enabled was created. When it is set 1
multiple ptp4l inputs are accepted and the high availability algorithms
are enabled.
In addition to ha_enabled 1 a set of interfaces must also be provided.
Each interface is one-to-one mapped to a clock source, and must be
associated to an unique ptp4l instance using the ha_uds_address
configuration option.
For example:
ha_enabled 1
[ens1f1]
ha_uds_address /var/run/ptp4l-ptp-inst1
[ens1f2]
ha_uds_address /var/run/ptp4l-ptp-inst2
A maximum of 128 interfaces is supported.
Regression: verify non HA phc2sys configuration
PASS: Verify auto configuration is still accepted.
PASS: Verify manual configuration with a single clock is still accepted.
PASS: Verify mix of manual and auto configuration is denied.
PASS: Verify manual configuration with zero clock sources is denied.
Test Plan: verify HA configuration
PASS: Verify HA is disabled by default.
PASS: Verify HA configuration with 1 or more clock source is accepted.
PASS: Verify ha_uds_address default value.
Reviewed-by: Cole Walker <cole.walker@windriver.com>
Reviewed-by: Andre Fernando Zanella Kantek <andrefernandozanella.kantek@windriver.com>
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
[commit 705fe12b294216c7b5797f48d83ff97fcc076294 upstream]
[commit e730f006cb56ac55932220c1afff5470de875200 upstream]
[commit df8fa0492771f6babb75254619337edb6041daea upstream]
[commit 0201340fa5abc17634bfb4d0b2a386d218d3095b upstream]
[commit dd7400f4eb548dfb2acfb6ebaf53a6d77b9c5da2 upstream]
[commit 904fb44ecebd448f9b2952dd287ac2b5db8249db upstream]
[commit 56dcd671d5241b589dc44b776fec9b2752496477 upstream]
[commit 7e5617afe8837b77629cc04c9e3abb38ae64678c upstream]
[commit 5ea8af40b8b5e4680d8a8e1a19482c28f95ce6b3 upstream]
[commit 3d38367a3151845ec543ab9125e2d0a0aefa2f56 upstream]
[commit 17a4d6805597fd6ddb911b8246e7b131a42f9191 upstream]
[commit 1650d972f4fe9bb39807536df2594d1a85aabf9c upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
config.c | 17 +++
config.h | 2 +
phc2sys.c | 337 +++++++++++++++++++++++++++++++++++++---------------
pmc_agent.c | 17 ---
pmc_agent.h | 21 +++-
uds.c | 19 ++-
6 files changed, 294 insertions(+), 119 deletions(-)
diff --git a/config.c b/config.c
index d45e948..b97e5d7 100644
--- a/config.c
+++ b/config.c
@@ -250,6 +250,8 @@ struct config_item config_tab[] = {
GLOB_ITEM_INT("G.8275.defaultDS.localPriority", 128, 1, UINT8_MAX),
PORT_ITEM_INT("G.8275.portDS.localPriority", 128, 1, UINT8_MAX),
GLOB_ITEM_INT("gmCapable", 1, 0, 1),
+ GLOB_ITEM_INT("ha_enabled", 0, 0, 1),
+ PORT_ITEM_STR("ha_uds_address", "/var/run/ptp4l"),
GLOB_ITEM_ENU("hwts_filter", HWTS_FILTER_NORMAL, hwts_filter_enu),
PORT_ITEM_INT("hybrid_e2e", 0, 0, 1),
PORT_ITEM_INT("ignore_source_id", 0, 0, 1),
@@ -996,6 +998,21 @@ char *config_get_string(struct config *cfg, const char *section,
return ci->val.s;
}
+unsigned int config_get_interfaces(struct config *cfg, char *interfaces[], unsigned int max)
+{
+ struct interface *iface = NULL;
+ unsigned int counter = 0;
+
+ STAILQ_FOREACH(iface, &cfg->interfaces, list) {
+ if (counter == max) {
+ pr_err("bug: too many interfaces!");
+ return (unsigned int)-1;
+ }
+ interfaces[counter++] = interface_name(iface);
+ }
+ return counter;
+}
+
int config_harmonize_onestep(struct config *cfg)
{
enum timestamp_type tstype = config_get_int(cfg, NULL, "time_stamping");
diff --git a/config.h b/config.h
index 14d2f64..645fb42 100644
--- a/config.h
+++ b/config.h
@@ -64,6 +64,8 @@ int config_get_int(struct config *cfg, const char *section,
char *config_get_string(struct config *cfg, const char *section,
const char *option);
+unsigned int config_get_interfaces(struct config *cfg, char *interfaces[], unsigned int max);
+
int config_harmonize_onestep(struct config *cfg);
static inline struct option *config_long_options(struct config *cfg)
diff --git a/phc2sys.c b/phc2sys.c
index c9fabd7..a4afe01 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -64,6 +64,12 @@
#define PHC_PPS_OFFSET_LIMIT 10000000
+#define MAX_SRC_CLOCKS 128
+
+#define PORT_INDEX_TO_PORT_ID(port, index) (((((unsigned int) port) & 0xFF) << 8) || (((unsigned int) index) & 0xFF))
+#define PORT_ID_TO_PORT(id) ((((unsigned int) id) >> 8) & 0xFF)
+#define PORT_ID_TO_INDEX(id) (((unsigned int) id) & 0xFF)
+
struct clock {
LIST_ENTRY(clock) list;
LIST_ENTRY(clock) dst_list;
@@ -85,6 +91,7 @@ struct clock {
struct stats *freq_stats;
struct stats *delay_stats;
struct clockcheck *sanity_check;
+ struct pmc_agent *node;
};
struct port {
@@ -103,7 +110,7 @@ struct phc2sys_private {
int forced_sync_offset;
int kernel_leap;
int state_changed;
- struct pmc_agent *node;
+ LIST_HEAD(pmc_agent_head, pmc_agent) pmc_agents;
LIST_HEAD(port_head, port) ports;
LIST_HEAD(clock_head, clock) clocks;
LIST_HEAD(dst_clock_head, clock) dst_clocks;
@@ -260,6 +267,18 @@ static struct port *port_get(struct phc2sys_private *priv, unsigned int number)
return NULL;
}
+static struct port *port_get_by_clock(struct phc2sys_private *priv, struct clock * clock)
+{
+ struct port *p, *port = NULL;
+ LIST_FOREACH(p, &priv->ports, list) {
+ if (p->clock == clock) {
+ port = p;
+ break;
+ }
+ }
+ return port;
+}
+
static struct port *port_add(struct phc2sys_private *priv, unsigned int number,
char *device)
{
@@ -293,6 +312,42 @@ static struct port *port_add(struct phc2sys_private *priv, unsigned int number,
return p;
}
+static struct pmc_agent *pmc_agent_get(struct phc2sys_private *priv, unsigned int index)
+{
+ struct pmc_agent *node;
+ LIST_FOREACH(node, &priv->pmc_agents, list) {
+ if (node->index == index) {
+ break;
+ }
+ }
+ return node;
+}
+
+static struct pmc_agent *pmc_agent_add(struct phc2sys_private *priv, unsigned int index)
+{
+ struct pmc_agent *node = pmc_agent_get(priv, index);
+ if (node)
+ return node;
+
+ node = pmc_agent_create();
+ if (!node) {
+ pr_err("failed to allocate memory for a pmc agent");
+ return NULL;
+ }
+
+ node->index = index;
+ LIST_INSERT_HEAD(&priv->pmc_agents, node, list);
+ return node;
+}
+
+static void pmc_agent_cleanup(struct phc2sys_private *priv)
+{
+ struct pmc_agent *node, *tmp;
+ LIST_FOREACH_SAFE(node, &priv->pmc_agents, list, tmp) {
+ pmc_agent_destroy(node);
+ }
+}
+
static void clock_reinit(struct phc2sys_private *priv, struct clock *clock,
int new_state)
{
@@ -302,12 +357,17 @@ static void clock_reinit(struct phc2sys_private *priv, struct clock *clock,
struct sk_ts_info ts_info;
char iface[IFNAMSIZ];
clockid_t clkid = CLOCK_INVALID;
+ struct pmc_agent *node;
+ unsigned int pmc_index;
LIST_FOREACH(p, &priv->ports, list) {
if (p->clock != clock) {
continue;
}
- err = pmc_agent_query_port_properties(priv->node, 1000,
+
+ pmc_index = PORT_ID_TO_INDEX(p->number);
+ node = pmc_agent_get(priv, pmc_index);
+ err = pmc_agent_query_port_properties(node, 1000,
p->number, &state,
&timestamping, iface);
if (!err) {
@@ -638,12 +698,13 @@ static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
int64_t pps_offset, phc_offset, phc_delay;
uint64_t pps_ts, phc_ts;
clockid_t src = priv->master->clkid;
+ struct pmc_agent *node = LIST_FIRST(&priv->pmc_agents);
priv->master->source_label = "pps";
if (src == CLOCK_INVALID) {
/* The sync offset can't be applied with PPS alone. */
- pmc_agent_set_sync_offset(priv->node, 0);
+ pmc_agent_set_sync_offset(node, 0);
} else {
enable_pps_output(priv->master->clkid);
}
@@ -674,7 +735,7 @@ static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
pps_offset = pps_ts - phc_ts;
}
- if (pmc_agent_update(priv->node) < 0)
+ if (pmc_agent_update(node) < 0)
continue;
update_clock(priv, clock, pps_offset, pps_ts, -1);
}
@@ -706,6 +767,7 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
uint64_t ts;
int64_t offset, delay;
int err;
+ struct pmc_agent *node = NULL;
interval.tv_sec = priv->phc_interval;
interval.tv_nsec = (priv->phc_interval - interval.tv_sec) * 1e9;
@@ -713,22 +775,28 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
while (is_running()) {
clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL);
- if (pmc_agent_update(priv->node) < 0) {
- continue;
- }
+ LIST_FOREACH(node, &priv->pmc_agents, list) {
+ if (pmc_agent_update(node) < 0) {
+ continue;
+ }
- if (subscriptions) {
- run_pmc_events(priv->node);
- if (priv->state_changed) {
- /* force getting offset, as it may have
- * changed after the port state change */
- if (pmc_agent_query_utc_offset(priv->node, 1000)) {
- pr_err("failed to get UTC offset");
- continue;
+ if (subscriptions) {
+ run_pmc_events(node);
+ if (priv->state_changed) {
+ /* force getting offset, as it may have
+ * changed after the port state change */
+ if (pmc_agent_query_utc_offset(node, 1000)) {
+ pr_err("failed to get UTC offset");
+ continue;
+ }
}
- reconfigure(priv);
}
}
+
+ if (subscriptions && priv->state_changed) {
+ reconfigure(priv);
+ }
+
if (!priv->master)
continue;
@@ -859,55 +927,65 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
struct clock *clock;
struct port *port;
unsigned int i;
+ struct pmc_agent *node = NULL;
+ unsigned int retries, port_number;
- while (1) {
- if (!is_running()) {
- return -1;
- }
- err = pmc_agent_query_dds(priv->node, 1000);
- if (!err) {
- break;
- }
- if (err == -ETIMEDOUT) {
- pr_notice("Waiting for ptp4l...");
- } else {
- return -1;
+ LIST_FOREACH(node, &priv->pmc_agents, list) {
+ retries = 0;
+ while(retries < 10) {
+ if (!is_running()) {
+ return -1;
+ }
+ err = pmc_agent_query_dds(node, 1000);
+ if (!err) {
+ break;
+ }
+ if (err == -ETIMEDOUT) {
+ pr_notice("Waiting for ptp4l...");
+ retries++;
+ } else {
+ return -1;
+ }
}
- }
- number_ports = pmc_agent_get_number_ports(priv->node);
- if (number_ports <= 0) {
- pr_err("failed to get number of ports");
- return -1;
- }
-
- err = pmc_agent_subscribe(priv->node, 1000);
- if (err) {
- pr_err("failed to subscribe");
- return -1;
- }
-
- for (i = 1; i <= number_ports; i++) {
- err = pmc_agent_query_port_properties(priv->node, 1000, i,
- &state, &timestamping,
- iface);
- if (err == -ENODEV) {
- /* port does not exist, ignore the port */
+ number_ports = pmc_agent_get_number_ports(node);
+ if (number_ports <= 0) {
+ pr_err("failed to get number of ports");
continue;
}
+
+ err = pmc_agent_subscribe(node, 1000);
if (err) {
- pr_err("failed to get port properties");
- return -1;
- }
- if (timestamping == TS_SOFTWARE) {
- /* ignore ports with software time stamping */
+ pr_err("failed to subscribe");
continue;
}
- port = port_add(priv, i, iface);
- if (!port)
- return -1;
- port->state = normalize_state(state);
+
+ for (i = 1; i <= number_ports; i++) {
+ err = pmc_agent_query_port_properties(node, 1000, i,
+ &state, &timestamping,
+ iface);
+ if (err == -ENODEV) {
+ /* port does not exist, ignore the port */
+ continue;
+ }
+ if (err) {
+ pr_err("failed to get port properties");
+ break;
+ }
+ if (timestamping == TS_SOFTWARE) {
+ /* ignore ports with software time stamping */
+ continue;
+ }
+ port_number = PORT_INDEX_TO_PORT_ID(i, node->index);
+ port = port_add(priv, port_number, iface);
+ if (!port)
+ return -1;
+ port->state = normalize_state(state);
+ /* map clock to pmc agent node */
+ port->clock->node = node;
+ }
}
+
if (LIST_EMPTY(&priv->clocks)) {
pr_err("no suitable ports available");
return -1;
@@ -926,9 +1004,11 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
}
/* get initial offset */
- if (pmc_agent_query_utc_offset(priv->node, 1000)) {
- pr_err("failed to get UTC offset");
- return -1;
+ LIST_FOREACH(node, &priv->pmc_agents, list) {
+ if (pmc_agent_query_utc_offset(node, 1000)) {
+ pr_err("failed to get UTC offset");
+ continue;
+ }
}
return 0;
}
@@ -937,9 +1017,12 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
int64_t offset, uint64_t ts)
{
- int clock_leap, node_leap = pmc_agent_get_leap(priv->node);
+ int clock_leap, node_leap;
+ struct pmc_agent *node = priv->master->node;
+
+ node_leap = pmc_agent_get_leap(node);
- clock->sync_offset = pmc_agent_get_sync_offset(priv->node);
+ clock->sync_offset = pmc_agent_get_sync_offset(node);
if ((node_leap || clock->leap_set) &&
clock->is_utc != priv->master->is_utc) {
@@ -980,7 +1063,7 @@ static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
}
}
- if (pmc_agent_utc_offset_traceable(priv->node) &&
+ if (pmc_agent_utc_offset_traceable(node) &&
clock->utc_offset_set != clock->sync_offset) {
if (clock->clkid == CLOCK_REALTIME)
sysclk_set_tai_offset(clock->sync_offset);
@@ -1034,7 +1117,8 @@ static void usage(char *progname)
int main(int argc, char *argv[])
{
- char *config = NULL, *dst_name = NULL, *progname, *src_name = NULL;
+ char *config = NULL, *dst_name = NULL, *progname;
+ char *src_names[MAX_SRC_CLOCKS];
char uds_local[MAX_IFNAME_SIZE + 1];
int autocfg = 0, c, domain_number = 0, index, ntpshm_segment, offset;
int pps_fd = -1, print_level = LOG_INFO, r = -1, rt = 0;
@@ -1047,7 +1131,11 @@ int main(int argc, char *argv[])
struct phc2sys_private priv = {
.phc_readings = 5,
.phc_interval = 1.0,
+ .master = NULL,
};
+ struct pmc_agent *node = NULL;
+ unsigned int i, src_cnt = 0;
+ int ha_enabled = 0;
handle_term_signals();
@@ -1055,8 +1143,8 @@ int main(int argc, char *argv[])
if (!cfg) {
return -1;
}
- priv.node = pmc_agent_create();
- if (!priv.node) {
+ node = pmc_agent_add(&priv, 0);
+ if (!node) {
return -1;
}
@@ -1102,7 +1190,11 @@ int main(int argc, char *argv[])
"'-i' has been deprecated. please use '-s' instead.\n");
/* fallthrough */
case 's':
- src_name = strdup(optarg);
+ if (src_cnt == MAX_SRC_CLOCKS) {
+ fprintf(stderr, "too many source clocks\n");
+ goto bad_usage;
+ }
+ src_names[src_cnt++] = optarg;
break;
case 'E':
if (!strcasecmp(optarg, "pi")) {
@@ -1153,7 +1245,7 @@ int main(int argc, char *argv[])
if (get_arg_val_i(c, optarg, &offset, INT_MIN, INT_MAX)) {
goto end;
}
- pmc_agent_set_sync_offset(priv.node, offset);
+ pmc_agent_set_sync_offset(node, offset);
priv.forced_sync_offset = -1;
break;
case 'L':
@@ -1241,12 +1333,22 @@ int main(int argc, char *argv[])
return c;
}
- if (autocfg && (src_name || dst_name || pps_fd >= 0 || wait_sync || priv.forced_sync_offset)) {
+ if (src_cnt == 0) {
+ /* get the source interface list from configuration file */
+ src_cnt = config_get_interfaces(cfg, src_names, MAX_SRC_CLOCKS);
+ if (src_cnt == (unsigned int)-1) {
+ fprintf(stderr, "too many interfaces in configuration file\n");
+ fprintf(stderr, "maximum number of interfaces is %u\n", MAX_SRC_CLOCKS);
+ goto bad_usage;
+ }
+ }
+
+ if (autocfg && (src_cnt > 0 || dst_name || pps_fd >= 0 || wait_sync || priv.forced_sync_offset)) {
fprintf(stderr,
"autoconfiguration cannot be mixed with manual config options.\n");
goto bad_usage;
}
- if (!autocfg && pps_fd < 0 && !src_name) {
+ if (!autocfg && pps_fd < 0 && src_cnt == 0) {
fprintf(stderr,
"autoconfiguration or valid source clock must be selected.\n");
goto bad_usage;
@@ -1282,7 +1384,7 @@ int main(int argc, char *argv[])
getpid());
if (autocfg) {
- if (init_pmc_node(cfg, priv.node, uds_local,
+ if (init_pmc_node(cfg, node, uds_local,
phc2sys_recv_subscribed, &priv))
goto end;
if (auto_init_ports(&priv, rt) < 0)
@@ -1291,15 +1393,26 @@ int main(int argc, char *argv[])
goto end;
}
- src = clock_add(&priv, src_name);
- free(src_name);
- if (!src) {
- fprintf(stderr,
- "valid source clock must be selected.\n");
+ ha_enabled = config_get_int(cfg, NULL, "ha_enabled");
+ if (!ha_enabled && src_cnt > 1) {
+ fprintf(stderr, "too many source clocks\n");
+ fprintf(stderr, "Use 'ha_enabled 1' to accept more than one source clocks\n");
goto bad_usage;
}
- src->state = PS_SLAVE;
- priv.master = src;
+
+ for (i = 0; i < src_cnt; ++i) {
+ src = clock_add(&priv, src_names[i]);
+ if (!src) {
+ fprintf(stderr,
+ "invalid source clock '%s'.\n", src_names[i]);
+ goto bad_usage;
+ }
+ src->state = PS_SLAVE;
+ /* select the first clock */
+ if (priv.master == NULL) {
+ priv.master = src;
+ }
+ }
dst = clock_add(&priv, dst_name ? dst_name : "CLOCK_REALTIME");
free(dst_name);
@@ -1320,32 +1433,58 @@ int main(int argc, char *argv[])
r = -1;
if (wait_sync) {
- if (init_pmc_node(cfg, priv.node, uds_local,
- phc2sys_recv_subscribed, &priv))
- goto end;
+ i = 0;
+ for (src = LIST_FIRST(&priv.clocks);
+ src != NULL;
+ src = LIST_NEXT(src, list)) {
- while (is_running()) {
- r = run_pmc_wait_sync(priv.node, 1000);
- if (r < 0)
- goto end;
- if (r > 0)
- break;
- else
- pr_notice("Waiting for ptp4l...");
- }
+ /* skip dst clock */
+ if (src == dst) {
+ continue;
+ }
- if (!priv.forced_sync_offset) {
- r = pmc_agent_query_utc_offset(priv.node, 1000);
- if (r) {
- pr_err("failed to get UTC offset");
+ if (i > 0) {
+ node = pmc_agent_add(&priv, i);
+ if (!node)
+ goto end;
+ }
+
+ /* uds local is formated '/var/run/phc2sys.<pid>.<source_interface>' */
+ snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d.%s",
+ getpid(), src->device);
+
+ if (init_pmc_node(cfg, node, uds_local,
+ phc2sys_recv_subscribed, &priv))
goto end;
+
+ /* map clock to pmc agent node */
+ src->node = node;
+
+ while (is_running()) {
+ r = run_pmc_wait_sync(node, 1000);
+ if (r < 0)
+ goto end;
+ if (r > 0)
+ break;
+ else
+ pr_notice("Waiting for ptp4l...");
+ }
+
+ if (!priv.forced_sync_offset) {
+ r = pmc_agent_query_utc_offset(node, 1000);
+ if (r) {
+ pr_err("failed to get UTC offset");
+ goto end;
+ }
+ }
+
+ if (priv.forced_sync_offset ||
+ (src->clkid != CLOCK_REALTIME && dst->clkid != CLOCK_REALTIME) ||
+ src->clkid == CLOCK_INVALID) {
+ pmc_agent_disable(node);
}
- }
- if (priv.forced_sync_offset ||
- (src->clkid != CLOCK_REALTIME && dst->clkid != CLOCK_REALTIME) ||
- src->clkid == CLOCK_INVALID) {
- pmc_agent_disable(priv.node);
+ ++i;
}
}
@@ -1359,7 +1498,7 @@ int main(int argc, char *argv[])
}
end:
- pmc_agent_destroy(priv.node);
+ pmc_agent_cleanup(&priv);
clock_cleanup(&priv);
port_cleanup(&priv);
config_destroy(cfg);
diff --git a/pmc_agent.c b/pmc_agent.c
index 3034f65..d13f569 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -34,23 +34,6 @@
* renewed.
*/
-struct pmc_agent {
- struct pmc *pmc;
- uint64_t pmc_last_update;
-
- struct defaultDS dds;
- bool dds_valid;
- int leap;
- int pmc_ds_requested;
- bool stay_subscribed;
- int sync_offset;
- int utc_offset_traceable;
-
- /* Callback on message reception */
- pmc_node_recv_subscribed_t *recv_subscribed;
- void *recv_context;
-};
-
static void send_subscription(struct pmc_agent *node)
{
struct subscribe_events_np sen;
diff --git a/pmc_agent.h b/pmc_agent.h
index dd34d30..5f25984 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -26,11 +26,28 @@
#include "pmc_common.h"
-struct pmc_agent;
-
typedef int pmc_node_recv_subscribed_t(void *context, struct ptp_message *msg,
int excluded);
+struct pmc_agent {
+ LIST_ENTRY(pmc_agent) list;
+ struct pmc *pmc;
+ uint64_t pmc_last_update;
+
+ struct defaultDS dds;
+ bool dds_valid;
+ int leap;
+ int pmc_ds_requested;
+ bool stay_subscribed;
+ int sync_offset;
+ int utc_offset_traceable;
+ unsigned int index;
+
+ /* Callback on message reception */
+ pmc_node_recv_subscribed_t *recv_subscribed;
+ void *recv_context;
+};
+
int init_pmc_node(struct config *cfg, struct pmc_agent *agent, const char *uds,
pmc_node_recv_subscribed_t *recv_subscribed, void *context);
int run_pmc_wait_sync(struct pmc_agent *agent, int timeout);
diff --git a/uds.c b/uds.c
index 641a672..57d4796 100644
--- a/uds.c
+++ b/uds.c
@@ -55,11 +55,13 @@ static int uds_close(struct transport *t, struct fdarray *fda)
static int uds_open(struct transport *t, struct interface *iface, struct fdarray *fda,
enum timestamp_type tt)
{
- char *uds_path = config_get_string(t->cfg, NULL, "uds_address");
+ char *uds_path = NULL;
struct uds *uds = container_of(t, struct uds, t);
const char *name = interface_name(iface);
struct sockaddr_un sa;
int fd, err;
+ char *point = NULL, *source = NULL;
+ int ha_enabled = config_get_int(t->cfg, NULL, "ha_enabled");
fd = socket(AF_LOCAL, SOCK_DGRAM, 0);
if (fd < 0) {
@@ -82,6 +84,21 @@ static int uds_open(struct transport *t, struct interface *iface, struct fdarray
/* For client use, pre load the server path. */
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_LOCAL;
+
+ if (!ha_enabled) {
+ uds_path = config_get_string(t->cfg, NULL, "uds_address");
+ } else {
+ /* The interface name is formated as '/var/run/phc2sys.<pid>.<source>'.
+ The last item is the source interface. */
+ point = strtok(name, ".");
+ while(point != NULL) {
+ source = point;
+ point = strtok(NULL, ".");
+ }
+
+ uds_path = config_get_string(t->cfg, source, "ha_uds_address");
+ }
+
strncpy(sa.sun_path, uds_path, sizeof(sa.sun_path) - 1);
uds->address.sun = sa;
uds->address.len = sizeof(sa);
--
2.25.1

View File

@ -0,0 +1,441 @@
From 142b30b1f996a5bd48f0edc9b5fb0f51af0b97fd Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Tue, 4 Jul 2023 17:27:50 -0300
Subject: [PATCH 38/47] Best source selection algorithm
An algorithm to select the best available clock and use it
as clock source.
A new set of configuration options was introduced to control
the clock requirements. The clock which fails to match the
requirements is discarded.
If a single clock matches the requirements, it is selected
as source.
If one or more clock match requirements, the clock with the highest
priority is selected. In case of tie, the 1st configured clock is
selected.
And if no clock match requirements, the clock with the best local
clock class is selected.
The ha_priority option is an interface setting used to configure
the clock priority. The lowest priority is 0 and the highest is 254,
and the default value is 0.
The ha_min_local_clockClass option is a global setting for the minimal
local clock class requirement. It ranges from 6 to 255 and its default
is 135.
The ha_min_clockAccuracy option is a global setting for the minimal
clock accuracy requirement. It ranges from 0x00 to 0xff and its default
is 0xfe.
The ha_min_offsetScaledLogVariance is a global setting for the minimal
offset scaled log variance. It ranges from 0 to 65535 and its default
is 65535.
The ha_timeTraceable is a global setting to enable or disable
the time traceable verification. When it's set the clock
which time is not traceable is discarded.
The ha_frequencyTraceable is a global setting to enable or disable
the frequency traceable verification. When it's set the clock
which frequency is not traceable is discarded.
The ha_min_gm_ClockClass is a global setting for the minimal
GM clock class requirement. It ranges from 6 to 255 and its
default is 135.
Test Plan: clock selection algorithm
PASS: Verify clock is discarded when local clock class doesn't match
requirements.
PASS: Verify clock is discarded when local clock accuracy doesn't match
requirements.
PASS: Verify clock is discarded when local offset scaled log variance doesn't
match requirements.
PASS: Verify clock is discarded when time traceable verification is set 1 and
the clock hasn't time traceable flag set.
PASS: Verify clock is discarded when frequency traceable verification is set 1
and the clock hasn't frequency traceable flag set.
PASS: Verify clock is discarded when GM clock class doesn't match requirements.
PASS: Verify clock is accepted when time traceable verification is set 0 even
when clock hasn't time traceable flag set.
PASS: Verify clock is accepted when frequency traceable verification is set 0
even when clock hasn't frequency traceable flag set.
PASS: Verify the highest priority clock is selected when one or more clock
match the requirements.
PASS: Verify the 1st configured clock is selected when one or more clock of the
same priority match the requirements.
PASS: Verify the clock with highest local clock class is selected when no clock
match the requirements.
Reviewed-by: Cole Walker <cole.walker@windriver.com>
Reviewed-by: Andre Fernando Zanella Kantek <andrefernandozanella.kantek@windriver.com>
[commit 1c10dd42b32388c2e708ad249dd1f193e7208155 upstream]
[commit 373c4fd50aaf52540d3eeb8f38f3e07307dea3a3 upstream]
[commit 279d5b6e7f88876ce00f1e87faba65c7cd6a90b0 upstream]
[commit 00d9ad798b1f700faefa0b5d4074c46f8ae87ef4 upstream]
[commit 1407a51d8000ca7df18ba67d611a761abb6f77f8 upstream]
[commit e0c1c7b64f7af8002092c01e023f524bfcc39f8b upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
config.c | 7 ++
phc2sys.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++
pmc_agent.c | 20 +++++
pmc_agent.h | 13 +++
4 files changed, 271 insertions(+)
diff --git a/config.c b/config.c
index b97e5d7..8ce5f6c 100644
--- a/config.c
+++ b/config.c
@@ -250,7 +250,14 @@ struct config_item config_tab[] = {
GLOB_ITEM_INT("G.8275.defaultDS.localPriority", 128, 1, UINT8_MAX),
PORT_ITEM_INT("G.8275.portDS.localPriority", 128, 1, UINT8_MAX),
GLOB_ITEM_INT("gmCapable", 1, 0, 1),
+ GLOB_ITEM_INT("ha_frequencyTraceable", 0, 0, 1),
GLOB_ITEM_INT("ha_enabled", 0, 0, 1),
+ GLOB_ITEM_INT("ha_min_clockAccuracy", 0xfe, 0, 0xff),
+ GLOB_ITEM_INT("ha_min_gm_ClockClass", 135, 6, 255),
+ GLOB_ITEM_INT("ha_min_local_clockClass", 135, 6, 255),
+ GLOB_ITEM_INT("ha_min_offsetScaledLogVariance", 65535, 0, 65535),
+ PORT_ITEM_INT("ha_priority", 0, 0, 255),
+ GLOB_ITEM_INT("ha_timeTraceable", 0, 0, 1),
PORT_ITEM_STR("ha_uds_address", "/var/run/ptp4l"),
GLOB_ITEM_ENU("hwts_filter", HWTS_FILTER_NORMAL, hwts_filter_enu),
PORT_ITEM_INT("hybrid_e2e", 0, 0, 1),
diff --git a/phc2sys.c b/phc2sys.c
index a4afe01..d148d62 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -73,6 +73,7 @@
struct clock {
LIST_ENTRY(clock) list;
LIST_ENTRY(clock) dst_list;
+ LIST_ENTRY(clock) good_list;
clockid_t clkid;
int phc_index;
int sysoff_method;
@@ -1073,6 +1074,232 @@ static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
return 0;
}
+static struct clock* startup_select_clock(struct phc2sys_private *priv, struct config *cfg)
+{
+ struct clock *clock = NULL, *best = NULL;
+ LIST_HEAD(head, clock) good_clocks;
+ int clock_priority, highest_priority;
+ int min_local_clock_class, min_gm_clock_class, clock_class, lowest_clock_class;
+ int err;
+ unsigned int min_clock_accuracy, min_offset_scaled_log_variance, retries;
+ bool check_time_traceable, check_freq_traceable;
+
+ LIST_INIT(&good_clocks);
+
+ /* get requirements */
+ min_local_clock_class = config_get_int(cfg, NULL, "ha_min_local_clockClass");
+ min_clock_accuracy = config_get_int(cfg, NULL, "ha_min_clockAccuracy");
+ min_offset_scaled_log_variance = config_get_int(cfg, NULL, "ha_min_offsetScaledLogVariance");
+ check_time_traceable = config_get_int(cfg, NULL, "ha_timeTraceable");
+ check_freq_traceable = config_get_int(cfg, NULL, "ha_frequencyTraceable");
+ min_gm_clock_class = config_get_int(cfg, NULL, "ha_min_gm_ClockClass");
+
+ /* save a list of available source clocks that matches requirements */
+ LIST_FOREACH(clock, &priv->clocks, list) {
+ /* check matching parameters */
+ pr_debug("clock %s state %d", clock->device, clock->state);
+
+ /* ignore the dst clock */
+ if (clock->state == PS_MASTER) {
+ pr_debug("clock %s discarded because state is PS_MASTER", clock->device);
+ continue;
+ }
+
+ /* sanity check */
+ if (clock->node == NULL) {
+ pr_debug("clock %s discarded because node is (null)", clock->device);
+ continue;
+ }
+
+ /* get Default Data Set */
+ retries = 0;
+ while(retries < 10) {
+ if (!is_running()) {
+ return NULL;
+ }
+ err = pmc_agent_query_dds(clock->node, 1000);
+ if (!err) {
+ break;
+ }
+ if (err == -ETIMEDOUT) {
+ pr_notice("Waiting for ptp4l...");
+ retries++;
+ } else {
+ return NULL;
+ }
+ }
+
+ if (!clock->node->dds_valid) {
+ pr_debug("clock %s discarded because dds is invalid", clock->device);
+ continue;
+ }
+
+ /* min clockClass
+ as lower clock class is better, accept sources which clock class
+ is lower then or equal to min local clock class and discard
+ the sources which clock class is higher than min local clock class.
+ */
+ clock_class = clock->node->dds.clockQuality.clockClass;
+ pr_debug("clock %s local clockClass %d", clock->device, clock_class);
+ if (clock_class > min_local_clock_class) {
+ pr_debug("clock %s discarded because local clock class %d > min clock class %d",
+ clock->device, clock_class, min_local_clock_class);
+ continue;
+ }
+
+ /* min clockAccuracy (lower is better) */
+ pr_debug("clock %s clockAccuracy 0x%x", clock->device,
+ clock->node->dds.clockQuality.clockAccuracy);
+ if (clock->node->dds.clockQuality.clockAccuracy > min_clock_accuracy) {
+ pr_debug("clock %s discarded because clock accuracy %d > min clock accuracy %d",
+ clock->device, clock->node->dds.clockQuality.clockAccuracy,
+ min_clock_accuracy);
+ continue;
+ }
+
+ /* min offset scaled log variance */
+ pr_debug("clock %s offsetScaledLogVariance 0x%x", clock->device,
+ clock->node->dds.clockQuality.offsetScaledLogVariance);
+ if (clock->node->dds.clockQuality.offsetScaledLogVariance > min_offset_scaled_log_variance) {
+ pr_debug("clock %s discarded because offset scaled log variance 0x%x > min offset 0x%x",
+ clock->device, clock->node->dds.clockQuality.offsetScaledLogVariance,
+ min_offset_scaled_log_variance);
+ continue;
+ }
+
+ if (check_time_traceable || check_freq_traceable) {
+ /* get Time Properties Data Set */
+ retries = 0;
+ while(retries < 10) {
+ if (!is_running()) {
+ return NULL;
+ }
+ err = pmc_agent_query_utc_offset(clock->node, 1000);
+ if (!err) {
+ break;
+ }
+ if (err == -ETIMEDOUT) {
+ pr_notice("Waiting for ptp4l...");
+ retries++;
+ } else {
+ return NULL;
+ }
+ }
+
+ if (err != 0) {
+ pr_debug("clock %s discarded because tds is invalid", clock->device);
+ continue;
+ }
+ }
+
+ /* is time traceable */
+ pr_debug("clock %s is time traceable %s", clock->device,
+ clock->node->utc_offset_traceable ? "yes" : "no");
+ if (check_time_traceable && !clock->node->utc_offset_traceable) {
+ pr_debug("clock %s discarded because time is not traceable", clock->device);
+ continue;
+ }
+
+ /* is frequency traceable */
+ pr_debug("clock %s is frequency traceable %s", clock->device,
+ clock->node->freq_traceable ? "yes" : "no");
+ if (check_freq_traceable && !clock->node->freq_traceable) {
+ pr_debug("clock %s discarded because frequency is not traceable", clock->device);
+ continue;
+ }
+
+ retries = 0;
+ while (retries < 10) {
+ if (!is_running()) {
+ return NULL;
+ }
+ err = pmc_agent_query_pds(clock->node, 1000);
+ if (!err) {
+ break;
+ }
+ if (err == -ETIMEDOUT) {
+ pr_notice("Waiting for ptp4l...");
+ retries++;
+ } else {
+ return NULL;
+ }
+ }
+
+ if (!clock->node->pds_valid) {
+ pr_debug("clock %s discarded because pds is invalid", clock->device);
+ continue;
+ }
+
+ /* min gm clock class - lower is better */
+ clock_class = clock->node->pds.grandmasterClockQuality.clockClass;
+ pr_debug("clock %s GM clockClass %d", clock->device, clock_class);
+ if (clock_class > min_gm_clock_class) {
+ pr_debug("clock %s discarded because GM clock class %d > min clock class %d",
+ clock->device, clock_class, min_gm_clock_class);
+ continue;
+ }
+
+ pr_notice("clock %s matched requirements", clock->device);
+
+ clock->good_list.le_next = NULL;
+ clock->good_list.le_prev = NULL;
+ LIST_INSERT_HEAD(&good_clocks, clock, good_list);
+ }
+
+ /* one or more sources match requirements, select highest priority */
+ highest_priority = 0;
+ LIST_FOREACH(clock, &good_clocks, good_list) {
+ clock_priority = config_get_int(cfg, clock->device, "ha_priority");
+
+ /* select highest priority clock
+ more than one clock with same priority, select first
+ don't select clocks with ha_priority 0 */
+ if (clock_priority > highest_priority) {
+ pr_notice("new highest ha priority clock %s ha_priority %d",
+ clock->device, clock_priority);
+ best = clock;
+ highest_priority = clock_priority;
+ }
+ }
+
+ /* no sources match requirements, choose best available clockClass */
+ if (!best) {
+ lowest_clock_class = 256;
+ LIST_FOREACH(clock, &priv->clocks, list) {
+ /* ignore the dst clock */
+ if (clock->state == PS_MASTER) {
+ continue;
+ }
+
+ /* get clock class */
+ clock_class = clock->node->dds.clockQuality.clockClass;
+ if (clock_class <= lowest_clock_class) {
+ pr_notice("new better clock class clock %s clock class %d",
+ clock->device, clock_class);
+ best = clock;
+ lowest_clock_class = clock_class;
+ }
+ }
+ }
+
+ /* no clock selected, select first clock configured (last in list) */
+ if (!best) {
+ LIST_FOREACH(clock, &priv->clocks, list) {
+ /* ignore the dst clock */
+ if (clock->state == PS_MASTER) {
+ continue;
+ }
+
+ best = clock;
+ }
+ }
+
+ if (best)
+ pr_notice("Best clock selected %s", best->device);
+
+ return best;
+};
+
static void usage(char *progname)
{
fprintf(stderr,
@@ -1486,6 +1713,10 @@ int main(int argc, char *argv[])
++i;
}
+
+ if (ha_enabled) {
+ startup_select_clock(&priv, cfg);
+ }
}
if (pps_fd >= 0) {
diff --git a/pmc_agent.c b/pmc_agent.c
index d13f569..534f483 100644
--- a/pmc_agent.c
+++ b/pmc_agent.c
@@ -351,15 +351,35 @@ int pmc_agent_query_utc_offset(struct pmc_agent *node, int timeout)
node->leap = 0;
node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
tds->flags & TIME_TRACEABLE;
+ node->freq_traceable = tds->flags & FREQ_TRACEABLE;
} else {
node->sync_offset = 0;
node->leap = 0;
node->utc_offset_traceable = 0;
+ node->freq_traceable = 0;
}
msg_put(msg);
return 0;
}
+int pmc_agent_query_pds(struct pmc_agent *node, int timeout)
+{
+ struct parentDS *pds;
+ struct ptp_message *msg;
+ int res;
+
+ res = run_pmc(node, timeout, MID_PARENT_DATA_SET, &msg);
+ if (is_run_pmc_error(res)) {
+ return run_pmc_err2errno(res);
+ }
+
+ pds = (struct parentDS *) management_tlv_data(msg);
+ memcpy(&node->pds, pds, sizeof(node->pds));
+ node->pds_valid = true;
+ msg_put(msg);
+ return 0;
+}
+
void pmc_agent_set_sync_offset(struct pmc_agent *agent, int offset)
{
agent->sync_offset = offset;
diff --git a/pmc_agent.h b/pmc_agent.h
index 5f25984..2bd7f02 100644
--- a/pmc_agent.h
+++ b/pmc_agent.h
@@ -41,7 +41,10 @@ struct pmc_agent {
bool stay_subscribed;
int sync_offset;
int utc_offset_traceable;
+ int freq_traceable;
unsigned int index;
+ struct parentDS pds;
+ bool pds_valid;
/* Callback on message reception */
pmc_node_recv_subscribed_t *recv_subscribed;
@@ -142,6 +145,16 @@ int pmc_agent_query_port_properties(struct pmc_agent *agent, int timeout,
*/
int pmc_agent_query_utc_offset(struct pmc_agent *agent, int timeout);
+/**
+ * Queries the parent data set from the ptp4l service.
+ * The result of the query will be cached inside of the agent.
+ *
+ * @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
+ * @param timeout Transmit and receive timeout in milliseconds.
+ * @return Zero on success, negative error code otherwise.
+ */
+int pmc_agent_query_pds(struct pmc_agent *agent, int timeout);
+
/**
* Sets the TAI-UTC offset.
* @param agent Pointer to a PMC instance obtained via @ref pmc_agent_create().
--
2.25.1

View File

@ -0,0 +1,256 @@
From 7d5061d971a8abc2ba8443edccde38e9a7a6f0ce Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Wed, 26 Jul 2023 15:08:15 -0300
Subject: [PATCH 40/47] Forced lock a clock source in configuration
To help on maintenance and debuging tasks was implemented a configuration
to forced lock to a single clock. It disables the automatic clock
selection algorithm and lock to a source interface.
When an interface is configured with maximum ha_priority (254)
the source selection is locked to it, regardless of its clock
status.
When more than one source clock is configured with ha_priority 254
selects the 1st interface in the configuration file.
Test plan: forced lock by configuration
PASS: Verify the clock source is forced lock to an interface, regardless
its state.
PASS: Verify the clock source remains locked event after change the clock
state.
PASS: Verify the 1st configured interface with priority 254 is selected
when multiple interfaces has the same priority.
Reviewed-by: Cole Walker <cole.walker@windriver.com>
Reviewed-by: Andre Fernando Zanella Kantek <andrefernandozanella.kantek@windriver.com>
[commit 9563a04ef76cda55f9f014150270dbd320ca4bc4 upstream]
[commit 655fe5e304386b4494d864638ca972c4bd892e52 upstream]
[commit 3200a16f4cbe2d125bf301827a24d3d01e7f1c70 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
config.c | 2 +-
phc2sys.c | 105 ++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 75 insertions(+), 32 deletions(-)
diff --git a/config.c b/config.c
index 1ad5157..dba1eef 100644
--- a/config.c
+++ b/config.c
@@ -256,7 +256,7 @@ struct config_item config_tab[] = {
GLOB_ITEM_INT("ha_min_gm_ClockClass", 135, 6, 255),
GLOB_ITEM_INT("ha_min_local_clockClass", 135, 6, 255),
GLOB_ITEM_INT("ha_min_offsetScaledLogVariance", 65535, 0, 65535),
- PORT_ITEM_INT("ha_priority", 0, 0, 255),
+ PORT_ITEM_INT("ha_priority", 0, 0, 254),
PORT_ITEM_INT("ha_stability_timer", 0, 0, INT_MAX),
GLOB_ITEM_INT("ha_timeTraceable", 0, 0, 1),
PORT_ITEM_STR("ha_uds_address", "/var/run/ptp4l"),
diff --git a/phc2sys.c b/phc2sys.c
index 152e783..0b3f724 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -64,6 +64,7 @@
#define PHC_PPS_OFFSET_LIMIT 10000000
+#define FORCED_SOURCE_CLOCK_PRIORITY 254
#define MAX_SRC_CLOCKS 128
#define PORT_INDEX_TO_PORT_ID(port, index) (((((unsigned int) port) & 0xFF) << 8) | (((unsigned int) index) & 0xFF))
@@ -121,6 +122,7 @@ struct phc2sys_private {
struct clock *better;
struct timespec stability_timer;
int default_sync;
+ int forced_source_clock;
};
static struct config *phc2sys_config;
@@ -998,6 +1000,29 @@ static int update_needed(struct clock *c)
return 0;
}
+/* check configuration if one of the source clocks is force locked to be active */
+static struct clock* ha_forced_source_clock(struct phc2sys_private *priv, struct config *cfg)
+{
+ int clock_priority;
+ struct clock *clock = NULL, *best = NULL;
+
+ LIST_FOREACH(clock, &priv->clocks, list) {
+ /* ignore the dst clock */
+ if (clock->state == PS_MASTER) {
+ continue;
+ }
+
+ clock_priority = config_get_int(cfg, clock->device, "ha_priority");
+ if (FORCED_SOURCE_CLOCK_PRIORITY == clock_priority) {
+ pr_info("HA automatic source selection is disabled by configuration");
+ priv->forced_source_clock = 1;
+ best = clock;
+ }
+ }
+
+ return best;
+}
+
static struct clock* ha_select_clock(struct phc2sys_private *priv, struct config *cfg)
{
int clock_priority, highest_priority;
@@ -1066,7 +1091,7 @@ static struct clock* ha_select_clock(struct phc2sys_private *priv, struct config
}
if (best)
- pr_notice("Best clock selected %s", best->device);
+ pr_notice("best clock available %s", best->device);
return best;
}
@@ -1121,7 +1146,7 @@ static struct clock* check_and_select_clock(struct phc2sys_private *priv, struct
return NULL;
}
- /* stability timer = 0 - change active */
+ /* stability timer equal 0 - change active */
stability_timer = config_get_int(cfg, NULL, "ha_stability_timer");
if (stability_timer == 0) {
pr_notice("new source clock selected %s", candidate->device);
@@ -1173,6 +1198,10 @@ static int do_loop(struct phc2sys_private *priv, struct config *cfg, int subscri
}
if (node->new_dds || node->new_tpds || node->new_pds) {
+ pr_debug("pmc agent index %d clock state changed by %s%s%s",
+ node->index, node->new_dds ? "new dds " : "",
+ node->new_tpds ? "new tpds " : "",
+ node->new_pds ? "new pds " : "");
priv->clock_state_changed = 1;
}
@@ -1194,30 +1223,38 @@ static int do_loop(struct phc2sys_private *priv, struct config *cfg, int subscri
}
if (ha_enabled) {
- if (priv->clock_state_changed) {
- clock = check_and_select_clock(priv, cfg);
- if (clock && clock != priv->master) {
- priv->master = clock;
- priv->better = NULL;
- priv->stability_timer.tv_sec = 0;
- priv->stability_timer.tv_nsec = 0;
+ if (priv->forced_source_clock) {
+ /* HA automatic clock selection is disabled */
+ if (priv->clock_state_changed) {
+ priv->clock_state_changed = 0;
+ reset_new_dataset_flags(priv);
}
+ } else {
+ if (priv->clock_state_changed) {
+ clock = check_and_select_clock(priv, cfg);
+ if (clock && clock != priv->master) {
+ priv->master = clock;
+ priv->better = NULL;
+ priv->stability_timer.tv_sec = 0;
+ priv->stability_timer.tv_nsec = 0;
+ }
- priv->clock_state_changed = 0;
- reset_new_dataset_flags(priv);
- }
+ priv->clock_state_changed = 0;
+ reset_new_dataset_flags(priv);
+ }
- if (priv->better) {
- /* has stability timer expired? */
- clock_gettime(CLOCK_REALTIME, &now);
- if ((now.tv_sec > priv->stability_timer.tv_sec) ||
- (now.tv_sec == priv->stability_timer.tv_sec &&
- now.tv_nsec > priv->stability_timer.tv_nsec)) {
- pr_notice("new source clock selected %s", priv->better->device);
- priv->master = priv->better;
- priv->better = NULL;
- priv->stability_timer.tv_sec = 0;
- priv->stability_timer.tv_nsec = 0;
+ if (priv->better) {
+ /* has stability timer expired? */
+ clock_gettime(CLOCK_REALTIME, &now);
+ if ((now.tv_sec > priv->stability_timer.tv_sec) ||
+ (now.tv_sec == priv->stability_timer.tv_sec &&
+ now.tv_nsec > priv->stability_timer.tv_nsec)) {
+ pr_notice("new source clock selected %s", priv->better->device);
+ priv->master = priv->better;
+ priv->better = NULL;
+ priv->stability_timer.tv_sec = 0;
+ priv->stability_timer.tv_nsec = 0;
+ }
}
}
}
@@ -1313,12 +1350,8 @@ static int phc2sys_recv_subscribed(struct pmc_agent *node, void *context, struct
struct phc2sys_private *priv = (struct phc2sys_private *) context;
int mgt_id, state;
struct portDS *pds;
- struct defaultDS *dds;
- struct parentDS *parentds;
- struct timePropertiesDS *tds;
struct port *port;
struct clock *clock;
- int utc_offset_traceable, freq_traceable;
mgt_id = management_tlv_id(msg);
if (mgt_id == excluded)
@@ -1563,6 +1596,7 @@ int main(int argc, char *argv[])
.master = NULL,
.better = NULL,
.stability_timer.tv_sec = 0,
+ .forced_source_clock = 0,
};
struct pmc_agent *node = NULL;
unsigned int i, src_cnt = 0;
@@ -1861,13 +1895,19 @@ int main(int argc, char *argv[])
goto bad_usage;
}
+ if (ha_enabled) {
+ src = ha_forced_source_clock(&priv, cfg);
+ if (src != NULL) {
+ pr_info("Only interface %s will be used as source clock", src->device);
+ priv.master = src;
+ }
+ }
+
r = -1;
if (wait_sync) {
i = 0;
- for (src = LIST_FIRST(&priv.clocks);
- src != NULL;
- src = LIST_NEXT(src, list)) {
+ LIST_FOREACH(src, &priv.clocks, list) {
/* skip dst clock */
if (src == dst) {
@@ -1890,6 +1930,8 @@ int main(int argc, char *argv[])
/* map clock to pmc agent node */
src->node = node;
+ pr_debug("pmc node index %d source clock %s initialized",
+ node->index, src->device);
while (is_running()) {
r = run_pmc_wait_sync(node, 1000);
@@ -1918,8 +1960,9 @@ int main(int argc, char *argv[])
++i;
}
- if (ha_enabled) {
+ if (ha_enabled && !priv.forced_source_clock) {
priv.master = ha_select_clock(&priv, cfg);
+ pr_info("interface %s will be used as source clock", priv.master->device);
}
}
--
2.25.1

View File

@ -0,0 +1,451 @@
From fce993dd36e481aace337a62ff81331cd2411bec Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Thu, 27 Jul 2023 14:22:47 -0300
Subject: [PATCH 41/47] HA phc2sys com socket
A new communication path was created to retrieve status and to control
the high availability algorithm.
The ha_phc2sys_com_socket option is a global setting to configure
the socket path. Its default value is /var/run/phc2sys.
The command 'status' was created to retrieve the current HA clock status.
The answer is a table of configured clocks and its status.
act interface priority clockClass clockAcc offset time freq gm.
* ens2f1 200 248 0xfe 0xffff no no 6
ens1f2 100 248 0xfe 0xffff no no 6
Source forced? no
The * sign marks the active source clock.
The - sign marks the active candidate source clock, which will be set active
after the stability timer expiration.
The x sign marks the disabled interfaces (see 'disable source' command).
The 'Source forced?' field shows if the active source is forced lock or not.
The 'clock source' command can be used to retrive the active
clock source. It returns the interface name of the active
clock source or "None" when there is no one select.
The 'forced lock' command can be used to retrieve if the active
clock source is forced lock, and the clock source selection
algorithm is disabled. It returns "True" when is forced lock
and "False" otherwise.
Test plan: socket path configuration
PASS Verify the socket using the default path.
PASS Verify the socket using a given socket path.
Test plan: status command
PASS: Verify the 'status' command after start up.
PASS: Verify the 'status' command while stability timer is running.
PASS: Verify the 'status' command with a forced lock interface by
configuring ha_priority 254.
Test plan: clock source command
PASS: Verify the 'clock source' command response is the highest priority
interface after start up.
PASS: Verify the 'clock source' command response is the active interface
after the primary has degraded.
PASS: Verify the 'clock source' command response is the forced lock
interface, when ha_priority 254 is configured in one of them.
Test plan: forced lock command
PASS: Verify the 'forced lock' command response is 'False' when no
interface is configured with ha_priority 254.
PASS: Verify the 'forced lock' command response is 'True' when one
interface is configured with ha_priority 254.
Reviewed-by: Cole Walker <cole.walker@windriver.com>
Reviewed-by: Andre Fernando Zanella Kantek <andrefernandozanella.kantek@windriver.com>
[commit 0cfcbb78485a83d324963130f9558fd0a1962a79 upstream]
[commit 73b9afa33a0d8dcfd9c4ebb7bceacee40af8eb2b upstream]
[commit 6e93059d34639a3c2aac6b56dcf94ddf1e48e9b4 upstream]
[commit 4f118cf954bc3543582765bc039c42aeac05caf5 upstream]
[commit 6387ddf644afcb880b67368be8416b8ce906e029 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
config.c | 1 +
phc2sys.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 216 insertions(+), 16 deletions(-)
diff --git a/config.c b/config.c
index dba1eef..6a1bfb4 100644
--- a/config.c
+++ b/config.c
@@ -256,6 +256,7 @@ struct config_item config_tab[] = {
GLOB_ITEM_INT("ha_min_gm_ClockClass", 135, 6, 255),
GLOB_ITEM_INT("ha_min_local_clockClass", 135, 6, 255),
GLOB_ITEM_INT("ha_min_offsetScaledLogVariance", 65535, 0, 65535),
+ GLOB_ITEM_STR("ha_phc2sys_com_socket", "/var/run/phc2sys-phc-inst1"),
PORT_ITEM_INT("ha_priority", 0, 0, 254),
PORT_ITEM_INT("ha_stability_timer", 0, 0, INT_MAX),
GLOB_ITEM_INT("ha_timeTraceable", 0, 0, 1),
diff --git a/phc2sys.c b/phc2sys.c
index 0b3f724..0bc3709 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -66,6 +66,9 @@
#define FORCED_SOURCE_CLOCK_PRIORITY 254
#define MAX_SRC_CLOCKS 128
+#define HA_SCK_N_FD 1
+#define HA_SCK_BUFFER_SIZE 1024
+#define HA_SCK_FILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) /*0660*/
#define PORT_INDEX_TO_PORT_ID(port, index) (((((unsigned int) port) & 0xFF) << 8) | (((unsigned int) index) & 0xFF))
#define PORT_ID_TO_PORT(id) ((((unsigned int) id) >> 8) & 0xFF)
@@ -94,6 +97,7 @@ struct clock {
struct stats *delay_stats;
struct clockcheck *sanity_check;
struct pmc_agent *node;
+ int ha_priority;
};
typedef LIST_HEAD(head, clock) clock_list_head_t;
@@ -123,6 +127,7 @@ struct phc2sys_private {
struct timespec stability_timer;
int default_sync;
int forced_source_clock;
+ int ha_socket_fd;
};
static struct config *phc2sys_config;
@@ -1003,7 +1008,6 @@ static int update_needed(struct clock *c)
/* check configuration if one of the source clocks is force locked to be active */
static struct clock* ha_forced_source_clock(struct phc2sys_private *priv, struct config *cfg)
{
- int clock_priority;
struct clock *clock = NULL, *best = NULL;
LIST_FOREACH(clock, &priv->clocks, list) {
@@ -1012,8 +1016,7 @@ static struct clock* ha_forced_source_clock(struct phc2sys_private *priv, struct
continue;
}
- clock_priority = config_get_int(cfg, clock->device, "ha_priority");
- if (FORCED_SOURCE_CLOCK_PRIORITY == clock_priority) {
+ if (FORCED_SOURCE_CLOCK_PRIORITY == clock->ha_priority) {
pr_info("HA automatic source selection is disabled by configuration");
priv->forced_source_clock = 1;
best = clock;
@@ -1025,7 +1028,7 @@ static struct clock* ha_forced_source_clock(struct phc2sys_private *priv, struct
static struct clock* ha_select_clock(struct phc2sys_private *priv, struct config *cfg)
{
- int clock_priority, highest_priority;
+ int highest_priority;
int clock_class, lowest_clock_class;
struct clock *clock = NULL, *best = NULL;
clock_list_head_t ha_available_clocks;
@@ -1038,17 +1041,14 @@ static struct clock* ha_select_clock(struct phc2sys_private *priv, struct config
/* one or more sources match requirements, select highest priority */
highest_priority = 0;
- LIST_FOREACH(clock, &ha_available_clocks, ha_list) {
- clock_priority = config_get_int(cfg, clock->device, "ha_priority");
-
- /* select highest priority clock
+ LIST_FOREACH(clock, &ha_available_clocks, ha_list) {/* select highest priority clock
more than one clock with same priority, select first
don't select clocks with ha_priority 0 */
- if (clock_priority > highest_priority) {
+ if (clock->ha_priority > highest_priority) {
pr_notice("new highest ha priority clock %s ha_priority %d",
- clock->device, clock_priority);
+ clock->device, clock->ha_priority);
best = clock;
- highest_priority = clock_priority;
+ highest_priority = clock->ha_priority;
}
}
@@ -1101,7 +1101,6 @@ static struct clock* check_and_select_clock(struct phc2sys_private *priv, struct
struct clock *active = priv->master, *candidate = NULL;
int stability_timer = 0;
struct timespec now;
- int active_priority, candidate_priority;
int active_clock_class, candidate_clock_class;
/* Active source degrades - re-run ha_select_clock algorithm */
@@ -1137,11 +1136,9 @@ static struct clock* check_and_select_clock(struct phc2sys_private *priv, struct
/* new clock candidate */
/* candidate has equal priority and clockClass than active - don't change active */
- active_priority = config_get_int(cfg, active->device, "ha_priority");
- candidate_priority = config_get_int(cfg, candidate->device, "ha_priority");
active_clock_class = active->node->dds.clockQuality.clockClass;
candidate_clock_class = candidate->node->dds.clockQuality.clockClass;
- if ((active_priority == candidate_priority) &&
+ if ((active->ha_priority == candidate->ha_priority) &&
(active_clock_class == candidate_clock_class)) {
return NULL;
}
@@ -1175,6 +1172,196 @@ static void reset_new_dataset_flags(struct phc2sys_private *priv)
}
}
+static int ha_com_socket_close(int fd)
+{
+ struct sockaddr_un sa;
+ socklen_t len = sizeof(sa);
+
+ // if (fd < 0)
+ // return -1;
+
+ if (!getsockname(fd, (struct sockaddr *) &sa, &len) &&
+ sa.sun_family == AF_LOCAL) {
+ unlink(sa.sun_path);
+ }
+
+ close(fd);
+ return 0;
+}
+
+static int ha_com_socket_open(int *fd_out, struct config *cfg)
+{
+ int fd, err;
+ struct sockaddr_un sa;
+ const char *name = config_get_string(cfg, NULL, "ha_phc2sys_com_socket");
+
+ fd = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ pr_err("ha_com_socket: failed to create socket: %m");
+ return -1;
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sun_family = AF_LOCAL;
+ strncpy(sa.sun_path, name, sizeof(sa.sun_path) - 1);
+
+ err = bind(fd, (struct sockaddr *) &sa, sizeof(sa));
+ if (err < 0) {
+ pr_err("ha_com_socket: bind failed: %m");
+ close(fd);
+ return -1;
+ }
+
+ *fd_out = fd;
+ chmod(name, HA_SCK_FILEMODE);
+
+ return 0;
+}
+
+static int ha_com_socket_recv(int fd, void *buf, size_t buflen,
+ struct address *addr)
+{
+ int cnt;
+
+ addr->len = sizeof(addr->sun);
+ cnt = recvfrom(fd, buf, buflen, 0, &addr->sa, &addr->len);
+ if (cnt <= 0) {
+ pr_err("ha_com_socket: recvfrom failed: %m");
+ return cnt;
+ }
+
+ ((char*)buf)[cnt] = '\0';
+
+ return 0;
+}
+
+static int ha_com_socket_send(int fd, struct address *addr, void *buf,
+ size_t buflen)
+{
+ int cnt;
+
+ cnt = sendto(fd, buf, buflen, 0, &addr->sa, addr->len);
+ if (cnt < 1) {
+ return -errno;
+ }
+ return cnt;
+}
+
+static int ha_handle_status_msg(struct phc2sys_private *priv, char *response,
+ size_t resplen)
+{
+ struct clock *clock;
+ size_t curlen = 0;
+
+ /* header */
+ curlen = snprintf(response, resplen,
+ "act interface priority clockClass clockAcc offset time freq "
+ "gm.clockClass\n\n");
+
+ LIST_FOREACH(clock, &priv->clocks, list) {
+
+ /* ignore the dst clock */
+ if (clock->state == PS_MASTER)
+ continue;
+
+ /* sanity check */
+ if (clock->node == NULL)
+ continue;
+
+ curlen += snprintf(response + curlen, resplen - curlen,
+ " %c %9s %8d %10d 0x%2x 0x%4x %s %s %d\n",
+ (priv->master == clock) ? '*' :
+ (priv->better == clock) ? '-' : ' ',
+ clock->device, clock->ha_priority,
+ clock->node->dds.clockQuality.clockClass,
+ clock->node->dds.clockQuality.clockAccuracy,
+ clock->node->dds.clockQuality.offsetScaledLogVariance,
+ clock->node->utc_offset_traceable ? "yes" : "no ",
+ clock->node->freq_traceable ? "yes" : "no ",
+ clock->node->pds.grandmasterClockQuality.clockClass);
+ }
+
+ curlen += snprintf(response + curlen, resplen - curlen,
+ "\n\nSource forced? %s\n", priv->forced_source_clock ? "yes" : "no");
+
+ return curlen;
+}
+
+static int ha_com_socket_handle_msg(struct phc2sys_private *priv)
+{
+ struct pollfd pollfd[HA_SCK_N_FD];
+ struct address sender;
+ int cnt, res = 0;
+ int timeout = 0;
+ void * buffer = NULL;
+ void * response = NULL;
+
+ while(1) {
+ pollfd[0].fd = priv->ha_socket_fd;
+ pollfd[0].events = POLLIN|POLLPRI;
+
+ cnt = poll(pollfd, HA_SCK_N_FD, timeout);
+ if (cnt < 0) {
+ pr_err("ha_com_socket: poll failed: %m");
+ res = -1;
+ break;
+ }
+ if (!cnt) {
+ /* timeout and fd wasn't ready */
+ break;
+ }
+
+ if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
+ break;
+
+ buffer = malloc(HA_SCK_BUFFER_SIZE);
+ if (!buffer) {
+ pr_err("ha_com_socket: failed to allocate memory for message");
+ res = -1;
+ break;
+ }
+
+ res = ha_com_socket_recv(pollfd[0].fd, buffer, HA_SCK_BUFFER_SIZE, &sender);
+ if (res < 0)
+ break;
+
+ fprintf(stderr, "ha_com_socket: received: %s\n", (char*)buffer);
+ fprintf(stderr, "ha_com_socket: recvd from: %s\n", ((struct sockaddr_un*)&sender.sa)->sun_path);
+
+ response = malloc(HA_SCK_BUFFER_SIZE);
+ if (!response) {
+ pr_err("ha_com_socket: failed to allocate memory for response message");
+ res = -1;
+ break;
+ }
+
+ /* handle messages and create responses */
+ if (strcmp((const char*)buffer, "status") == 0) {
+ cnt = ha_handle_status_msg(priv, response, HA_SCK_BUFFER_SIZE);
+ } else if (strcmp((const char*)buffer, "clock source") == 0) {
+ if (priv->master) {
+ cnt = snprintf((char*)response, HA_SCK_BUFFER_SIZE, "%s",
+ priv->master->device);
+ } else {
+ cnt = snprintf((char*)buffer, HA_SCK_BUFFER_SIZE, "None");
+ }
+ } else if (strcmp((const char*)buffer, "forced lock") == 0) {
+ cnt = snprintf((char*)response, HA_SCK_BUFFER_SIZE, "%s",
+ priv->forced_source_clock ? "True" : "False");
+ } else {
+ cnt = snprintf((char*)response, HA_SCK_BUFFER_SIZE, "error: invalid command");
+ }
+
+ fprintf(stderr, "ha_com_socket: response: \n%s", (char*)response);
+
+ res = ha_com_socket_send(pollfd[0].fd, &sender, response, cnt);
+ }
+
+ free(buffer);
+ free(response);
+ return res;
+}
+
static int do_loop(struct phc2sys_private *priv, struct config *cfg, int subscriptions)
{
struct timespec interval;
@@ -1223,6 +1410,8 @@ static int do_loop(struct phc2sys_private *priv, struct config *cfg, int subscri
}
if (ha_enabled) {
+ ha_com_socket_handle_msg(priv);
+
if (priv->forced_source_clock) {
/* HA automatic clock selection is disabled */
if (priv->clock_state_changed) {
@@ -1312,6 +1501,7 @@ static int do_loop(struct phc2sys_private *priv, struct config *cfg, int subscri
update_clock(priv, clock, offset, ts, delay);
}
}
+
return 0;
}
@@ -1597,6 +1787,7 @@ int main(int argc, char *argv[])
.better = NULL,
.stability_timer.tv_sec = 0,
.forced_source_clock = 0,
+ .ha_socket_fd = -1,
};
struct pmc_agent *node = NULL;
unsigned int i, src_cnt = 0;
@@ -1861,7 +2052,7 @@ int main(int argc, char *argv[])
ha_enabled = config_get_int(cfg, NULL, "ha_enabled");
if (!ha_enabled && src_cnt > 1) {
fprintf(stderr, "too many source clocks\n");
- fprintf(stderr, "Use 'ha_enabled 1' to accept more than one source clocks\n");
+ fprintf(stderr, "Use 'ha_enabled 1' to accept more than one source clock\n");
goto bad_usage;
}
@@ -1877,6 +2068,9 @@ int main(int argc, char *argv[])
if (priv.master == NULL) {
priv.master = src;
}
+ if (ha_enabled) {
+ src->ha_priority = config_get_int(cfg, src->device, "ha_priority");
+ }
}
dst = clock_add(&priv, dst_name ? dst_name : "CLOCK_REALTIME");
@@ -1966,6 +2160,10 @@ int main(int argc, char *argv[])
}
}
+ if (ha_enabled) {
+ ha_com_socket_open(&priv.ha_socket_fd, cfg);
+ }
+
if (pps_fd >= 0) {
/* only one destination clock allowed with PPS until we
* implement a mean to specify PTP port to PPS mapping */
@@ -1976,6 +2174,7 @@ int main(int argc, char *argv[])
}
end:
+ ha_com_socket_close(priv.ha_socket_fd);
pmc_agent_cleanup(&priv);
clock_cleanup(&priv);
port_cleanup(&priv);
--
2.25.1

View File

@ -0,0 +1,193 @@
From e77783a9873baeeda277cfa59059021ce121a693 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Fri, 4 Aug 2023 15:44:12 -0300
Subject: [PATCH 42/47] Commands 'enable lock' and 'disable lock.
The 'enable lock' command is used to lock to a single clock
source and disable the HA clock selection algorithm. The
interface of the clock source must be specified in the
command. For example:
'enable lock <interface-name>'
It returns "Success" or an error message. The error message
"Error: Usage 'enable lock <interface>'" is returned when
no interface was provided in the command. The error message
"Error: Interface not found!" is returned when the interface
provided is not found in the phc2sys configuration.
The command 'disable lock' is used to unlock the clock source
and re-enable the HA clock selection algorithm. It returns
"Success" even when the clock source was not locked.
Test plan: enable lock and disable lock commands
PASS: Verify the enable lock changes the clock source to the given
interface.
PASS: Verify that regardless the interface state, the clock source
remains locked.
PASS: Verify that disable lock command makes the better available
clock to be selected again.
[commit 704d9ed2e22b89308c7f0149d7fde86d456bc4e3 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 110 +++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 93 insertions(+), 17 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 0bc3709..f89dc23 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -259,13 +259,21 @@ static void clock_cleanup(struct phc2sys_private *priv)
}
}
-static struct clock *clock_get(struct phc2sys_private *priv, struct pmc_agent *node)
+static struct clock * clock_get_by_device(struct phc2sys_private *priv,
+ const char * device)
{
struct clock * clock = NULL;
LIST_FOREACH(clock, &priv->clocks, list) {
- if (clock->node == node) {
+ /* ignore the dst clock */
+ if (clock->state == PS_MASTER)
+ continue;
+
+ /* sanity check */
+ if (!clock->device)
+ continue;
+
+ if (strcmp(device, clock->device) == 0)
break;
- }
}
return clock;
}
@@ -508,18 +516,6 @@ static struct port *port_get(struct phc2sys_private *priv, unsigned int number)
return NULL;
}
-static struct port *port_get_by_clock(struct phc2sys_private *priv, struct clock * clock)
-{
- struct port *p, *port = NULL;
- LIST_FOREACH(p, &priv->ports, list) {
- if (p->clock == clock) {
- port = p;
- break;
- }
- }
- return port;
-}
-
static struct port *port_add(struct phc2sys_private *priv, unsigned int number,
char *device)
{
@@ -1287,7 +1283,82 @@ static int ha_handle_status_msg(struct phc2sys_private *priv, char *response,
return curlen;
}
-static int ha_com_socket_handle_msg(struct phc2sys_private *priv)
+static bool startsWith(const char *prefix, const char *str)
+{
+ return 0 == strncmp(prefix, str, strlen(prefix) - 1);
+}
+
+static char * strAtColumn(char *msg, size_t column)
+{
+ int i;
+ char * str = NULL;
+
+ /* split and walk over the columns */
+ strtok(msg, " ");
+ for (i = 1; i < column; i++) {
+ str = strtok(NULL, " ");
+ }
+
+ return str;
+}
+
+static int ha_handle_enable_lock_msg(struct phc2sys_private *priv, char *msg,
+ char *response, size_t resplen)
+{
+ size_t curlen = 0;
+ char *interface = NULL;
+ struct clock *clock = NULL;
+
+ interface = strAtColumn(msg, 3);
+ if (strlen(interface) == 0) {
+ return snprintf(response, resplen, "Error: Usage 'enable lock <interface>'");
+ }
+
+ clock = clock_get_by_device(priv, interface);
+ if (!clock) {
+ return snprintf(response, resplen, "Error: Interface not found!");
+ }
+
+ pr_info("HA automatic source selection is disabled by command");
+ pr_info("Only interface %s will be used as source clock", clock->device);
+
+ priv->master = clock;
+ priv->better = NULL;
+ priv->stability_timer.tv_sec = 0;
+ priv->stability_timer.tv_nsec = 0;
+
+ priv->forced_source_clock = 1;
+
+ curlen = snprintf(response, resplen, "Success");
+
+ return curlen;
+}
+
+static int ha_handle_disable_lock_msg(struct phc2sys_private *priv,
+ struct config *cfg, char *response, size_t resplen)
+{
+ size_t curlen = 0;
+ struct clock *clock = NULL;
+
+ if (priv->forced_source_clock) {
+ pr_info("HA automatic source selection is enabled by command");
+ /* re-enable HA source selection algorithm */
+ priv->forced_source_clock = 0;
+ /* select the best clock available */
+ clock = ha_select_clock(priv, cfg);
+ if (clock && clock != priv->master) {
+ priv->master = clock;
+ pr_notice("new source clock selected %s", clock->device);
+ }
+ }
+
+ curlen = snprintf(response, resplen, "Success");
+
+ return curlen;
+}
+
+static int ha_com_socket_handle_msg(struct phc2sys_private *priv,
+ struct config *cfg)
{
struct pollfd pollfd[HA_SCK_N_FD];
struct address sender;
@@ -1348,6 +1419,11 @@ static int ha_com_socket_handle_msg(struct phc2sys_private *priv)
} else if (strcmp((const char*)buffer, "forced lock") == 0) {
cnt = snprintf((char*)response, HA_SCK_BUFFER_SIZE, "%s",
priv->forced_source_clock ? "True" : "False");
+ } else if (startsWith("enable lock", buffer)) {
+ cnt = ha_handle_enable_lock_msg(priv, buffer, response,
+ HA_SCK_BUFFER_SIZE);
+ } else if (strcmp((const char*)buffer, "disable lock") == 0) {
+ cnt = ha_handle_disable_lock_msg(priv, cfg, response, HA_SCK_BUFFER_SIZE);
} else {
cnt = snprintf((char*)response, HA_SCK_BUFFER_SIZE, "error: invalid command");
}
@@ -1410,7 +1486,7 @@ static int do_loop(struct phc2sys_private *priv, struct config *cfg, int subscri
}
if (ha_enabled) {
- ha_com_socket_handle_msg(priv);
+ ha_com_socket_handle_msg(priv, cfg);
if (priv->forced_source_clock) {
/* HA automatic clock selection is disabled */
--
2.25.1

View File

@ -0,0 +1,288 @@
From 27b5c6afff470053b30ade14537be43f1c1c376d Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Fri, 4 Aug 2023 19:01:57 -0300
Subject: [PATCH 43/47] Commands 'enable source' and 'disable source'.
These commands controls the list of clocks available to clock
selection algorithm.
At startup all sources are enabled and can be selected as clock
source. The 'disable source' command removes a given interface
from the available list and it can't be selected any more. The
'enable source' command re-enables the interface.
The last interface can't be disable. The disable command fails and
returns an error indicating the given interface is the last one.
If the active clock source interface is disabled than a new one
will be selected.
Every time the enable command is executed the clock selection
algorithm is executed and the best available clock is selected.
The enable and disable source commands won't affect the active
clock if one interface is forced lock as active.
The disabled interface is market with 'x' sign in the status
command.
Test plan: enable source and disable source commands
PASS: Verify a new interface is selected when the active one
is disabled.
PASS: Verify the primary interface is re-selected active after
it is enabled back.
PASS: Verify the disable source command fails when attempt to
disable the last enabled interface.
PASS: Verify the active interface don't change while one of them
are forced lock as active.
PASS: Verify the active interface dont't change after enabling
an interface while in forced lock mode.
Reviewed-by: Cole Walker <cole.walker@windriver.com>
Reviewed-by: Andre Fernando Zanella Kantek
<andrefernandozanella.kantek@windriver.com>
[commit 55ac3f4131aaa999b1b7b9eec50b7cb7cebbf0d4 upstream]
[commit c77de0acd3641833d2705e3929be2152bd5fb519 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 127 insertions(+), 19 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index f89dc23..035ee21 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -98,6 +98,7 @@ struct clock {
struct clockcheck *sanity_check;
struct pmc_agent *node;
int ha_priority;
+ int enabled;
};
typedef LIST_HEAD(head, clock) clock_list_head_t;
@@ -228,6 +229,8 @@ static struct clock *clock_add(struct phc2sys_private *priv, char *device)
c->sysoff_method = sysoff_probe(CLOCKID_TO_FD(clkid),
priv->phc_readings);
+ c->enabled = 1;
+
LIST_INSERT_HEAD(&priv->clocks, c, list);
return c;
}
@@ -278,6 +281,28 @@ static struct clock * clock_get_by_device(struct phc2sys_private *priv,
return clock;
}
+static size_t clock_count_enabled_sources(struct phc2sys_private *priv,
+ struct clock *ignore)
+{
+ size_t count = 0;
+ struct clock * clock = NULL;
+
+ LIST_FOREACH(clock, &priv->clocks, list) {
+ /* ignore the dst clock */
+ if (clock->state == PS_MASTER)
+ continue;
+
+ if (clock == ignore)
+ continue;
+
+ if (!clock->enabled)
+ continue;
+
+ count++;
+ }
+ return count;
+}
+
static bool clock_match_ha_dds_requirements(struct clock *clock, struct config *cfg)
{
/* get requirements */
@@ -404,6 +429,11 @@ static int clock_available_ha_src_clocks(struct phc2sys_private *priv, struct co
continue;
}
+ if (!clock->enabled) {
+ pr_debug("clock %s is disabled", clock->device);
+ continue;
+ }
+
/* get Default Data Set */
if (!clock->node->dds_valid) {
retries = 0;
@@ -1267,7 +1297,8 @@ static int ha_handle_status_msg(struct phc2sys_private *priv, char *response,
curlen += snprintf(response + curlen, resplen - curlen,
" %c %9s %8d %10d 0x%2x 0x%4x %s %s %d\n",
(priv->master == clock) ? '*' :
- (priv->better == clock) ? '-' : ' ',
+ (priv->better == clock) ? '-' :
+ (!clock->enabled) ? 'x' : ' ',
clock->device, clock->ha_priority,
clock->node->dds.clockQuality.clockClass,
clock->node->dds.clockQuality.clockAccuracy,
@@ -1302,6 +1333,16 @@ static char * strAtColumn(char *msg, size_t column)
return str;
}
+static void ha_set_clock_source(struct phc2sys_private *priv, struct clock *clock)
+{
+ pr_notice("new clock source selected %s", clock->device);
+
+ priv->master = clock;
+ priv->better = NULL;
+ priv->stability_timer.tv_sec = 0;
+ priv->stability_timer.tv_nsec = 0;
+}
+
static int ha_handle_enable_lock_msg(struct phc2sys_private *priv, char *msg,
char *response, size_t resplen)
{
@@ -1316,16 +1357,13 @@ static int ha_handle_enable_lock_msg(struct phc2sys_private *priv, char *msg,
clock = clock_get_by_device(priv, interface);
if (!clock) {
- return snprintf(response, resplen, "Error: Interface not found!");
+ return snprintf(response, resplen, "Error: Interface not found");
}
pr_info("HA automatic source selection is disabled by command");
pr_info("Only interface %s will be used as source clock", clock->device);
- priv->master = clock;
- priv->better = NULL;
- priv->stability_timer.tv_sec = 0;
- priv->stability_timer.tv_nsec = 0;
+ ha_set_clock_source(priv, clock);
priv->forced_source_clock = 1;
@@ -1347,8 +1385,77 @@ static int ha_handle_disable_lock_msg(struct phc2sys_private *priv,
/* select the best clock available */
clock = ha_select_clock(priv, cfg);
if (clock && clock != priv->master) {
- priv->master = clock;
- pr_notice("new source clock selected %s", clock->device);
+ ha_set_clock_source(priv, clock);
+ }
+ }
+
+ curlen = snprintf(response, resplen, "Success");
+
+ return curlen;
+}
+
+static int ha_handle_enable_source_msg(struct phc2sys_private *priv,
+ struct config *cfg, char *msg, char *response, size_t resplen)
+{
+ size_t curlen;
+ char *interface = NULL;
+ struct clock *clock = NULL;
+
+ interface = strAtColumn(msg, 3);
+ if (strlen(interface) == 0) {
+ return snprintf(response, resplen, "Error: Usage 'enable source <interface>'");
+ }
+
+ clock = clock_get_by_device(priv, interface);
+ if (!clock) {
+ return snprintf(response, resplen, "Error: Interface not found");
+ }
+
+ clock->enabled = 1;
+
+ if (!priv->forced_source_clock) {
+ /* select the best clock available */
+ clock = ha_select_clock(priv, cfg);
+ if (clock && clock != priv->master) {
+ ha_set_clock_source(priv, clock);
+ }
+ }
+
+ curlen = snprintf(response, resplen, "Success");
+
+ return curlen;
+}
+
+static int ha_handle_disable_source_msg(struct phc2sys_private *priv,
+ struct config *cfg, char *msg, char *response, size_t resplen)
+{
+ size_t curlen;
+ char *interface = NULL;
+ struct clock *clock = NULL;
+
+ interface = strAtColumn(msg, 3);
+ if (strlen(interface) == 0) {
+ return snprintf(response, resplen, "Error: Usage 'disable source <interface>'");
+ }
+
+ clock = clock_get_by_device(priv, interface);
+ if (!clock) {
+ return snprintf(response, resplen, "Error: Interface not found");
+ }
+
+ /* check if is the last clock enabled */
+ if (clock_count_enabled_sources(priv, clock) == 0) {
+ return snprintf(response, resplen, "Error: Last interface enabled");
+ }
+
+ clock->enabled = 0;
+
+ /* disabling clock source */
+ if (clock == priv->master && !priv->forced_source_clock) {
+ /* select the best clock available */
+ clock = ha_select_clock(priv, cfg);
+ if (clock && clock != priv->master) {
+ ha_set_clock_source(priv, clock);
}
}
@@ -1423,9 +1530,17 @@ static int ha_com_socket_handle_msg(struct phc2sys_private *priv,
cnt = ha_handle_enable_lock_msg(priv, buffer, response,
HA_SCK_BUFFER_SIZE);
} else if (strcmp((const char*)buffer, "disable lock") == 0) {
- cnt = ha_handle_disable_lock_msg(priv, cfg, response, HA_SCK_BUFFER_SIZE);
+ cnt = ha_handle_disable_lock_msg(priv, cfg, response,
+ HA_SCK_BUFFER_SIZE);
+ } else if (startsWith("enable source", buffer)) {
+ cnt = ha_handle_enable_source_msg(priv, cfg, buffer, response,
+ HA_SCK_BUFFER_SIZE);
+ } else if (startsWith("disable source", buffer)) {
+ cnt = ha_handle_disable_source_msg(priv, cfg, buffer, response,
+ HA_SCK_BUFFER_SIZE);
} else {
- cnt = snprintf((char*)response, HA_SCK_BUFFER_SIZE, "error: invalid command");
+ cnt = snprintf((char*)response, HA_SCK_BUFFER_SIZE,
+ "Error: Invalid command");
}
fprintf(stderr, "ha_com_socket: response: \n%s", (char*)response);
@@ -1498,10 +1613,7 @@ static int do_loop(struct phc2sys_private *priv, struct config *cfg, int subscri
if (priv->clock_state_changed) {
clock = check_and_select_clock(priv, cfg);
if (clock && clock != priv->master) {
- priv->master = clock;
- priv->better = NULL;
- priv->stability_timer.tv_sec = 0;
- priv->stability_timer.tv_nsec = 0;
+ ha_set_clock_source(priv, clock);
}
priv->clock_state_changed = 0;
@@ -1514,11 +1626,7 @@ static int do_loop(struct phc2sys_private *priv, struct config *cfg, int subscri
if ((now.tv_sec > priv->stability_timer.tv_sec) ||
(now.tv_sec == priv->stability_timer.tv_sec &&
now.tv_nsec > priv->stability_timer.tv_nsec)) {
- pr_notice("new source clock selected %s", priv->better->device);
- priv->master = priv->better;
- priv->better = NULL;
- priv->stability_timer.tv_sec = 0;
- priv->stability_timer.tv_nsec = 0;
+ ha_set_clock_source(priv, priv->better);
}
}
}
--
2.25.1

View File

@ -0,0 +1,201 @@
From 2d40cc7cf52bbf054856c34902e4bda9f13ebb79 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 7 Aug 2023 14:55:12 -0300
Subject: [PATCH 44/47] Stream type phc2sys com socket
The type of the socket was changed from datagram to stream.
Test plan: status/show commands
PASS: Verify status command response
PASS: Verify forced lock command response
PASS: Verify clock source command response
Test plan: enable lock and disable lock commands
PASS: Verify the enable lock changes the clock source to the given
interface.
PASS: Verify that disable lock command makes the better available
clock to be selected again.
Test plan: disable source and enable source commands
PASS: Verify a new interface is selected when the active one
is disabled.
PASS: Verify the primary interface is re-selected active after
it is enabled back.
Reviewed-by: Cole Walker <cole.walker@windriver.com>
Reviewed-by: Andre Fernando Zanella Kantek
<andrefernandozanella.kantek@windriver.com>
[commit b4f79cb626d6e40cf1d5aa2c5d5fba89e2c2e340 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 76 +++++++++++++++++++++++++++----------------------------
1 file changed, 38 insertions(+), 38 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 035ee21..a597014 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -1203,14 +1203,12 @@ static int ha_com_socket_close(int fd)
struct sockaddr_un sa;
socklen_t len = sizeof(sa);
- // if (fd < 0)
- // return -1;
-
if (!getsockname(fd, (struct sockaddr *) &sa, &len) &&
sa.sun_family == AF_LOCAL) {
unlink(sa.sun_path);
}
+ shutdown(fd, SHUT_RDWR);
close(fd);
return 0;
}
@@ -1219,9 +1217,10 @@ static int ha_com_socket_open(int *fd_out, struct config *cfg)
{
int fd, err;
struct sockaddr_un sa;
+ const int backlog = 50;
const char *name = config_get_string(cfg, NULL, "ha_phc2sys_com_socket");
- fd = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (fd < 0) {
pr_err("ha_com_socket: failed to create socket: %m");
return -1;
@@ -1238,22 +1237,27 @@ static int ha_com_socket_open(int *fd_out, struct config *cfg)
return -1;
}
+ err = listen(fd, backlog);
+ if (err < 0) {
+ pr_err("ha_com_socket: listen failed: %m");
+ close(fd);
+ return -1;
+ }
+
*fd_out = fd;
chmod(name, HA_SCK_FILEMODE);
return 0;
}
-static int ha_com_socket_recv(int fd, void *buf, size_t buflen,
- struct address *addr)
+static int ha_com_socket_recv(int fd, void *buf, size_t buflen)
{
int cnt;
- addr->len = sizeof(addr->sun);
- cnt = recvfrom(fd, buf, buflen, 0, &addr->sa, &addr->len);
+ cnt = read(fd, buf, buflen);
if (cnt <= 0) {
- pr_err("ha_com_socket: recvfrom failed: %m");
- return cnt;
+ pr_err("ha_com_socket: read failed: %m");
+ return -errno;
}
((char*)buf)[cnt] = '\0';
@@ -1261,13 +1265,13 @@ static int ha_com_socket_recv(int fd, void *buf, size_t buflen,
return 0;
}
-static int ha_com_socket_send(int fd, struct address *addr, void *buf,
- size_t buflen)
+static int ha_com_socket_send(int fd, void *buf, size_t buflen)
{
int cnt;
- cnt = sendto(fd, buf, buflen, 0, &addr->sa, addr->len);
- if (cnt < 1) {
+ cnt = send(fd, buf, buflen, 0);
+ if (cnt < 0) {
+ pr_err("ha_com_socket: send failed: %m");
return -errno;
}
return cnt;
@@ -1467,48 +1471,42 @@ static int ha_handle_disable_source_msg(struct phc2sys_private *priv,
static int ha_com_socket_handle_msg(struct phc2sys_private *priv,
struct config *cfg)
{
- struct pollfd pollfd[HA_SCK_N_FD];
- struct address sender;
- int cnt, res = 0;
- int timeout = 0;
+ int cnt, res = 0, fd;
void * buffer = NULL;
void * response = NULL;
while(1) {
- pollfd[0].fd = priv->ha_socket_fd;
- pollfd[0].events = POLLIN|POLLPRI;
-
- cnt = poll(pollfd, HA_SCK_N_FD, timeout);
- if (cnt < 0) {
- pr_err("ha_com_socket: poll failed: %m");
- res = -1;
- break;
- }
- if (!cnt) {
- /* timeout and fd wasn't ready */
+ fd = accept(priv->ha_socket_fd, NULL, NULL);
+ if (fd < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ /* no msg available */
+ } else {
+ pr_err("ha_com_socket: accept failed: %m");
+ res = -1;
+ }
break;
}
- if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
- break;
-
buffer = malloc(HA_SCK_BUFFER_SIZE);
if (!buffer) {
pr_err("ha_com_socket: failed to allocate memory for message");
+ close(fd);
res = -1;
break;
}
- res = ha_com_socket_recv(pollfd[0].fd, buffer, HA_SCK_BUFFER_SIZE, &sender);
- if (res < 0)
+ res = ha_com_socket_recv(fd, buffer, HA_SCK_BUFFER_SIZE);
+ if (res < 0) {
+ close(fd);
break;
+ }
- fprintf(stderr, "ha_com_socket: received: %s\n", (char*)buffer);
- fprintf(stderr, "ha_com_socket: recvd from: %s\n", ((struct sockaddr_un*)&sender.sa)->sun_path);
+ pr_debug("ha_com_socket: command received: %s", (char*)buffer);
response = malloc(HA_SCK_BUFFER_SIZE);
if (!response) {
pr_err("ha_com_socket: failed to allocate memory for response message");
+ close(fd);
res = -1;
break;
}
@@ -1543,9 +1541,11 @@ static int ha_com_socket_handle_msg(struct phc2sys_private *priv,
"Error: Invalid command");
}
- fprintf(stderr, "ha_com_socket: response: \n%s", (char*)response);
+ pr_debug("ha_com_socket: response: %s", (char*)response);
- res = ha_com_socket_send(pollfd[0].fd, &sender, response, cnt);
+ res = ha_com_socket_send(fd, response, cnt);
+
+ close(fd);
}
free(buffer);
--
2.25.1

View File

@ -0,0 +1,92 @@
From 2896553d6dfa975102cba4cc45105b000ec0ae52 Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Tue, 8 Aug 2023 13:10:50 -0300
Subject: [PATCH 45/47] Functions starts_with and str_at_column
Renaming starts_with and str_at_column functions to match ptp4l code
style.
Test plan: commands
PASS: Verify 'enable lock <interface>', 'disabel source <interface>' and
'enable source <interface>' still work.
Reviewed-by: Cole Walker <cole.walker@windriver.com>
Reviewed-by: Andre Fernando Zanella Kantek
<andrefernandozanella.kantek@windriver.com>
[commit f43f86eab5f8f5d2c9895d290d4bdfd6f60853f8 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index a597014..6965162 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -1318,12 +1318,12 @@ static int ha_handle_status_msg(struct phc2sys_private *priv, char *response,
return curlen;
}
-static bool startsWith(const char *prefix, const char *str)
+static bool starts_with(const char *prefix, const char *str)
{
return 0 == strncmp(prefix, str, strlen(prefix) - 1);
}
-static char * strAtColumn(char *msg, size_t column)
+static char * str_at_column(char *msg, size_t column)
{
int i;
char * str = NULL;
@@ -1354,7 +1354,7 @@ static int ha_handle_enable_lock_msg(struct phc2sys_private *priv, char *msg,
char *interface = NULL;
struct clock *clock = NULL;
- interface = strAtColumn(msg, 3);
+ interface = str_at_column(msg, 3);
if (strlen(interface) == 0) {
return snprintf(response, resplen, "Error: Usage 'enable lock <interface>'");
}
@@ -1405,7 +1405,7 @@ static int ha_handle_enable_source_msg(struct phc2sys_private *priv,
char *interface = NULL;
struct clock *clock = NULL;
- interface = strAtColumn(msg, 3);
+ interface = str_at_column(msg, 3);
if (strlen(interface) == 0) {
return snprintf(response, resplen, "Error: Usage 'enable source <interface>'");
}
@@ -1437,7 +1437,7 @@ static int ha_handle_disable_source_msg(struct phc2sys_private *priv,
char *interface = NULL;
struct clock *clock = NULL;
- interface = strAtColumn(msg, 3);
+ interface = str_at_column(msg, 3);
if (strlen(interface) == 0) {
return snprintf(response, resplen, "Error: Usage 'disable source <interface>'");
}
@@ -1524,16 +1524,16 @@ static int ha_com_socket_handle_msg(struct phc2sys_private *priv,
} else if (strcmp((const char*)buffer, "forced lock") == 0) {
cnt = snprintf((char*)response, HA_SCK_BUFFER_SIZE, "%s",
priv->forced_source_clock ? "True" : "False");
- } else if (startsWith("enable lock", buffer)) {
+ } else if (starts_with("enable lock", buffer)) {
cnt = ha_handle_enable_lock_msg(priv, buffer, response,
HA_SCK_BUFFER_SIZE);
} else if (strcmp((const char*)buffer, "disable lock") == 0) {
cnt = ha_handle_disable_lock_msg(priv, cfg, response,
HA_SCK_BUFFER_SIZE);
- } else if (startsWith("enable source", buffer)) {
+ } else if (starts_with("enable source", buffer)) {
cnt = ha_handle_enable_source_msg(priv, cfg, buffer, response,
HA_SCK_BUFFER_SIZE);
- } else if (startsWith("disable source", buffer)) {
+ } else if (starts_with("disable source", buffer)) {
cnt = ha_handle_disable_source_msg(priv, cfg, buffer, response,
HA_SCK_BUFFER_SIZE);
} else {
--
2.25.1

View File

@ -0,0 +1,78 @@
From f480fb54182da36baeb35bac90154abafcaf854a Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Tue, 8 Aug 2023 14:06:55 -0300
Subject: [PATCH 46/47] Robustness improvements to phc2sys socket
When phc2sys abnormally exits the socket file might remain created.
To avoid error when phc2sys is relaunched, the exixting file is
deleted before recriating the socket.
If the peer application closes the socket before sending the
response completely, it will cause a broken pipe error. The
send function generates a SIGPIPE on broken pipe errors,
killing the phc2sys process unless MSG_NOSIGNAL flag is set.
Test plan: socket file
PASS: Verify that phc2sys can restart normally after killing it.
Test plan: SIGPIPE
PASS: Verify the phc2sys application don't exit when client socket
is closed before the respose is sent.
Reviewed-by: Cole Walker <cole.walker@windriver.com>
Reviewed-by: Andre Fernando Zanella Kantek
<andrefernandozanella.kantek@windriver.com>
[commit 8b3765b3f104a90a487fbcb0f61074c7677c215e upstream]
[commit 50ad1c6f81a706b8be6689bea2ba2db215cf3dc3 upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 6965162..edc626f 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -1218,7 +1218,9 @@ static int ha_com_socket_open(int *fd_out, struct config *cfg)
int fd, err;
struct sockaddr_un sa;
const int backlog = 50;
- const char *name = config_get_string(cfg, NULL, "ha_phc2sys_com_socket");
+ const char *path = config_get_string(cfg, NULL, "ha_phc2sys_com_socket");
+
+ unlink(path);
fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (fd < 0) {
@@ -1228,7 +1230,7 @@ static int ha_com_socket_open(int *fd_out, struct config *cfg)
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_LOCAL;
- strncpy(sa.sun_path, name, sizeof(sa.sun_path) - 1);
+ strncpy(sa.sun_path, path, sizeof(sa.sun_path) - 1);
err = bind(fd, (struct sockaddr *) &sa, sizeof(sa));
if (err < 0) {
@@ -1245,7 +1247,7 @@ static int ha_com_socket_open(int *fd_out, struct config *cfg)
}
*fd_out = fd;
- chmod(name, HA_SCK_FILEMODE);
+ chmod(path, HA_SCK_FILEMODE);
return 0;
}
@@ -1269,7 +1271,7 @@ static int ha_com_socket_send(int fd, void *buf, size_t buflen)
{
int cnt;
- cnt = send(fd, buf, buflen, 0);
+ cnt = send(fd, buf, buflen, MSG_NOSIGNAL);
if (cnt < 0) {
pr_err("ha_com_socket: send failed: %m");
return -errno;
--
2.25.1

View File

@ -0,0 +1,110 @@
From c5e1599748877f16bfd1dea6910f6b8b57be7ddd Mon Sep 17 00:00:00 2001
From: Andre Mauricio Zelak <andre.zelak@windriver.com>
Date: Mon, 7 Aug 2023 18:19:37 -0300
Subject: [PATCH 47/47] phc2sys without -w option.
Fix bad clock and pmc initialization when -w command argument
is not provided.
The pmc agent must be created and mapped to a clock source even
in cases the -w (wait for ptp4l) option is not used.
Test plan:
PASS: Verify phc2sys initializes without -w argument.
PASS: Verify phc2sys initializes with two ptp4l interfaces
configured.
Reviewed-by: Cole Walker <cole.walker@windriver.com>
Reviewed-by: Andre Fernando Zanella Kantek
<andrefernandozanella.kantek@windriver.com>
[commit 10fa27f5829787c15e9ae59c45703328ca4e644f upstream]
Signed-off-by: Andre Mauricio Zelak <andre.zelak@windriver.com>
---
phc2sys.c | 34 ++++++++++++++--------------------
1 file changed, 14 insertions(+), 20 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index edc626f..065b7f0 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -2254,6 +2254,15 @@ int main(int argc, char *argv[])
if (priv.master == NULL) {
priv.master = src;
}
+ if (i > 0) {
+ node = pmc_agent_add(&priv, i);
+ if (!node)
+ goto end;
+ }
+ /* map clock to pmc agent node */
+ src->node = node;
+ pr_debug("pmc node index %d assigned to source interface %s",
+ node->index, src->device);
if (ha_enabled) {
src->ha_priority = config_get_int(cfg, src->device, "ha_priority");
}
@@ -2286,35 +2295,22 @@ int main(int argc, char *argv[])
r = -1;
if (wait_sync) {
- i = 0;
LIST_FOREACH(src, &priv.clocks, list) {
/* skip dst clock */
- if (src == dst) {
+ if (src->state == PS_MASTER)
continue;
- }
-
- if (i > 0) {
- node = pmc_agent_add(&priv, i);
- if (!node)
- goto end;
- }
/* uds local is formated '/var/run/phc2sys.<pid>.<source_interface>' */
snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d.%s",
getpid(), src->device);
- if (init_pmc_node(cfg, node, uds_local,
+ if (init_pmc_node(cfg, src->node, uds_local,
phc2sys_recv_subscribed, &priv))
goto end;
- /* map clock to pmc agent node */
- src->node = node;
- pr_debug("pmc node index %d source clock %s initialized",
- node->index, src->device);
-
while (is_running()) {
- r = run_pmc_wait_sync(node, 1000);
+ r = run_pmc_wait_sync(src->node, 1000);
if (r < 0)
goto end;
if (r > 0)
@@ -2324,7 +2320,7 @@ int main(int argc, char *argv[])
}
if (!priv.forced_sync_offset) {
- r = pmc_agent_query_utc_offset(node, 1000);
+ r = pmc_agent_query_utc_offset(src->node, 1000);
if (r) {
pr_err("failed to get UTC offset");
goto end;
@@ -2334,10 +2330,8 @@ int main(int argc, char *argv[])
if (priv.forced_sync_offset ||
(src->clkid != CLOCK_REALTIME && dst->clkid != CLOCK_REALTIME) ||
src->clkid == CLOCK_INVALID) {
- pmc_agent_disable(node);
+ pmc_agent_disable(src->node);
}
-
- ++i;
}
if (ha_enabled && !priv.forced_source_clock) {
--
2.25.1

View File

@ -8,3 +8,40 @@
0008-sysoff-Change-log-level-of-ioctl-error-messages.patch
0009-sysoff-Retry-on-EBUSY-when-probing-supported-ioctls.patch
0010-phc2sys-Don-t-exit-when-reading-of-PHC-fails-with-EB.patch
0011-phc2sys-extract-PMC-functionality-into-a-smaller-str.patch
0012-phc2sys-make-PMC-functions-non-static.patch
0013-phc2sys-break-out-pmc-code-into-pmc_common.c.patch
0014-Introduce-the-PMC-agent-module.patch
0015-pmc_agent-Rename-pmc_node-to-something-more-descript.patch
0016-pmc_agent-Hide-the-implementation.patch
0017-Find-a-better-home-for-the-management-TLV-ID-helper-.patch
0018-Find-a-better-home-for-the-management-TLV-data-helpe.patch
0019-Introduce-error-codes-for-the-run_pmc-method.patch
0020-pmc_agent-Convert-the-subscribe-method-into-the-cano.patch
0021-pmc_agent-Simplify-the-update-method.patch
0022-pmc_agent-Simplify-logic-in-update-method.patch
0023-pmc_agent-Remove-bogus-comparison-between-last-updat.patch
0024-pmc_agent-Perform-time-comparison-using-positive-log.patch
0025-pmc_agent-Rename-the-update-method-and-attempt-to-do.patch
0026-phc2sys-Fix-null-pointer-de-reference-in-manual-mode.patch
0027-pmc_agent-Convert-the-method-that-queries-TAI-UTC-of.patch
0028-pmc_agent-Convert-the-method-that-queries-the-port-p.patch
0029-pmc_agent-Generalize-the-method-that-queries-the-loc.patch
0030-pmc_agent-Simplify-the-method-that-gets-of-the-numbe.patch
0031-pmc_agent-Let-the-update-method-poll-for-push-events.patch
0032-phc2sys-Fix-regression-in-the-automatic-mode.patch
0033-Implement-push-notification-for-TIME_STATUS_NP.patch
0034-clock-Rename-UDS-variables-to-read-write.patch
0035-clock-Add-read-only-UDS-port-for-monitoring.patch
0036-Rename-management-ID-macros.patch
0037-Enhance-phc2sys-to-accept-multiple-ptp4l-inputs.patch
0038-Best-source-selection-algorithm.patch
0039-Select-best-source-clock-after-state-changes.patch
0040-Forced-lock-a-clock-source-in-configuration.patch
0041-HA-phc2sys-com-socket.patch
0042-Commands-enable-lock-and-disable-lock.patch
0043-Commands-enable-source-and-disable-source.patch
0044-Stream-type-phc2sys-com-socket.patch
0045-Functions-starts_with-and-str_at_column.patch
0046-Robustness-improvements-to-phc2sys-socket.patch
0047-phc2sys-without-w-option.patch