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