On 8/1/2020 10:46 AM, Vladimir Oltean wrote:
> Move the code for sending various messages to ptp4l via pmc to a common
> 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.
> 
> 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.

Ah, perfect: pmc_node is not too generic, so this is great.

I looked this over using git diff with the moved lines coloring options,
and the only places where the new code differs is in name change from
priv to pmc_node.

Makes sense.

Reviewed-by: Jacob Keller <jacob.e.kel...@intel.com>

> 
> Signed-off-by: Vladimir Oltean <olte...@gmail.com>
> ---
>  phc2sys.c    | 404 +++++----------------------------------------------
>  pmc_common.c | 337 ++++++++++++++++++++++++++++++++++++++++++
>  pmc_common.h |  35 +++++
>  3 files changed, 407 insertions(+), 369 deletions(-)
> 
> diff --git a/phc2sys.c b/phc2sys.c
> index a36cbe071d7d..c4d72bd7d17a 100644
> --- a/phc2sys.c
> +++ b/phc2sys.c
> @@ -56,18 +56,13 @@
>  #include "uds.h"
>  #include "util.h"
>  #include "version.h"
> +#include "contain.h"
>  
>  #define KP 0.7
>  #define KI 0.3
>  #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;
> @@ -105,17 +100,10 @@ struct phc2sys_private {
>       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;
> @@ -124,18 +112,11 @@ struct phc2sys_private {
>  
>  static struct config *phc2sys_config;
>  
> -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);
> -static int run_pmc_get_utc_offset(struct phc2sys_private *priv,
> -                               int timeout);
> -static void run_pmc_events(struct phc2sys_private *priv);
>  
>  static int normalize_state(int state);
> -static int run_pmc_port_properties(struct phc2sys_private *priv,
> -                                int timeout, unsigned int port,
> -                                int *state, int *tstamping, char *iface);
>  
>  static struct servo *servo_add(struct phc2sys_private *priv,
>                              struct clock *clock)
> @@ -324,7 +305,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)
> @@ -659,7 +640,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);
>       }
> @@ -690,7 +671,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);
>       }
> @@ -727,15 +708,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;
>                               }
> @@ -792,53 +773,6 @@ 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)
> -{
> -     if (!priv->clock_identity_set)
> -             return 1;
> -     return cid_eq(&priv->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;
> -}
> -
> -static 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)
> -{
> -     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 &&
> @@ -868,9 +802,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;
> @@ -905,259 +843,6 @@ static int recv_subscribed(struct phc2sys_private *priv,
>       return 0;
>  }
>  
> -static void send_subscription(struct phc2sys_private *priv)
> -{
> -     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));
> -}
> -
> -static int init_pmc(struct config *cfg, struct phc2sys_private *priv)
> -{
> -     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,
> -                            config_get_int(cfg, NULL, "domainNumber"),
> -                            config_get_int(cfg, NULL, "transportSpecific") 
> << 4, 1);
> -     if (!priv->pmc) {
> -             pr_err("failed to create pmc");
> -             return -1;
> -     }
> -
> -     return 0;
> -}
> -
> -/* Return values:
> - * 1: success
> - * 0: timeout
> - * -1: error reported by the other side
> - * -2: local error, fatal
> - */
> -static int run_pmc(struct phc2sys_private *priv, 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(priv->pmc);
> -             pollfd[0].events = POLLIN|POLLPRI;
> -             if (!priv->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. */
> -                     priv->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(priv);
> -                             break;
> -                     default:
> -                             pmc_send_get_action(priv->pmc, ds_id);
> -                             break;
> -                     }
> -                     priv->pmc_ds_requested = 1;
> -             }
> -
> -             if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
> -                     continue;
> -
> -             *msg = pmc_recv(priv->pmc);
> -
> -             if (!*msg)
> -                     continue;
> -
> -             if (!check_clock_identity(priv, *msg)) {
> -                     msg_put(*msg);
> -                     *msg = NULL;
> -                     continue;
> -             }
> -
> -             res = is_msg_mgt(*msg);
> -             if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
> -                     priv->pmc_ds_requested = 0;
> -                     return -1;
> -             }
> -             if (res <= 0 || recv_subscribed(priv, *msg, ds_id) ||
> -                 get_mgt_id(*msg) != ds_id) {
> -                     msg_put(*msg);
> -                     *msg = NULL;
> -                     continue;
> -             }
> -             priv->pmc_ds_requested = 0;
> -             return 1;
> -     }
> -}
> -
> -static int run_pmc_wait_sync(struct phc2sys_private *priv, int timeout)
> -{
> -     struct ptp_message *msg;
> -     int res;
> -     void *data;
> -     Enumeration8 portState;
> -
> -     while (1) {
> -             res = run_pmc(priv, 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) */
> -             priv->pmc_ds_requested = 1;
> -     }
> -}
> -
> -static int run_pmc_get_utc_offset(struct phc2sys_private *priv, int timeout)
> -{
> -     struct ptp_message *msg;
> -     int res;
> -     struct timePropertiesDS *tds;
> -
> -     res = run_pmc(priv, 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;
> -             if (tds->flags & LEAP_61)
> -                     priv->leap = 1;
> -             else if (tds->flags & LEAP_59)
> -                     priv->leap = -1;
> -             else
> -                     priv->leap = 0;
> -             priv->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;
> -     }
> -     msg_put(msg);
> -     return 1;
> -}
> -
> -static int run_pmc_get_number_ports(struct phc2sys_private *priv, int 
> timeout)
> -{
> -     struct ptp_message *msg;
> -     int res;
> -     struct defaultDS *dds;
> -
> -     res = run_pmc(priv, 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;
> -}
> -
> -static int run_pmc_subscribe(struct phc2sys_private *priv, int timeout)
> -{
> -     struct ptp_message *msg;
> -     int res;
> -
> -     res = run_pmc(priv, 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)
> -{
> -     struct ptp_message *msg;
> -
> -     run_pmc(priv, 0, -1, &msg);
> -}
> -
> -static int run_pmc_port_properties(struct phc2sys_private *priv, 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);
> -     while (1) {
> -             res = run_pmc(priv, 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(priv->pmc);
> -     return res;
> -}
> -
> -static int run_pmc_clock_identity(struct phc2sys_private *priv, int timeout)
> -{
> -     struct ptp_message *msg;
> -     struct defaultDS *dds;
> -     int res;
> -
> -     res = run_pmc(priv, timeout, TLV_DEFAULT_DATA_SET, &msg);
> -     if (res <= 0)
> -             return res;
> -
> -     dds = (struct defaultDS *)get_mgt_data(msg);
> -     memcpy(&priv->clock_identity, &dds->clockIdentity,
> -            sizeof(struct ClockIdentity));
> -     priv->clock_identity_set = 1;
> -     msg_put(msg);
> -     return 1;
> -}
> -
> -static void close_pmc(struct phc2sys_private *priv)
> -{
> -     pmc_destroy(priv->pmc);
> -     priv->pmc = NULL;
> -}
> -
>  static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
>  {
>       struct port *port;
> @@ -1170,7 +855,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)
> @@ -1179,20 +864,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 */
> @@ -1229,44 +914,20 @@ 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;
>       }
>       return 0;
>  }
>  
> -/* Returns: -1 in case of error, 0 otherwise */
> -static int update_pmc(struct phc2sys_private *priv, 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 (priv->pmc &&
> -         !(ts > priv->pmc_last_update &&
> -           ts - priv->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;
> -     }
> -
> -     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)
>  {
> -     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) {
> @@ -1307,7 +968,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);
> @@ -1361,6 +1022,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;
> @@ -1469,7 +1131,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;
> @@ -1589,8 +1251,12 @@ int main(int argc, char *argv[])
>       priv.kernel_leap = config_get_int(cfg, NULL, "kernel_leap");
>       priv.sanity_freq_limit = config_get_int(cfg, NULL, "sanity_freq_limit");
>  
> +     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;
> @@ -1627,11 +1293,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)
> @@ -1641,7 +1308,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;
> @@ -1651,7 +1318,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) {
> @@ -1664,8 +1331,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);
> diff --git a/pmc_common.c b/pmc_common.c
> index f07f6f65568f..89d7f40b84fe 100644
> --- a/pmc_common.c
> +++ b/pmc_common.c
> @@ -22,6 +22,8 @@
>  #include <string.h>
>  #include <sys/types.h>
>  #include <unistd.h>
> +#include <net/if.h>
> +#include <poll.h>
>  
>  #include "notification.h"
>  #include "print.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 9fa72deb4c87..a28bab767e9c 100644
> --- a/pmc_common.h
> +++ b/pmc_common.h
> @@ -24,6 +24,7 @@
>  #include "config.h"
>  #include "msg.h"
>  #include "transport.h"
> +#include "fsm.h"
>  
>  struct pmc;
>  
> @@ -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
> 


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

Reply via email to