This change brings slave clock jbod feature which allows ptp4l to work as a
Ordinary Subordinate/Slave clock using "just a bunch of devices" that are not
synchronized to each other but a collection of clocks synchronized by an 
external
source.The best master will be decided by BMCA among the collection of the 
clocks.
This feature gets enabled by ptp4l config option: slave_clock_jbod and
by default it is disabled.

Signed-off-by: Amar Subramanyam <asubraman...@altiostar.com>
Signed-off-by: Ramana Reddy  <rre...@altiostar.com>
---
 bmc.c            |  4 ++++
 clock.c          | 14 ++++++++++++++
 clock.h          |  7 +++++++
 config.c         |  1 +
 designated_fsm.c |  4 ++--
 designated_fsm.h |  6 ++++--
 fsm.c            | 51 ++++++++++++++++++++++++++++++++++++++++++++++-----
 fsm.h            |  7 +++++--
 port.c           | 20 +++++++++++++++-----
 port.h           |  7 +++++++
 port_private.h   |  3 ++-
 ptp4l.8          | 10 ++++++++++
 unicast_client.c |  1 +
 13 files changed, 118 insertions(+), 17 deletions(-)

diff --git a/bmc.c b/bmc.c
index 6ac7aa0..11e8231 100644
--- a/bmc.c
+++ b/bmc.c
@@ -156,6 +156,10 @@ enum port_state bmc_state_decision(struct clock *c, struct 
port *r,
                return PS_SLAVE; /*S1*/
        }
 
+       if (port_sjbod(r)) {
+               return PS_PASSIVE;
+       }
+
        if (compare(clock_best, port_best) == A_BETTER_TOPO) {
                return PS_PASSIVE; /*P2*/
        } else {
diff --git a/clock.c b/clock.c
index 85d7667..32e41a2 100644
--- a/clock.c
+++ b/clock.c
@@ -1870,6 +1870,20 @@ enum servo_state clock_synchronize(struct clock *c, 
tmv_t ingress, tmv_t origin)
        return state;
 }
 
