diff --git a/clock.c b/clock.c index 5d5ccbf..5523297 100644 --- a/clock.c +++ b/clock.c @@ -37,7 +37,6 @@ #include "util.h" #define CLK_N_PORTS (MAX_PORTS + 1) /* plus one for the UDS interface */ -#define FAULT_RESET_SECONDS 15 #define N_CLOCK_PFD (N_POLLFD + 1) /* one extra per port, for the fault timer */ #define MAVE_LENGTH 10 #define POW2_41 ((double)(1ULL << 41)) @@ -65,7 +64,7 @@ struct clock { struct port *port[CLK_N_PORTS]; struct pollfd pollfd[CLK_N_PORTS*N_CLOCK_PFD]; int fault_fd[CLK_N_PORTS]; - time_t fault_timeout; + int8_t fault_timeout[CLK_N_PORTS]; int nports; /* does not include the UDS port */ int free_running; int freq_est_interval; @@ -110,17 +109,18 @@ void clock_destroy(struct clock *c) static int clock_fault_timeout(struct clock *c, int index, int set) { - struct itimerspec tmo = { - {0, 0}, {0, 0} - }; + int log_seconds = 0; + unsigned int scale = 0; + if (set) { - pr_debug("waiting %d seconds to clear fault on port %d", - c->fault_timeout, index); - tmo.it_value.tv_sec = c->fault_timeout; + 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 { pr_debug("clearing fault on port %d", index); } - return timerfd_settime(c->fault_fd[index], 0, &tmo, NULL); + return set_tmo(c->fault_fd[index], scale, log_seconds); } static void clock_freq_est_reset(struct clock *c) @@ -479,10 +479,10 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, c->pollfd[i].events = 0; } - c->fault_timeout = FAULT_RESET_SECONDS; c->fest.max_count = 2; 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); @@ -722,6 +722,7 @@ int clock_poll(struct clock *c) /* Clear any fault after a little while. */ if (PS_FAULTY == port_state(c->port[i])) { clock_fault_timeout(c, i, 1); + break; } } } diff --git a/config.c b/config.c index a4a6261..7262049 100644 --- a/config.c +++ b/config.c @@ -106,6 +106,15 @@ static enum parser_result parse_pod_setting(const char *option, return BAD_VALUE; pod->follow_up_info = val ? 1 : 0; + } else if (!strcmp(option, "fault_reset_interval")) { + if (!strcasecmp("ASAP", value)) { + pod->fault_reset_interval = FRI_ASAP; + } else if (1 == sscanf(value, "%hhd", &i8)) { + pod->fault_reset_interval = i8; + } else { + return BAD_VALUE; + } + } else return NOT_PARSED; diff --git a/default.cfg b/default.cfg index ee2700d..d551a3b 100644 --- a/default.cfg +++ b/default.cfg @@ -21,6 +21,7 @@ logMinDelayReqInterval 0 logMinPdelayReqInterval 0 announceReceiptTimeout 3 delayAsymmetry 0 +fault_reset_interval 4 # # Run time options # diff --git a/ds.h b/ds.h index 514679b..27f9ab7 100644 --- a/ds.h +++ b/ds.h @@ -101,6 +101,8 @@ struct portDS { UInteger8 versionNumber; } PACKED; +#define FRI_ASAP (-128) + struct port_defaults { Integer64 asymmetry; Integer8 logAnnounceInterval; @@ -112,6 +114,7 @@ struct port_defaults { int path_trace_enabled; int follow_up_info; int freq_est_interval; /*log seconds*/ + int fault_reset_interval; /*log seconds*/ }; #endif diff --git a/gPTP.cfg b/gPTP.cfg index f186e78..3c47e28 100644 --- a/gPTP.cfg +++ b/gPTP.cfg @@ -20,6 +20,7 @@ logSyncInterval -3 logMinPdelayReqInterval 0 announceReceiptTimeout 3 delayAsymmetry 0 +fault_reset_interval 4 # # Run time options # diff --git a/port.c b/port.c index 8b03bd9..c521c18 100644 --- a/port.c +++ b/port.c @@ -150,7 +150,7 @@ static int source_pid_eq(struct ptp_message *m1, struct ptp_message *m2) &m2->header.sourcePortIdentity); } -static int set_tmo(int fd, unsigned int scale, int log_seconds) +int set_tmo(int fd, unsigned int scale, int log_seconds) { struct itimerspec tmo = { {0, 0}, {0, 0} @@ -1419,7 +1419,8 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff) next = ptp_fsm(p->state, event, mdiff); } - if (PS_INITIALIZING == next) { + if (PS_INITIALIZING == next || + (PS_FAULTY == next && FRI_ASAP == p->pod.fault_reset_interval)) { /* * 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 2fc71e4..d98f610 100644 --- a/port.h +++ b/port.h @@ -155,4 +155,20 @@ struct port *port_open(int phc_index, */ enum port_state port_state(struct port *port); +/** + * Utility function for setting or resetting a file descriptor timer. + * + * This function sets the timer 'fd' to the value M(2^N), where M is + * the value of the 'scale' parameter and N in the value of the + * 'log_seconds' parameter. + * + * Passing both 'scale' and 'log_seconds' as zero disables the timer. + * + * @param fd A file descriptor previously opened with timerfd_create(2). + * @param scale The multiplicative factor for the timer. + * @param log_seconds The exponential factor for the timer. + * @return Zero on success, non-zero otherwise. + */ +int set_tmo(int fd, unsigned int scale, int log_seconds); + #endif diff --git a/ptp4l.8 b/ptp4l.8 index fadf854..0b9f558 100644 --- a/ptp4l.8 +++ b/ptp4l.8 @@ -181,6 +181,13 @@ The default is 0 (disabled). Include the 802.1AS data in the Follow_Up messages if enabled. The default is 0 (disabled). .TP +.B fault_reset_interval +The time in seconds between the detection of a port's fault and the fault +being reset. This value is expressed as a power of two. Setting this +value to -128 or to the special key word "ASAP" will let the fault be +reset immediately. +The default is 4 (16 seconds). +.TP .B delay_mechanism Select the delay mechanism. Possible values are E2E, P2P and Auto. The default is E2E. diff --git a/ptp4l.c b/ptp4l.c index 4fc0c88..f486516 100644 --- a/ptp4l.c +++ b/ptp4l.c @@ -64,6 +64,7 @@ static struct config cfg_settings = { .path_trace_enabled = 0, .follow_up_info = 0, .freq_est_interval = 1, + .fault_reset_interval = 4, }, .timestamping = TS_HARDWARE,