Make the fault reset interval a per-port configuration parameter.

A timeout of 15 seconds is not always acceptable, make it configurable.

By popular consensus, instead of using a linear number of seconds, use
the 2^N format for the time interval, just like the other intervals in
the PTP data sets. In addition to numeric values, let the configuration
file support 'ASAP' to have the fault reset immediately.

[RC - moved the handling of special case tmo=0 and added a break out
      of the fd event loop in case the fds have been closed.
    - changed the linear seconds option to log second instead.
    - changed the commit message to reflect the final version. ]

Signed-off-by: Delio Brignoli <dbrignoli@audioscience.com>
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
master
Delio Brignoli 2013-01-30 16:28:54 +01:00 committed by Richard Cochran
parent eec07ae240
commit da594e78d9
9 changed files with 52 additions and 12 deletions

21
clock.c
View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -21,6 +21,7 @@ logMinDelayReqInterval 0
logMinPdelayReqInterval 0
announceReceiptTimeout 3
delayAsymmetry 0
fault_reset_interval 4
#
# Run time options
#

3
ds.h
View File

@ -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

View File

@ -20,6 +20,7 @@ logSyncInterval -3
logMinPdelayReqInterval 0
announceReceiptTimeout 3
delayAsymmetry 0
fault_reset_interval 4
#
# Run time options
#

5
port.c
View File

@ -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

16
port.h
View File

@ -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

View File

@ -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.

View File

@ -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,