+int clock_isany_slave(struct clock *c)
+{
+       struct port *piter;
+
+       LIST_FOREACH(piter, &c->ports, list) {
+               enum port_state ps = port_state(piter);
+
+               if (ps == PS_SLAVE || ps == PS_UNCALIBRATED) {
+                       return 0;
+               }
+       }
+       return 1;
+}
+
 void clock_sync_interval(struct clock *c, int n)
 {
        int shift;
diff --git a/clock.h b/clock.h
index 845d54f..30050c3 100644
--- a/clock.h
+++ b/clock.h
@@ -374,4 +374,11 @@ void clock_check_ts(struct clock *c, uint64_t ts);
  */
 double clock_rate_ratio(struct clock *c);
 
+/**
+ * Check whether any slave port is present in the clock
+ * @param c  The clock instance.
+ * @return   Return 0 if any slave port is present
+ */
+int clock_isany_slave(struct clock *c);
+
 #endif
diff --git a/config.c b/config.c
index 4472d3d..ab4596f 100644
--- a/config.c
+++ b/config.c
@@ -301,6 +301,7 @@ struct config_item config_tab[] = {
        PORT_ITEM_INT("serverOnly", 0, 0, 1),
        GLOB_ITEM_INT("servo_num_offset_values", 10, 0, INT_MAX),
        GLOB_ITEM_INT("servo_offset_threshold", 0, 0, INT_MAX),
+       PORT_ITEM_INT("slave_clock_jbod", 0, 0, 1),
        GLOB_ITEM_STR("slave_event_monitor", ""),
        GLOB_ITEM_INT("slaveOnly", 0, 0, 1), /*deprecated*/
        GLOB_ITEM_INT("socket_priority", 0, 0, 15),
diff --git a/designated_fsm.c b/designated_fsm.c
index d19158b..d3c93ec 100644
--- a/designated_fsm.c
+++ b/designated_fsm.c
@@ -22,7 +22,7 @@
 
 enum port_state designated_master_fsm(enum port_state state,
                                      enum fsm_event event,
-                                     int mdiff)
+                                     int mdiff, int sjbod)
 {
        enum port_state next = state;
 
@@ -63,7 +63,7 @@ enum port_state designated_master_fsm(enum port_state state,
 
 enum port_state designated_slave_fsm(enum port_state state,
                                     enum fsm_event event,
-                                    int mdiff)
+                                    int mdiff, int sjbod)
 {
        enum port_state next = state;
 
diff --git a/designated_fsm.h b/designated_fsm.h
index 8ffa1a3..2c73d13 100644
--- a/designated_fsm.h
+++ b/designated_fsm.h
@@ -27,20 +27,22 @@
  * @param state  The current state of the port.
  * @param event  The event to be processed.
  * @param mdiff  This param is not used by this function.
+ * @param sjbod  This param is not used by this function.
  * @return       The new state for the port.
  */
 enum port_state designated_master_fsm(enum port_state state,
                                      enum fsm_event event,
-                                     int mdiff);
+                                     int mdiff, int sjbod);
 
 /**
  * Run the state machine for a clock designated as slave port.
  * @param state  The current state of the port.
  * @param event  The event to be processed.
  * @param mdiff  This param is not used by this function.
+ * @param sjbod  This param is not used by this function.
  * @return       The new state for the port.
  */
 enum port_state designated_slave_fsm(enum port_state state,
                                     enum fsm_event event,
-                                    int mdiff);
+                                    int mdiff, int sjbod);
 #endif
diff --git a/fsm.c b/fsm.c
index ce6efad..b4adc64 100644
--- a/fsm.c
+++ b/fsm.c
@@ -18,7 +18,8 @@
  */
 #include "fsm.h"
 
-enum port_state ptp_fsm(enum port_state state, enum fsm_event event, int mdiff)
+enum port_state ptp_fsm(enum port_state state, enum fsm_event event, int mdiff,
+                       int sjbod)
 {
        enum port_state next = state;
 
@@ -220,7 +221,7 @@ enum port_state ptp_fsm(enum port_state state, enum 
fsm_event event, int mdiff)
 }
 
 enum port_state ptp_slave_fsm(enum port_state state, enum fsm_event event,
-                             int mdiff)
+                             int mdiff, int sjbod)
 {
        enum port_state next = state;
 
@@ -270,9 +271,15 @@ enum port_state ptp_slave_fsm(enum port_state state, enum 
fsm_event event,
                case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES:
                case EV_RS_MASTER:
                case EV_RS_GRAND_MASTER:
-               case EV_RS_PASSIVE:
                        next = PS_LISTENING;
                        break;
+               case EV_RS_PASSIVE:
+                       if (sjbod) {
+                               next = PS_PASSIVE;
+                       } else {
+                               next = PS_LISTENING;
+                       }
+                       break;
                case EV_RS_SLAVE:
                        next = PS_UNCALIBRATED;
                        break;
@@ -292,9 +299,15 @@ enum port_state ptp_slave_fsm(enum port_state state, enum 
fsm_event event,
                case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES:
                case EV_RS_MASTER:
                case EV_RS_GRAND_MASTER:
-               case EV_RS_PASSIVE:
                        next = PS_LISTENING;
                        break;
+               case EV_RS_PASSIVE:
+                       if (sjbod) {
+                               next = PS_PASSIVE;
+                       } else {
+                               next = PS_LISTENING;
+                       }
+                       break;
                case EV_MASTER_CLOCK_SELECTED:
                        next = PS_SLAVE;
                        break;
@@ -314,9 +327,15 @@ enum port_state ptp_slave_fsm(enum port_state state, enum 
fsm_event event,
                case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES:
                case EV_RS_MASTER:
                case EV_RS_GRAND_MASTER:
-               case EV_RS_PASSIVE:
                        next = PS_LISTENING;
                        break;
+               case EV_RS_PASSIVE:
+                       if (sjbod) {
+                               next = PS_PASSIVE;
+                       } else {
+                               next = PS_LISTENING;
+                       }
+                       break;
                case EV_SYNCHRONIZATION_FAULT:
                        next = PS_UNCALIBRATED;
                        break;
@@ -328,6 +347,28 @@ enum port_state ptp_slave_fsm(enum port_state state, enum 
fsm_event event,
                        break;
                }
                break;
+       case PS_PASSIVE:
+               if (sjbod) {
+                       switch (event) {
+                       case EV_DESIGNATED_DISABLED:
+                               next = PS_DISABLED;
+                               break;
+                       case EV_FAULT_DETECTED:
+                               next = PS_FAULTY;
+                               break;
+                       case EV_RS_SLAVE:
+                               next = PS_UNCALIBRATED;
+                               break;
+                       case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES:
+                               next = PS_LISTENING;
+                               break;
+                       default:
+                               break;
+                       }
+               } else {
+                       next = PS_LISTENING;
+               }
+               break;
 
        default:
                break;
diff --git a/fsm.h b/fsm.h
index 857af05..016e3fb 100644
--- a/fsm.h
+++ b/fsm.h
@@ -65,18 +65,21 @@ enum bmca_select {
  * @param state  The current state of the port.
  * @param event  The event to be processed.
  * @param mdiff  Whether a new master has been selected.
+ * @param sjbod  This parameter is not used by this function.
  * @return       The new state for the port.
  */
-enum port_state ptp_fsm(enum port_state state, enum fsm_event event, int 
mdiff);
+enum port_state ptp_fsm(enum port_state state, enum fsm_event event,
+                       int mdiff, int sjbod);
 
 /**
  * Run the state machine for a slave only clock.
  * @param state  The current state of the port.
  * @param event  The event to be processed.
  * @param mdiff  Whether a new master has been selected.
+ * @param sjbod  The sjbod flag of the port.
  * @return       The new state for the port.
  */
 enum port_state ptp_slave_fsm(enum port_state state, enum fsm_event event,
-                             int mdiff);
+                             int mdiff, int sjbod);
 
 #endif
diff --git a/port.c b/port.c
index da7c327..2af6149 100644
--- a/port.c
+++ b/port.c
@@ -2545,7 +2545,7 @@ static void bc_dispatch(struct port *p, enum fsm_event 
event, int mdiff)
                port_e2e_transition(p, p->state);
        }
 
-       if (p->jbod && p->state == PS_UNCALIBRATED) {
+       if ((p->jbod || p->sjbod) && p->state == PS_UNCALIBRATED) {
                if (clock_switch_phc(p->clock, p->phc_index)) {
                        p->last_fault_type = FT_SWITCH_PHC;
                        port_dispatch(p, EV_FAULT_DETECTED, 0);
@@ -2653,6 +2653,10 @@ static enum fsm_event bc_event(struct port *p, int 
fd_index)
                        port_set_announce_tmo(p);
                }
 
+               if (port_sjbod(p) && !clock_isany_slave(p->clock)) {
+                       port_clr_tmo(p->fda.fd[FD_ANNOUNCE_TIMER]);
+               }
+
                delay_req_prune(p);
                if (clock_slave_only(p->clock) && p->delayMechanism != DM_P2P &&
                    port_renew_transport(p)) {
@@ -2852,6 +2856,11 @@ const char *port_log_name(struct port *p)
        return p->log_name;
 }
 
+int port_sjbod(struct port *p)
+{
+       return p->sjbod;
+}
+
 int port_link_status_get(struct port *p)
 {
        return !!(p->link_status & LINK_UP);
@@ -3073,6 +3082,7 @@ struct port *port_open(const char *phc_device,
        p->phc_index = phc_index;
        p->jbod = config_get_int(cfg, interface_name(interface), 
"boundary_clock_jbod");
        p->master_only = config_get_int(cfg, interface_name(interface), 
"serverOnly");
+       p->sjbod = config_get_int(cfg, interface_name(interface), 
"slave_clock_jbod");
        p->bmca = config_get_int(cfg, interface_name(interface), "BMCA");
        p->trp = transport_create(cfg, config_get_int(cfg,
                              interface_name(interface), "network_transport"));
@@ -3099,7 +3109,7 @@ struct port *port_open(const char *phc_device,
                pr_warning("%s: get_ts_info not supported", p->log_name);
        } else if (phc_index >= 0 &&
                   phc_index != interface_phc_index(interface)) {
-               if (p->jbod) {
+               if (p->jbod || p->sjbod) {
                        pr_warning("%s: just a bunch of devices", p->log_name);
                        p->phc_index = interface_phc_index(interface);
                } else if (phc_device) {
@@ -3224,14 +3234,14 @@ enum port_state port_state(struct port *port)
 
 int port_state_update(struct port *p, enum fsm_event event, int mdiff)
 {
-       enum port_state next = p->state_machine(p->state, event, mdiff);
+       enum port_state next = p->state_machine(p->state, event, mdiff, 
p->sjbod);
 
        if (PS_FAULTY == next) {
                struct fault_interval i;
                fault_interval(p, last_fault_type(p), &i);
                if (clear_fault_asap(&i)) {
                        pr_notice("%s: clearing fault immediately", 
p->log_name);
-                       next = p->state_machine(next, EV_FAULT_CLEARED, 0);
+                       next = p->state_machine(next, EV_FAULT_CLEARED, 0, 
p->sjbod);
                }
        }
 
@@ -3249,7 +3259,7 @@ int port_state_update(struct port *p, enum fsm_event 
event, int mdiff)
                } else {
                        event = EV_INIT_COMPLETE;
                }
-               next = p->state_machine(next, event, 0);
+               next = p->state_machine(next, event, 0, p->sjbod);
        }
 
        if (mdiff) {
diff --git a/port.h b/port.h
index 37a4e19..d9ee893 100644
--- a/port.h
+++ b/port.h
@@ -135,6 +135,13 @@ int port_number(struct port *p);
 const char *port_log_name(struct port *p);
 
 /**
+ * Obtain the port sjbod flag of a port
+ * @param p        A port instance.
+ * @return         sjbod flag of 'p'.
+ */
+int port_sjbod(struct port *p);
+
+/**
  * Obtain the link status of a port.
  * @param p        A port instance.
  * @return         One (1) if the link is up, zero otherwise.
diff --git a/port_private.h b/port_private.h
index 2a98ef4..37ee8b4 100644
--- a/port_private.h
+++ b/port_private.h
@@ -91,6 +91,7 @@ struct port {
                UInteger16 signaling;
                UInteger16 sync;
        } seqnum;
+       int sjbod;
        tmv_t peer_delay;
        struct tsproc *tsproc;
        int log_sync_interval;
@@ -99,7 +100,7 @@ struct port {
        unsigned int multiple_seq_pdr_count;
        unsigned int multiple_pdr_detected;
        enum port_state (*state_machine)(enum port_state state,
-                                        enum fsm_event event, int mdiff);
+                                        enum fsm_event event, int mdiff, int 
sjbod);
        int bmca;
        int inhibit_announce;
        int ignore_source_id;
diff --git a/ptp4l.8 b/ptp4l.8
index fe9e150..886815a 100644
--- a/ptp4l.8
+++ b/ptp4l.8
@@ -369,6 +369,16 @@ collection of clocks must be synchronized by an external 
program, for
 example phc2sys(8) in "automatic" mode.
 The default is 0 (disabled).
 .TP
+.B slave_clock_jbod
+When running as a ordinary clock-Subordinate/Slave (that is, when more
+than one network interface is configured), ptp4l performs a sanity check
+to make sure that all of the ports share the same hardware clock device.
+This option allows ptp4l to work as a Orindary Subordinate/Slave clock
+using "just a bunch of devices" that are not synchronized to each other.
+For this mode, the collection of clocks must be synchronized by an external
+program, for example phc2sys(8) in "automatic" mode.
+The default is 0 (disabled).
+.TP
 .B udp_ttl
 Specifies the Time to live (TTL) value for IPv4 multicast messages and the hop
 limit for IPv6 multicast messages. This option is only relevant with the IPv4
diff --git a/unicast_client.c b/unicast_client.c
index 87d8471..a962388 100644
--- a/unicast_client.c
+++ b/unicast_client.c
@@ -476,6 +476,7 @@ void unicast_client_grant(struct port *p, struct 
ptp_message *m,
                        }
                        unicast_client_set_renewal(p, ucma, g->durationField);
                        clock_sync_interval(p->clock, g->logInterMessagePeriod);
+                       p->log_sync_interval = g->logInterMessagePeriod;
                        break;
                }
                break;
-- 
1.8.3.1



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

Reply via email to