Add support for multiple fault types

Signed-off-by: Delio Brignoli <dbrignoli@audioscience.com>
master
Delio Brignoli 2013-03-18 17:08:21 +01:00 committed by Richard Cochran
parent 455ebe7d22
commit b936d35b6d
9 changed files with 151 additions and 22 deletions

29
clock.c
View File

@ -72,7 +72,6 @@ struct clock {
struct port *port[CLK_N_PORTS]; struct port *port[CLK_N_PORTS];
struct pollfd pollfd[CLK_N_PORTS*N_CLOCK_PFD]; struct pollfd pollfd[CLK_N_PORTS*N_CLOCK_PFD];
int fault_fd[CLK_N_PORTS]; int fault_fd[CLK_N_PORTS];
int8_t fault_timeout[CLK_N_PORTS];
int nports; /* does not include the UDS port */ int nports; /* does not include the UDS port */
int free_running; int free_running;
int freq_est_interval; 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) static int clock_fault_timeout(struct clock *c, int index, int set)
{ {
int log_seconds = 0; struct fault_interval i;
unsigned int scale = 0;
if (set) { 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 {
pr_debug("clearing fault on port %d", index); 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) 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); clock_sync_interval(c, 0);
for (i = 0; i < count; i++) { 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); c->port[i] = port_open(phc_index, timestamping, 1+i, &iface[i], c);
if (!c->port[i]) { if (!c->port[i]) {
pr_err("failed to open port %s", iface[i].name); pr_err("failed to open port %s", iface[i].name);

View File

@ -113,10 +113,11 @@ static enum parser_result parse_pod_setting(const char *option,
pod->neighborPropDelayThresh = val; pod->neighborPropDelayThresh = val;
} else if (!strcmp(option, "fault_reset_interval")) { } else if (!strcmp(option, "fault_reset_interval")) {
pod->flt_interval_pertype[FT_UNSPECIFIED].type = FTMO_LOG2_SECONDS;
if (!strcasecmp("ASAP", value)) { 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)) { } else if (1 == sscanf(value, "%hhd", &i8)) {
pod->fault_reset_interval = i8; pod->flt_interval_pertype[FT_UNSPECIFIED].val = i8;
} else { } else {
return BAD_VALUE; return BAD_VALUE;
} }

3
ds.h
View File

@ -21,6 +21,7 @@
#define HAVE_DS_H #define HAVE_DS_H
#include "ddt.h" #include "ddt.h"
#include "fault.h"
/* clock data sets */ /* clock data sets */
@ -124,7 +125,7 @@ struct port_defaults {
int path_trace_enabled; int path_trace_enabled;
int follow_up_info; int follow_up_info;
int freq_est_interval; /*log seconds*/ int freq_est_interval; /*log seconds*/
int fault_reset_interval; /*log seconds*/ struct fault_interval flt_interval_pertype[FT_CNT];
UInteger32 neighborPropDelayThresh; /*nanoseconds*/ UInteger32 neighborPropDelayThresh; /*nanoseconds*/
}; };

30
fault.c 100644
View File

@ -0,0 +1,30 @@
/**
* @file fault.c
* @note Copyright (C) 2013 Delio Brignoli <dbrignoli@audioscience.com>
*
* 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];
}

37
fault.h 100644
View File

@ -0,0 +1,37 @@
/**
* @file fault.h
* @note Copyright (C) 2013 Delio Brignoli <dbrignoli@audioscience.com>
*
* 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 <stdint.h>
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);

View File

@ -29,9 +29,9 @@ VER = -DVER=$(version)
CFLAGS = -Wall $(VER) $(INC) $(DEBUG) $(FEAT_CFLAGS) $(EXTRA_CFLAGS) CFLAGS = -Wall $(VER) $(INC) $(DEBUG) $(FEAT_CFLAGS) $(EXTRA_CFLAGS)
LDLIBS = -lm -lrt $(EXTRA_LDFLAGS) LDLIBS = -lm -lrt $(EXTRA_LDFLAGS)
PRG = ptp4l pmc phc2sys hwstamp_ctl 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 \ OBJ = bmc.o clock.o config.o fault.o fsm.o ptp4l.o mave.o msg.o phc.o pi.o \
print.o raw.o servo.o sk.o stats.o tlv.o tmtab.o transport.o udp.o udp6.o \ port.o print.o raw.o servo.o sk.o stats.o tlv.o tmtab.o transport.o udp.o \
uds.o util.o version.o udp6.o uds.o util.o version.o
OBJECTS = $(OBJ) hwstamp_ctl.o phc2sys.o pmc.o pmc_common.o sysoff.o OBJECTS = $(OBJ) hwstamp_ctl.o phc2sys.o pmc.o pmc_common.o sysoff.o
SRC = $(OBJECTS:.o=.c) SRC = $(OBJECTS:.o=.c)

32
port.c
View File

@ -87,6 +87,7 @@ struct port {
Enumeration8 delayMechanism; Enumeration8 delayMechanism;
Integer8 logMinPdelayReqInterval; Integer8 logMinPdelayReqInterval;
UInteger32 neighborPropDelayThresh; UInteger32 neighborPropDelayThresh;
enum fault_type last_fault_type;
unsigned int versionNumber; /*UInteger4*/ unsigned int versionNumber; /*UInteger4*/
/* foreignMasterDS */ /* foreignMasterDS */
LIST_HEAD(fm, foreign_clock) foreign_masters; 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); &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) int set_tmo_log(int fd, unsigned int scale, int log_seconds)
{ {
struct itimerspec tmo = { struct itimerspec tmo = {
@ -768,8 +786,14 @@ static int port_set_sync_tmo(struct port *p)
static void port_show_transition(struct port *p, static void port_show_transition(struct port *p,
enum port_state next, enum fsm_event event) enum port_state next, enum fsm_event 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), pr_notice("port %hu: %s to %s on %s", portnum(p),
ps_str[p->state], ps_str[next], ev_str[event]); ps_str[p->state], ps_str[next], ev_str[event]);
}
} }
static void port_slave_priority_warning(struct port *p) 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; int fd[N_TIMER_FDS], i;
p->last_fault_type = FT_UNSPECIFIED;
p->logMinDelayReqInterval = p->pod.logMinDelayReqInterval; p->logMinDelayReqInterval = p->pod.logMinDelayReqInterval;
p->peerMeanPathDelay = 0; p->peerMeanPathDelay = 0;
p->logAnnounceInterval = p->pod.logAnnounceInterval; 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) int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
{ {
enum port_state next; enum port_state next;
struct fault_interval i;
if (clock_slave_only(p->clock)) { if (clock_slave_only(p->clock)) {
if (event == EV_RS_MASTER || event == EV_RS_GRAND_MASTER) { 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); next = ptp_fsm(p->state, event, mdiff);
} }
if (PS_INITIALIZING == next || fault_interval(p, last_fault_type(p), &i);
(PS_FAULTY == next && FRI_ASAP == p->pod.fault_reset_interval)) { 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 * This is a special case. Since we initialize the
* port immediately, we can skip right to listening * port immediately, we can skip right to listening

20
port.h
View File

@ -186,4 +186,24 @@ int set_tmo_log(int fd, unsigned int scale, int log_seconds);
*/ */
int set_tmo_lin(int fd, int 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 #endif

View File

@ -79,7 +79,6 @@ static struct config cfg_settings = {
.path_trace_enabled = 0, .path_trace_enabled = 0,
.follow_up_info = 0, .follow_up_info = 0,
.freq_est_interval = 1, .freq_est_interval = 1,
.fault_reset_interval = 4,
/* Default to very a large neighborPropDelay threshold */ /* Default to very a large neighborPropDelay threshold */
.neighborPropDelayThresh = 20000000, .neighborPropDelayThresh = 20000000,
}, },
@ -174,6 +173,12 @@ int main(int argc, char *argv[])
return -1; 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. */ /* Process the command line arguments. */
progname = strrchr(argv[0], '/'); progname = strrchr(argv[0], '/');
progname = progname ? 1+progname : argv[0]; progname = progname ? 1+progname : argv[0];