diff --git a/clock.c b/clock.c index d9dd518..50b6a15 100644 --- a/clock.c +++ b/clock.c @@ -72,7 +72,6 @@ struct clock { struct port *port[CLK_N_PORTS]; struct pollfd pollfd[CLK_N_PORTS*N_CLOCK_PFD]; int fault_fd[CLK_N_PORTS]; - int8_t fault_timeout[CLK_N_PORTS]; int nports; /* does not include the UDS port */ int free_running; int freq_est_interval; @@ -123,18 +122,27 @@ void clock_destroy(struct clock *c) static int clock_fault_timeout(struct clock *c, int index, int set) { - int log_seconds = 0; - unsigned int scale = 0; + struct fault_interval i; - if (set) { - pr_debug("waiting 2^{%d} seconds to clear fault on port %d", - c->fault_timeout[index], index); - log_seconds = c->fault_timeout[index]; - scale = 1; - } else { + if (!set) { pr_debug("clearing fault on port %d", index); + return set_tmo_lin(c->fault_fd[index], 0); } - return set_tmo_log(c->fault_fd[index], scale, log_seconds); + + fault_interval(c->port[index], last_fault_type(c->port[index]), &i); + + if (i.type == FTMO_LINEAR_SECONDS) { + pr_debug("waiting %d seconds to clear fault on port %d", + i.val, index); + return set_tmo_lin(c->fault_fd[index], i.val); + } else if (i.type == FTMO_LOG2_SECONDS) { + pr_debug("waiting 2^{%d} seconds to clear fault on port %d", + i.val, index); + return set_tmo_log(c->fault_fd[index], 1, i.val); + } + + pr_err("Unsupported fault interval type %d", i.type); + return -1; } static void clock_freq_est_reset(struct clock *c) @@ -618,7 +626,6 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, clock_sync_interval(c, 0); for (i = 0; i < count; i++) { - c->fault_timeout[i] = iface[i].pod.fault_reset_interval; c->port[i] = port_open(phc_index, timestamping, 1+i, &iface[i], c); if (!c->port[i]) { pr_err("failed to open port %s", iface[i].name); diff --git a/config.c b/config.c index 1e5c7ff..0b3abb4 100644 --- a/config.c +++ b/config.c @@ -113,10 +113,11 @@ static enum parser_result parse_pod_setting(const char *option, pod->neighborPropDelayThresh = val; } else if (!strcmp(option, "fault_reset_interval")) { + pod->flt_interval_pertype[FT_UNSPECIFIED].type = FTMO_LOG2_SECONDS; if (!strcasecmp("ASAP", value)) { - pod->fault_reset_interval = FRI_ASAP; + pod->flt_interval_pertype[FT_UNSPECIFIED].val = FRI_ASAP; } else if (1 == sscanf(value, "%hhd", &i8)) { - pod->fault_reset_interval = i8; + pod->flt_interval_pertype[FT_UNSPECIFIED].val = i8; } else { return BAD_VALUE; } diff --git a/ds.h b/ds.h index 05d49bc..757e1be 100644 --- a/ds.h +++ b/ds.h @@ -21,6 +21,7 @@ #define HAVE_DS_H #include "ddt.h" +#include "fault.h" /* clock data sets */ @@ -124,7 +125,7 @@ struct port_defaults { int path_trace_enabled; int follow_up_info; int freq_est_interval; /*log seconds*/ - int fault_reset_interval; /*log seconds*/ + struct fault_interval flt_interval_pertype[FT_CNT]; UInteger32 neighborPropDelayThresh; /*nanoseconds*/ }; diff --git a/fault.c b/fault.c new file mode 100644 index 0000000..6f48169 --- /dev/null +++ b/fault.c @@ -0,0 +1,30 @@ +/** + * @file fault.c + * @note Copyright (C) 2013 Delio Brignoli + * + * 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 "fault.h" + +static const char *fault_type_str[FT_CNT] = { + "FT_UNSPECIFIED", +}; + +const char *ft_str(enum fault_type ft) +{ + if (ft < 0 || ft >= FT_CNT) + return "INVALID_FAULT_TYPE_ENUM"; + return fault_type_str[ft]; +} diff --git a/fault.h b/fault.h new file mode 100644 index 0000000..d7ac2b6 --- /dev/null +++ b/fault.h @@ -0,0 +1,37 @@ +/** + * @file fault.h + * @note Copyright (C) 2013 Delio Brignoli + * + * 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 + +enum fault_type { + FT_UNSPECIFIED = 0, + FT_CNT, +}; + +enum fault_tmo_type { + FTMO_LINEAR_SECONDS = 0, + FTMO_LOG2_SECONDS, + FTMO_CNT, +}; + +struct fault_interval { + enum fault_tmo_type type; + int32_t val; +}; + +const char *ft_str(enum fault_type ft); diff --git a/makefile b/makefile index 671de48..14760bb 100644 --- a/makefile +++ b/makefile @@ -29,9 +29,9 @@ VER = -DVER=$(version) CFLAGS = -Wall $(VER) $(INC) $(DEBUG) $(FEAT_CFLAGS) $(EXTRA_CFLAGS) LDLIBS = -lm -lrt $(EXTRA_LDFLAGS) PRG = ptp4l pmc phc2sys hwstamp_ctl -OBJ = bmc.o clock.o config.o fsm.o ptp4l.o mave.o msg.o phc.o pi.o port.o \ - print.o raw.o servo.o sk.o stats.o tlv.o tmtab.o transport.o udp.o udp6.o \ - uds.o util.o version.o +OBJ = bmc.o clock.o config.o fault.o fsm.o ptp4l.o mave.o msg.o phc.o pi.o \ + port.o print.o raw.o servo.o sk.o stats.o tlv.o tmtab.o transport.o udp.o \ + udp6.o uds.o util.o version.o OBJECTS = $(OBJ) hwstamp_ctl.o phc2sys.o pmc.o pmc_common.o sysoff.o SRC = $(OBJECTS:.o=.c) diff --git a/port.c b/port.c index 5ae43f9..e47f276 100644 --- a/port.c +++ b/port.c @@ -87,6 +87,7 @@ struct port { Enumeration8 delayMechanism; Integer8 logMinPdelayReqInterval; UInteger32 neighborPropDelayThresh; + enum fault_type last_fault_type; unsigned int versionNumber; /*UInteger4*/ /* foreignMasterDS */ LIST_HEAD(fm, foreign_clock) foreign_masters; @@ -160,6 +161,23 @@ static int source_pid_eq(struct ptp_message *m1, struct ptp_message *m2) &m2->header.sourcePortIdentity); } +enum fault_type last_fault_type(struct port *port) +{ + return port->last_fault_type; +} + +int fault_interval(struct port *port, enum fault_type ft, + struct fault_interval *i) +{ + if (!port || !i) + return -EINVAL; + if (ft < 0 || ft >= FT_CNT) + return -EINVAL; + i->type = port->pod.flt_interval_pertype[ft].type; + i->val = port->pod.flt_interval_pertype[ft].val; + return 0; +} + int set_tmo_log(int fd, unsigned int scale, int log_seconds) { struct itimerspec tmo = { @@ -768,8 +786,14 @@ static int port_set_sync_tmo(struct port *p) static void port_show_transition(struct port *p, enum port_state next, enum fsm_event event) { - pr_notice("port %hu: %s to %s on %s", portnum(p), - ps_str[p->state], ps_str[next], ev_str[event]); + if (event == EV_FAULT_DETECTED) { + pr_notice("port %hu: %s to %s on %s (%s)", portnum(p), + ps_str[p->state], ps_str[next], ev_str[event], + ft_str(last_fault_type(p))); + } else { + pr_notice("port %hu: %s to %s on %s", portnum(p), + ps_str[p->state], ps_str[next], ev_str[event]); + } } static void port_slave_priority_warning(struct port *p) @@ -1120,6 +1144,7 @@ static int port_initialize(struct port *p) { int fd[N_TIMER_FDS], i; + p->last_fault_type = FT_UNSPECIFIED; p->logMinDelayReqInterval = p->pod.logMinDelayReqInterval; p->peerMeanPathDelay = 0; p->logAnnounceInterval = p->pod.logAnnounceInterval; @@ -1774,6 +1799,7 @@ static void port_p2p_transition(struct port *p, enum port_state next) int port_dispatch(struct port *p, enum fsm_event event, int mdiff) { enum port_state next; + struct fault_interval i; if (clock_slave_only(p->clock)) { if (event == EV_RS_MASTER || event == EV_RS_GRAND_MASTER) { @@ -1784,8 +1810,10 @@ int port_dispatch(struct port *p, enum fsm_event event, int mdiff) next = ptp_fsm(p->state, event, mdiff); } - if (PS_INITIALIZING == next || - (PS_FAULTY == next && FRI_ASAP == p->pod.fault_reset_interval)) { + fault_interval(p, last_fault_type(p), &i); + int fri_asap = (i.val == FRI_ASAP && i.type == FTMO_LOG2_SECONDS) || + (i.val == 0 && i.type == FTMO_LINEAR_SECONDS); + if (PS_INITIALIZING == next || (PS_FAULTY == next && fri_asap)) { /* * This is a special case. Since we initialize the * port immediately, we can skip right to listening diff --git a/port.h b/port.h index cd9649c..5fef028 100644 --- a/port.h +++ b/port.h @@ -186,4 +186,24 @@ int set_tmo_log(int fd, unsigned int scale, int log_seconds); */ int set_tmo_lin(int fd, int seconds); +/** + * Returns a port's last fault type. + * + * @param port A port instance. + * @return One of the @ref fault_type values. + */ +enum fault_type last_fault_type(struct port *port); + +/** + * Fills passed in struct fault_interval with the value associated to a + * port and fault type. + * + * @param port A port instance. + * @param ft Fault type. + * @param i Pointer to the struct which will be filled in. + * @return Zero on success, non-zero otherwise. + */ +int fault_interval(struct port *port, enum fault_type ft, + struct fault_interval *i); + #endif diff --git a/ptp4l.c b/ptp4l.c index 05a7521..e2d64bb 100644 --- a/ptp4l.c +++ b/ptp4l.c @@ -79,7 +79,6 @@ static struct config cfg_settings = { .path_trace_enabled = 0, .follow_up_info = 0, .freq_est_interval = 1, - .fault_reset_interval = 4, /* Default to very a large neighborPropDelay threshold */ .neighborPropDelayThresh = 20000000, }, @@ -174,6 +173,12 @@ int main(int argc, char *argv[]) return -1; } + /* Set fault timeouts to a default value */ + for (i = 0; i < FT_CNT; i++) { + cfg_settings.pod.flt_interval_pertype[i].type = FTMO_LOG2_SECONDS; + cfg_settings.pod.flt_interval_pertype[i].val = 4; + } + /* Process the command line arguments. */ progname = strrchr(argv[0], '/'); progname = progname ? 1+progname : argv[0];