On Mon, 24 Apr 2023 at 11:08, Stephan Wurm <stephan.w...@a-eberle.de> wrote:
> Standard IEC 21439-3:2016 Appendix A extends the PTPv2 standard by the > definition of doubly attached clocks (DAC) via redundant ports (either > connected by HSR or PRP). Therefore, the state machine is extended by > state PASSIVE_SLAVE and transition PSLAVE. > > In order to take advantage of the DAC feature, two interfaces need to > be configured as redundant port by explicitly selecting the respective > other interface via the `paired_interface` configuration option. > > The new state is reported as PASSIVE via the management interface, > remaining compatible with the PTPv2 standard. > > Signed-off-by: Stephan Wurm <stephan.w...@a-eberle.de> > --- > bmc.c | 10 ++++++++ > clock.c | 4 ++++ > config.c | 1 + > e2e_tc.c | 1 + > fsm.c | 71 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > fsm.h | 2 ++ > p2p_tc.c | 2 ++ > pmc.c | 4 ++-- > port.c | 44 +++++++++++++++++++++++++++++++--- > port.h | 47 ++++++++++++++++++++++++------------ > port_private.h | 4 ++++ > port_signaling.c | 1 + > tc.c | 2 ++ > unicast_service.c | 1 + > util.c | 4 +++- > 15 files changed, 177 insertions(+), 21 deletions(-) > > diff --git a/bmc.c b/bmc.c > index ebc0789..1e1d83f 100644 > --- a/bmc.c > +++ b/bmc.c > @@ -130,12 +130,14 @@ enum port_state bmc_state_decision(struct clock *c, > struct port *r, > int (*compare)(struct dataset *a, > struct dataset *b)) > { > struct dataset *clock_ds, *clock_best, *port_best; > + struct port *paired_port; > enum port_state ps; > > clock_ds = clock_default_ds(c); > clock_best = clock_best_foreign(c); > port_best = port_best_foreign(r); > ps = port_state(r); > + paired_port = port_paired_port(r); > > /* > * This scenario is particularly important in the > designated_slave_fsm > @@ -167,6 +169,14 @@ enum port_state bmc_state_decision(struct clock *c, > struct port *r, > return PS_SLAVE; /*S1*/ > } > > + /* > + * This scenario handles the PASSIVE_SLAVE transition according to > + * IEC 62439-3 standard in case of a doubly attached clock. > + */ > + if (paired_port && (clock_best_port(c) == paired_port)) { > + return PS_PASSIVE_SLAVE; > + } > + > if (compare(clock_best, port_best) == A_BETTER_TOPO) { > return PS_PASSIVE; /*P2*/ > } else { > diff --git a/clock.c b/clock.c > index 75d7c40..d52e826 100644 > --- a/clock.c > +++ b/clock.c > @@ -1009,6 +1009,7 @@ static int clock_add_port(struct clock *c, const > char *phc_device, > return -1; > } > LIST_FOREACH(piter, &c->ports, list) { > + port_pair(piter, p); > lastp = piter; > } > if (lastp) { > @@ -2235,6 +2236,9 @@ static void handle_state_decision_event(struct clock > *c) > clock_update_slave(c); > event = EV_RS_SLAVE; > break; > + case PS_PASSIVE_SLAVE: > + event = EV_RS_PSLAVE; > + break; > default: > event = EV_FAULT_DETECTED; > break; > diff --git a/config.c b/config.c > index cb4421f..28beb3b 100644 > --- a/config.c > +++ b/config.c > @@ -298,6 +298,7 @@ struct config_item config_tab[] = { > GLOB_ITEM_INT("offsetScaledLogVariance", 0xffff, 0, UINT16_MAX), > PORT_ITEM_INT("operLogPdelayReqInterval", 0, INT8_MIN, INT8_MAX), > PORT_ITEM_INT("operLogSyncInterval", 0, INT8_MIN, INT8_MAX), > + PORT_ITEM_STR("paired_interface", ""), > PORT_ITEM_INT("path_trace_enabled", 0, 0, 1), > PORT_ITEM_INT("phc_index", -1, -1, INT_MAX), > GLOB_ITEM_DBL("pi_integral_const", 0.0, 0.0, DBL_MAX), > diff --git a/e2e_tc.c b/e2e_tc.c > index 2f8e821..94099eb 100644 > --- a/e2e_tc.c > +++ b/e2e_tc.c > @@ -69,6 +69,7 @@ void e2e_dispatch(struct port *p, enum fsm_event event, > int mdiff) > flush_delay_req(p); > /* fall through */ > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > port_set_announce_tmo(p); > break; > }; > diff --git a/fsm.c b/fsm.c > index ce6efad..9679fea 100644 > --- a/fsm.c > +++ b/fsm.c > @@ -80,6 +80,9 @@ enum port_state ptp_fsm(enum port_state state, enum > fsm_event event, int mdiff) > case EV_RS_PASSIVE: > next = PS_PASSIVE; > break; > + case EV_RS_PSLAVE: > + next = PS_PASSIVE_SLAVE; > + break; > default: > break; > } > @@ -102,6 +105,9 @@ enum port_state ptp_fsm(enum port_state state, enum > fsm_event event, int mdiff) > case EV_RS_PASSIVE: > next = PS_PASSIVE; > break; > + case EV_RS_PSLAVE: > + next = PS_PASSIVE_SLAVE; > + break; > default: > break; > } > @@ -122,6 +128,9 @@ enum port_state ptp_fsm(enum port_state state, enum > fsm_event event, int mdiff) > case EV_RS_PASSIVE: > next = PS_PASSIVE; > break; > + case EV_RS_PSLAVE: > + next = PS_PASSIVE_SLAVE; > + break; > default: > break; > } > @@ -210,6 +219,40 @@ enum port_state ptp_fsm(enum port_state state, enum > fsm_event event, int mdiff) > case EV_RS_PASSIVE: > next = PS_PASSIVE; > break; > + case EV_RS_PSLAVE: > + next = PS_PASSIVE_SLAVE; > + break; > + default: > + break; > + } > + break; > + > + case PS_PASSIVE_SLAVE: > + switch (event) { > + case EV_DESIGNATED_DISABLED: > + next = PS_DISABLED; > + break; > + case EV_FAULT_DETECTED: > + next = PS_FAULTY; > + break; > + case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES: > + next = PS_MASTER; > + break; > + case EV_SYNCHRONIZATION_FAULT: > + next = PS_LISTENING; > + break; > + case EV_RS_MASTER: > + next = PS_PRE_MASTER; > + break; > + case EV_RS_GRAND_MASTER: > + next = PS_GRAND_MASTER; > + break; > + case EV_RS_PASSIVE: > + next = PS_PASSIVE; > + break; > + case EV_RS_SLAVE: > + next = PS_SLAVE; > + break; > default: > break; > } > @@ -276,6 +319,9 @@ enum port_state ptp_slave_fsm(enum port_state state, > enum fsm_event event, > case EV_RS_SLAVE: > next = PS_UNCALIBRATED; > break; > + case EV_RS_PSLAVE: > + next = PS_PASSIVE_SLAVE; > + break; > default: > break; > } > @@ -324,6 +370,31 @@ enum port_state ptp_slave_fsm(enum port_state state, > enum fsm_event event, > if (mdiff) > next = PS_UNCALIBRATED; > break; > + case EV_RS_PSLAVE: > + next = PS_PASSIVE_SLAVE; > + break; > + default: > + break; > + } > + break; > + > + case PS_PASSIVE_SLAVE: > + switch (event) { > + case EV_DESIGNATED_DISABLED: > + next = PS_DISABLED; > + break; > + case EV_FAULT_DETECTED: > + next = PS_FAULTY; > + break; > + 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_SLAVE: > + next = PS_SLAVE; > + break; > default: > break; > } > diff --git a/fsm.h b/fsm.h > index 857af05..919e934 100644 > --- a/fsm.h > +++ b/fsm.h > @@ -31,6 +31,7 @@ enum port_state { > PS_PASSIVE, > PS_UNCALIBRATED, > PS_SLAVE, > + PS_PASSIVE_SLAVE, /*according to IEC 62439-3 doubly attached > clocks*/ > PS_GRAND_MASTER, /*non-standard extension*/ > }; > > @@ -53,6 +54,7 @@ enum fsm_event { > EV_RS_GRAND_MASTER, > EV_RS_SLAVE, > EV_RS_PASSIVE, > + EV_RS_PSLAVE, /*according to IEC 62439-3 doubly attached clocks*/ > }; > > enum bmca_select { > diff --git a/p2p_tc.c b/p2p_tc.c > index 75cb3b9..2aabba8 100644 > --- a/p2p_tc.c > +++ b/p2p_tc.c > @@ -37,6 +37,7 @@ static int p2p_delay_request(struct port *p) > case PS_PASSIVE: > case PS_UNCALIBRATED: > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > case PS_GRAND_MASTER: > break; > } > @@ -85,6 +86,7 @@ void p2p_dispatch(struct port *p, enum fsm_event event, > int mdiff) > break; > case PS_UNCALIBRATED: > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > port_set_announce_tmo(p); > break; > }; > diff --git a/pmc.c b/pmc.c > index 00e691f..af797bb 100644 > --- a/pmc.c > +++ b/pmc.c > @@ -463,7 +463,7 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) > break; > case MID_PORT_DATA_SET: > p = (struct portDS *) mgt->data; > - if (p->portState > PS_SLAVE) { > + if (p->portState > PS_PASSIVE_SLAVE) { > This is IEEE 1558 port state, you should add non IEEE 1558 port states here! Values are defined in IEEE 1588-2019 "8.2.15.3.1 portDS.portState". I think we have 3 options: Ask IEEE 1558 for a new port state. Use enterprise management tlv Perhaps Use high value like 0xf1? p->portState = 0; > } > fprintf(fp, "PORT_DATA_SET " > @@ -494,7 +494,7 @@ static void pmc_show(struct ptp_message *msg, FILE *fp) > break; > case MID_PORT_PROPERTIES_NP: > ppn = (struct port_properties_np *) mgt->data; > - if (ppn->port_state > PS_SLAVE) { > + if (ppn->port_state > PS_PASSIVE_SLAVE) { Although this is a linuxptp enterprise tlv. The port state are IEEE 1558. > ppn->port_state = 0; > } > fprintf(fp, "PORT_PROPERTIES_NP " > diff --git a/port.c b/port.c > index 3453716..d05797e 100644 > --- a/port.c > +++ b/port.c > @@ -989,6 +989,8 @@ static int port_management_fill_response(struct port > *target, > pds->portIdentity = target->portIdentity; > if (target->state == PS_GRAND_MASTER) { > pds->portState = PS_MASTER; > + } else if (target->state == PS_PASSIVE_SLAVE) { > + pds->portState = PS_PASSIVE; > This is correct :-) > } else { > pds->portState = target->state; > } > @@ -1053,10 +1055,13 @@ static int port_management_fill_response(struct > port *target, > case MID_PORT_PROPERTIES_NP: > ppn = (struct port_properties_np *)tlv->data; > ppn->portIdentity = target->portIdentity; > - if (target->state == PS_GRAND_MASTER) > + if (target->state == PS_GRAND_MASTER) { > ppn->port_state = PS_MASTER; > - else > + } else if (target->state == PS_PASSIVE_SLAVE) { > + ppn->port_state = PS_PASSIVE; > + } else { > ppn->port_state = target->state; > + } > ppn->timestamping = target->timestamping; > ts_label = interface_label(target->iface); > ptp_text_set(&ppn->interface, ts_label); > @@ -1365,6 +1370,7 @@ static void port_synchronize(struct port *p, > switch (p->state) { > case PS_UNCALIBRATED: > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > monitor_sync(p->slave_event_monitor, > clock_parent_identity(p->clock), seqid, > t1, tmv_add(c1, c2), t2); > @@ -1821,6 +1827,7 @@ int port_is_enabled(struct port *p) > case PS_PASSIVE: > case PS_UNCALIBRATED: > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > break; > } > return 1; > @@ -2094,6 +2101,7 @@ int process_announce(struct port *p, struct > ptp_message *m) > case PS_PASSIVE: > case PS_UNCALIBRATED: > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > result = update_current_master(p, m); > break; > } > @@ -2234,6 +2242,7 @@ void process_follow_up(struct port *p, struct > ptp_message *m) > return; > case PS_UNCALIBRATED: > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > break; > } > > @@ -2455,7 +2464,8 @@ calc: > > p->peerMeanPathDelay = tmv_to_TimeInterval(p->peer_delay); > > - if (p->state == PS_UNCALIBRATED || p->state == PS_SLAVE) { > + if (p->state == PS_UNCALIBRATED || p->state == PS_SLAVE || > + p->state == PS_PASSIVE_SLAVE) { > clock_peer_delay(p->clock, p->peer_delay, t1, t2, > p->nrate.ratio); > } > @@ -2538,6 +2548,7 @@ void process_sync(struct port *p, struct ptp_message > *m) > return; > case PS_UNCALIBRATED: > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > break; > } > > @@ -2678,6 +2689,9 @@ static void port_e2e_transition(struct port *p, enum > port_state next) > port_set_announce_tmo(p); > port_set_delay_tmo(p); > break; > + case PS_PASSIVE_SLAVE: > + port_set_announce_tmo(p); > + break; > }; > } > > @@ -2720,6 +2734,7 @@ static void port_p2p_transition(struct port *p, enum > port_state next) > flush_peer_delay(p); > /* fall through */ > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > port_set_announce_tmo(p); > break; > }; > @@ -3408,6 +3423,10 @@ struct port *port_open(const char *phc_device, > config_get_int(cfg, p->name, > "power_profile.2017.totalTimeInaccuracy"); > p->slave_event_monitor = clock_slave_monitor(clock); > > + p->paired_interface = config_get_string(cfg, p->name, > "paired_interface"); > + p->prpPairedPort = UINT16_MAX; > + p->paired_port = NULL; > + > if (!port_is_uds(p) && unicast_client_initialize(p)) { > goto err_transport; > } > @@ -3550,3 +3569,22 @@ void port_update_unicast_state(struct port *p) > p->unicast_state_dirty = false; > } > } > + > +void port_pair(struct port *p, struct port *o) > +{ > + if ((strncmp(p->paired_interface, interface_name(o->iface), > + MAX_IFNAME_SIZE) == 0) && > + (strncmp(o->paired_interface, > interface_name(p->iface), > + MAX_IFNAME_SIZE) == 0)) { > + p->paired_port = o; > + p->prpPairedPort = portnum(o); > + o->paired_port = p; > + o->prpPairedPort = portnum(p); > + pr_info("Created redundancy pair from ports %s and %s", > p->name, o->name); > + } > +} > + > +struct port *port_paired_port(struct port *p) > +{ > + return p->paired_port; > +} > diff --git a/port.h b/port.h > index 57c8c2f..f1deaf1 100644 > --- a/port.h > +++ b/port.h > In this file it seems you just add spaces. Please, only real changes, no spaces! > @@ -205,7 +205,7 @@ void port_notify_event(struct port *p, enum > notification event); > * @param phc_device The name of PHC device as found on the command > line. > * @param phc_index The PHC device index for the network device. > * @param timestamping The timestamping mode for this port. > - * @param number An arbitrary number assigned to this port. > + * @param number An arbitrary number assigned to this port. > Any change here? > * @param interface The interface data > * @param clock A pointer to the system PTP clock. > * @return A pointer to an open port on success, or NULL otherwise. > @@ -229,8 +229,8 @@ enum port_state port_state(struct port *port); > > /** > * Return port's delay mechanism method. > - * @param port A port instance. > - * @return one of the @ref delay_mechanism values. > + * @param port A port instance. > + * @return one of the @ref delay_mechanism values. > Any change here? > */ > enum delay_mechanism port_delay_mechanism(struct port *port); > > @@ -246,16 +246,16 @@ int port_state_update(struct port *p, enum fsm_event > event, int mdiff); > /** > * Return array of file descriptors for this port. The fault fd is not > * included. > - * @param port A port instance > - * @return Array of file descriptors. Unused descriptors are guranteed > - * to be set to -1. > + * @param port A port instance > + * @return Array of file descriptors. Unused descriptors are > guranteed > + * to be set to -1. > Any change here? > */ > struct fdarray *port_fda(struct port *port); > > /** > * Return file descriptor of the port. > - * @param port A port instance. > - * @return File descriptor or -1 if not applicable. > + * @param port A port instance. > + * @return File descriptor or -1 if not applicable. > Any change here? > */ > int port_fault_fd(struct port *port); > > @@ -307,10 +307,10 @@ int set_tmo_lin(int fd, int seconds); > * Sets port's fault file descriptor timer. > * Passing both 'scale' and 'log_seconds' as zero disables the timer. > * > - * @param fd A port instance. > - * @param scale The multiplicative factor for the timer. > - * @param log_seconds The exponential factor for the timer. > - * @return Zero on success, non-zero otherwise. > + * @param fd A port instance. > + * @param scale The multiplicative factor for the timer. > + * @param log_seconds The exponential factor for the timer. > + * @return Zero on success, non-zero otherwise. > Any change here? > */ > int port_set_fault_timer_log(struct port *port, > unsigned int scale, int log_seconds); > @@ -319,9 +319,9 @@ int port_set_fault_timer_log(struct port *port, > * Sets port's fault file descriptor timer. > * Passing 'seconds' as zero disables the timer. > * > - * @param fd A port instance. > - * @param seconds The timeout value for the timer. > - * @return Zero on success, non-zero otherwise. > + * @param fd A port instance. > + * @param seconds The timeout value for the timer. > + * @return Zero on success, non-zero otherwise. > Any change here? > */ > int port_set_fault_timer_lin(struct port *port, int seconds); > > @@ -364,4 +364,21 @@ void tc_cleanup(void); > */ > void port_update_unicast_state(struct port *p); > > +/** > + * Pair redundant ports according to IEC 62439-3 standard. > + * > + * @param port A port instance. > + * @param port Another port instance. > + */ > +void port_pair(struct port *p, struct port *o); > + > +/** > + * Get the associated paired port according to IEC 62439-3 standard. > + * > + * @param port A port instance. > + * @return Pointer to the paired port instance, > + * or NULL if not a doubly attached clock. > + */ > +struct port *port_paired_port(struct port *p); > + > #endif > diff --git a/port_private.h b/port_private.h > index 3b02d2f..c99d972 100644 > --- a/port_private.h > +++ b/port_private.h > @@ -150,6 +150,10 @@ struct port { > Integer64 portAsymmetry; > struct PortStats stats; > struct PortServiceStats service_stats; > + /* IEC 62439-3 portDS additions */ > + char *paired_interface; > + UInteger16 prpPairedPort; > + struct port *paired_port; > /* foreignMasterDS */ > LIST_HEAD(fm, foreign_clock) foreign_masters; > /* TC book keeping */ > diff --git a/port_signaling.c b/port_signaling.c > index 5a764d6..20a0369 100644 > --- a/port_signaling.c > +++ b/port_signaling.c > @@ -148,6 +148,7 @@ int process_signaling(struct port *p, struct > ptp_message *m) > case PS_PASSIVE: > case PS_UNCALIBRATED: > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > break; > } > > diff --git a/tc.c b/tc.c > index 2e3830c..789a0bb 100644 > --- a/tc.c > +++ b/tc.c > @@ -87,6 +87,7 @@ static int tc_blocked(struct port *q, struct port *p, > struct ptp_message *m) > break; > case PS_UNCALIBRATED: > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > break; > } > /* Egress state */ > @@ -101,6 +102,7 @@ static int tc_blocked(struct port *q, struct port *p, > struct ptp_message *m) > return 1; > case PS_UNCALIBRATED: > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > /* Delay_Req swims against the stream. */ > if (msg_type(m) != DELAY_REQ) { > return 1; > diff --git a/unicast_service.c b/unicast_service.c > index 687468c..3e57806 100644 > --- a/unicast_service.c > +++ b/unicast_service.c > @@ -532,6 +532,7 @@ int unicast_service_timer(struct port *p) > case PS_PASSIVE: > case PS_UNCALIBRATED: > case PS_SLAVE: > + case PS_PASSIVE_SLAVE: > break; > case PS_MASTER: > case PS_GRAND_MASTER: > diff --git a/util.c b/util.c > index e204c9c..a3de8c7 100644 > --- a/util.c > +++ b/util.c > @@ -45,9 +45,10 @@ const char *ps_str[] = { > "LISTENING", > "PRE_MASTER", > "MASTER", > - "PASSIVE", > + "PASSIVE", /*PASSIVE_MASTER*/ > "UNCALIBRATED", > "SLAVE", > + "PASSIVE", /*PASSIVE_SLAVE*/ > "GRAND_MASTER", > }; > > @@ -69,6 +70,7 @@ const char *ev_str[] = { > "RS_GRAND_MASTER", > "RS_SLAVE", > "RS_PASSIVE", > + "RS_PSLAVE", > }; > > const char *ts_str(enum timestamp_type ts) > > -- > 2.34.1 > > > > _______________________________________________ > Linuxptp-devel mailing list > Linuxptp-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/linuxptp-devel >
_______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel