Merge the gPTP sync timeout branch.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>master
commit
bf659ae09d
14
config.c
14
config.c
|
@ -90,11 +90,17 @@ static enum parser_result parse_pod_setting(const char *option,
|
|||
pod->logMinPdelayReqInterval = val;
|
||||
|
||||
} else if (!strcmp(option, "announceReceiptTimeout")) {
|
||||
r = get_ranged_uint(value, &uval, 0, UINT8_MAX);
|
||||
r = get_ranged_uint(value, &uval, 2, UINT8_MAX);
|
||||
if (r != PARSED_OK)
|
||||
return r;
|
||||
pod->announceReceiptTimeout = uval;
|
||||
|
||||
} else if (!strcmp(option, "syncReceiptTimeout")) {
|
||||
r = get_ranged_uint(value, &uval, 0, UINT8_MAX);
|
||||
if (r != PARSED_OK)
|
||||
return r;
|
||||
pod->syncReceiptTimeout = uval;
|
||||
|
||||
} else if (!strcmp(option, "transportSpecific")) {
|
||||
r = get_ranged_uint(value, &uval, 0, 0x0F);
|
||||
if (r != PARSED_OK)
|
||||
|
@ -295,6 +301,12 @@ static enum parser_result parse_global_setting(const char *option,
|
|||
return r;
|
||||
*cfg->tx_timestamp_timeout = val;
|
||||
|
||||
} else if (!strcmp(option, "check_fup_sync")) {
|
||||
r = get_ranged_int(value, &val, 0, 1);
|
||||
if (r != PARSED_OK)
|
||||
return r;
|
||||
*cfg->check_fup_sync = val;
|
||||
|
||||
} else if (!strcmp(option, "pi_proportional_const")) {
|
||||
r = get_ranged_double(value, &df, 0.0, DBL_MAX);
|
||||
if (r != PARSED_OK)
|
||||
|
|
1
config.h
1
config.h
|
@ -70,6 +70,7 @@ struct config {
|
|||
struct port_defaults pod;
|
||||
int *assume_two_step;
|
||||
int *tx_timestamp_timeout;
|
||||
int *check_fup_sync;
|
||||
|
||||
enum servo_type clock_servo;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ logSyncInterval 0
|
|||
logMinDelayReqInterval 0
|
||||
logMinPdelayReqInterval 0
|
||||
announceReceiptTimeout 3
|
||||
syncReceiptTimeout 0
|
||||
delayAsymmetry 0
|
||||
fault_reset_interval 4
|
||||
neighborPropDelayThresh 20000000
|
||||
|
@ -35,6 +36,7 @@ use_syslog 1
|
|||
verbose 0
|
||||
summary_interval 0
|
||||
kernel_leap 1
|
||||
check_fup_sync 0
|
||||
#
|
||||
# Servo Options
|
||||
#
|
||||
|
|
1
ds.h
1
ds.h
|
@ -123,6 +123,7 @@ struct port_defaults {
|
|||
Integer8 logMinDelayReqInterval;
|
||||
Integer8 logMinPdelayReqInterval;
|
||||
UInteger8 announceReceiptTimeout;
|
||||
UInteger8 syncReceiptTimeout;
|
||||
UInteger8 transportSpecific;
|
||||
int path_trace_enabled;
|
||||
int follow_up_info;
|
||||
|
|
5
fd.h
5
fd.h
|
@ -20,16 +20,17 @@
|
|||
#ifndef HAVE_FD_H
|
||||
#define HAVE_FD_H
|
||||
|
||||
#define N_TIMER_FDS 5
|
||||
#define N_TIMER_FDS 6
|
||||
|
||||
enum {
|
||||
FD_EVENT,
|
||||
FD_GENERAL,
|
||||
FD_ANNOUNCE_TIMER,
|
||||
FD_SYNC_RX_TIMER,
|
||||
FD_DELAY_TIMER,
|
||||
FD_QUALIFICATION_TIMER,
|
||||
FD_MANNO_TIMER,
|
||||
FD_SYNC_TIMER,
|
||||
FD_SYNC_TX_TIMER,
|
||||
N_POLLFD,
|
||||
};
|
||||
|
||||
|
|
2
gPTP.cfg
2
gPTP.cfg
|
@ -19,6 +19,7 @@ logAnnounceInterval 1
|
|||
logSyncInterval -3
|
||||
logMinPdelayReqInterval 0
|
||||
announceReceiptTimeout 3
|
||||
syncReceiptTimeout 3
|
||||
delayAsymmetry 0
|
||||
fault_reset_interval 4
|
||||
neighborPropDelayThresh 800
|
||||
|
@ -34,6 +35,7 @@ use_syslog 1
|
|||
verbose 0
|
||||
summary_interval 0
|
||||
kernel_leap 1
|
||||
check_fup_sync 0
|
||||
#
|
||||
# Servo options
|
||||
#
|
||||
|
|
54
port.c
54
port.c
|
@ -97,6 +97,7 @@ struct port {
|
|||
TimeInterval peerMeanPathDelay;
|
||||
Integer8 logAnnounceInterval;
|
||||
UInteger8 announceReceiptTimeout;
|
||||
UInteger8 syncReceiptTimeout;
|
||||
UInteger8 transportSpecific;
|
||||
Integer8 logSyncInterval;
|
||||
Enumeration8 delayMechanism;
|
||||
|
@ -365,6 +366,21 @@ static void free_foreign_masters(struct port *p)
|
|||
}
|
||||
}
|
||||
|
||||
static int fup_sync_ok(struct ptp_message *fup, struct ptp_message *sync)
|
||||
{
|
||||
int64_t tfup, tsync;
|
||||
tfup = tmv_to_nanoseconds(timespec_to_tmv(fup->hwts.sw));
|
||||
tsync = tmv_to_nanoseconds(timespec_to_tmv(sync->hwts.sw));
|
||||
/*
|
||||
* NB - If the sk_check_fupsync option is not enabled, then
|
||||
* both of these time stamps will be zero.
|
||||
*/
|
||||
if (tfup < tsync) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int incapable_ignore(struct port *p, struct ptp_message *m)
|
||||
{
|
||||
if (port_capable(p)) {
|
||||
|
@ -800,9 +816,15 @@ static int port_set_qualification_tmo(struct port *p)
|
|||
1+clock_steps_removed(p->clock), p->logAnnounceInterval);
|
||||
}
|
||||
|
||||
static int port_set_sync_tmo(struct port *p)
|
||||
static int port_set_sync_rx_tmo(struct port *p)
|
||||
{
|
||||
return set_tmo_log(p->fda.fd[FD_SYNC_TIMER], 1, p->logSyncInterval);
|
||||
return set_tmo_log(p->fda.fd[FD_SYNC_RX_TIMER],
|
||||
p->syncReceiptTimeout, p->logSyncInterval);
|
||||
}
|
||||
|
||||
static int port_set_sync_tx_tmo(struct port *p)
|
||||
{
|
||||
return set_tmo_log(p->fda.fd[FD_SYNC_TX_TIMER], 1, p->logSyncInterval);
|
||||
}
|
||||
|
||||
static void port_show_transition(struct port *p,
|
||||
|
@ -832,6 +854,8 @@ static void port_synchronize(struct port *p,
|
|||
{
|
||||
enum servo_state state;
|
||||
|
||||
port_set_sync_rx_tmo(p);
|
||||
|
||||
state = clock_synchronize(p->clock, ingress_ts, origin_ts,
|
||||
correction1, correction2);
|
||||
switch (state) {
|
||||
|
@ -1274,6 +1298,7 @@ static int port_initialize(struct port *p)
|
|||
p->peerMeanPathDelay = 0;
|
||||
p->logAnnounceInterval = p->pod.logAnnounceInterval;
|
||||
p->announceReceiptTimeout = p->pod.announceReceiptTimeout;
|
||||
p->syncReceiptTimeout = p->pod.syncReceiptTimeout;
|
||||
p->transportSpecific = p->pod.transportSpecific;
|
||||
p->logSyncInterval = p->pod.logSyncInterval;
|
||||
p->logMinPdelayReqInterval = p->pod.logMinPdelayReqInterval;
|
||||
|
@ -1798,6 +1823,7 @@ static void process_sync(struct port *p, struct ptp_message *m)
|
|||
}
|
||||
|
||||
if (p->syfu == SF_HAVE_FUP &&
|
||||
fup_sync_ok(p->last_syncfup, m) &&
|
||||
p->last_syncfup->header.sequenceId == m->header.sequenceId) {
|
||||
event = SYNC_MATCH;
|
||||
} else {
|
||||
|
@ -1851,10 +1877,11 @@ struct foreign_clock *port_compute_best(struct port *p)
|
|||
static void port_e2e_transition(struct port *p, enum port_state next)
|
||||
{
|
||||
port_clr_tmo(p->fda.fd[FD_ANNOUNCE_TIMER]);
|
||||
port_clr_tmo(p->fda.fd[FD_SYNC_RX_TIMER]);
|
||||
port_clr_tmo(p->fda.fd[FD_DELAY_TIMER]);
|
||||
port_clr_tmo(p->fda.fd[FD_QUALIFICATION_TIMER]);
|
||||
port_clr_tmo(p->fda.fd[FD_MANNO_TIMER]);
|
||||
port_clr_tmo(p->fda.fd[FD_SYNC_TIMER]);
|
||||
port_clr_tmo(p->fda.fd[FD_SYNC_TX_TIMER]);
|
||||
|
||||
switch (next) {
|
||||
case PS_INITIALIZING:
|
||||
|
@ -1871,8 +1898,8 @@ static void port_e2e_transition(struct port *p, enum port_state next)
|
|||
break;
|
||||
case PS_MASTER:
|
||||
case PS_GRAND_MASTER:
|
||||
port_set_manno_tmo(p);
|
||||
port_set_sync_tmo(p);
|
||||
set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/
|
||||
port_set_sync_tx_tmo(p);
|
||||
break;
|
||||
case PS_PASSIVE:
|
||||
port_set_announce_tmo(p);
|
||||
|
@ -1883,6 +1910,7 @@ static void port_e2e_transition(struct port *p, enum port_state next)
|
|||
/* fall through */
|
||||
case PS_SLAVE:
|
||||
port_set_announce_tmo(p);
|
||||
port_set_sync_rx_tmo(p);
|
||||
port_set_delay_tmo(p);
|
||||
break;
|
||||
};
|
||||
|
@ -1891,10 +1919,11 @@ static void port_e2e_transition(struct port *p, enum port_state next)
|
|||
static void port_p2p_transition(struct port *p, enum port_state next)
|
||||
{
|
||||
port_clr_tmo(p->fda.fd[FD_ANNOUNCE_TIMER]);
|
||||
port_clr_tmo(p->fda.fd[FD_SYNC_RX_TIMER]);
|
||||
/* Leave FD_DELAY_TIMER running. */
|
||||
port_clr_tmo(p->fda.fd[FD_QUALIFICATION_TIMER]);
|
||||
port_clr_tmo(p->fda.fd[FD_MANNO_TIMER]);
|
||||
port_clr_tmo(p->fda.fd[FD_SYNC_TIMER]);
|
||||
port_clr_tmo(p->fda.fd[FD_SYNC_TX_TIMER]);
|
||||
|
||||
switch (next) {
|
||||
case PS_INITIALIZING:
|
||||
|
@ -1911,8 +1940,8 @@ static void port_p2p_transition(struct port *p, enum port_state next)
|
|||
break;
|
||||
case PS_MASTER:
|
||||
case PS_GRAND_MASTER:
|
||||
port_set_manno_tmo(p);
|
||||
port_set_sync_tmo(p);
|
||||
set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/
|
||||
port_set_sync_tx_tmo(p);
|
||||
break;
|
||||
case PS_PASSIVE:
|
||||
port_set_announce_tmo(p);
|
||||
|
@ -1923,6 +1952,7 @@ static void port_p2p_transition(struct port *p, enum port_state next)
|
|||
/* fall through */
|
||||
case PS_SLAVE:
|
||||
port_set_announce_tmo(p);
|
||||
port_set_sync_rx_tmo(p);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
@ -1987,7 +2017,9 @@ enum fsm_event port_event(struct port *p, int fd_index)
|
|||
|
||||
switch (fd_index) {
|
||||
case FD_ANNOUNCE_TIMER:
|
||||
pr_debug("port %hu: announce timeout", portnum(p));
|
||||
case FD_SYNC_RX_TIMER:
|
||||
pr_debug("port %hu: %s timeout", portnum(p),
|
||||
fd_index == FD_SYNC_RX_TIMER ? "rx sync" : "announce");
|
||||
if (p->best)
|
||||
fc_clear(p->best);
|
||||
port_set_announce_tmo(p);
|
||||
|
@ -2011,9 +2043,9 @@ enum fsm_event port_event(struct port *p, int fd_index)
|
|||
port_set_manno_tmo(p);
|
||||
return port_tx_announce(p) ? EV_FAULT_DETECTED : EV_NONE;
|
||||
|
||||
case FD_SYNC_TIMER:
|
||||
case FD_SYNC_TX_TIMER:
|
||||
pr_debug("port %hu: master sync timeout", portnum(p));
|
||||
port_set_sync_tmo(p);
|
||||
port_set_sync_tx_tmo(p);
|
||||
return port_tx_sync(p) ? EV_FAULT_DETECTED : EV_NONE;
|
||||
}
|
||||
|
||||
|
|
19
ptp4l.8
19
ptp4l.8
|
@ -148,6 +148,13 @@ The number of missed Announce messages before the last Announce messages
|
|||
expires.
|
||||
The default is 3.
|
||||
.TP
|
||||
.B syncReceiptTimeout
|
||||
The number of sync/follow up messages that may go missing before
|
||||
triggering a Best Master Clock election. This option is used for
|
||||
running in gPTP mode according to the 802.1AS-2011 standard. Setting
|
||||
this option to zero will disable the sync message timeout.
|
||||
The default is 0 or disabled.
|
||||
.TP
|
||||
.B transportSpecific
|
||||
The transport specific field. Must be in the range 0 to 255.
|
||||
The default is 0.
|
||||
|
@ -248,6 +255,18 @@ The number of milliseconds to poll waiting for the tx time stamp from the kernel
|
|||
when a message has recently been sent.
|
||||
The default is 1.
|
||||
.TP
|
||||
.B check_fup_sync
|
||||
Because of packet reordering that can occur in the network, in the
|
||||
hardware, or in the networking stack, a follow up message can appear
|
||||
to arrive in the application before the matching sync message. As this
|
||||
is a normal occurrence, and the sequenceID message field ensures
|
||||
proper matching, the ptp4l program accepts out of order packets. This
|
||||
option adds an additional check using the software time stamps from
|
||||
the networking stack to verify that the sync message did arrive
|
||||
first. This option is only useful if you do not trust the sequence IDs
|
||||
generated by the master.
|
||||
The default is 0 (disabled).
|
||||
.TP
|
||||
.B clock_servo
|
||||
The servo which is used to synchronize the local clock. Currently only one
|
||||
servo is implemented, a PI controller.
|
||||
|
|
2
ptp4l.c
2
ptp4l.c
|
@ -77,6 +77,7 @@ static struct config cfg_settings = {
|
|||
.logMinDelayReqInterval = 0,
|
||||
.logMinPdelayReqInterval = 0,
|
||||
.announceReceiptTimeout = 3,
|
||||
.syncReceiptTimeout = 0,
|
||||
.transportSpecific = 0,
|
||||
.path_trace_enabled = 0,
|
||||
.follow_up_info = 0,
|
||||
|
@ -91,6 +92,7 @@ static struct config cfg_settings = {
|
|||
|
||||
.assume_two_step = &assume_two_step,
|
||||
.tx_timestamp_timeout = &sk_tx_timeout,
|
||||
.check_fup_sync = &sk_check_fupsync,
|
||||
|
||||
.clock_servo = CLOCK_SERVO_PI,
|
||||
|
||||
|
|
3
raw.c
3
raw.c
|
@ -209,6 +209,9 @@ static int raw_open(struct transport *t, char *name,
|
|||
if (sk_timestamping_init(efd, name, ts_type, TRANS_IEEE_802_3))
|
||||
goto no_timestamping;
|
||||
|
||||
if (sk_general_init(gfd))
|
||||
goto no_timestamping;
|
||||
|
||||
fda->fd[FD_EVENT] = efd;
|
||||
fda->fd[FD_GENERAL] = gfd;
|
||||
return 0;
|
||||
|
|
27
sk.c
27
sk.c
|
@ -36,6 +36,7 @@
|
|||
/* globals */
|
||||
|
||||
int sk_tx_timeout = 1;
|
||||
int sk_check_fupsync;
|
||||
|
||||
/* private methods */
|
||||
|
||||
|
@ -91,6 +92,16 @@ int sk_interface_index(int fd, char *name)
|
|||
return ifreq.ifr_ifindex;
|
||||
}
|
||||
|
||||
int sk_general_init(int fd)
|
||||
{
|
||||
int on = sk_check_fupsync ? 1 : 0;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPNS, &on, sizeof(on)) < 0) {
|
||||
pr_err("ioctl SO_TIMESTAMPNS failed: %m");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sk_get_ts_info(char *name, struct sk_ts_info *sk_info)
|
||||
{
|
||||
#ifdef ETHTOOL_GET_TS_INFO
|
||||
|
@ -205,7 +216,7 @@ int sk_receive(int fd, void *buf, int buflen,
|
|||
struct cmsghdr *cm;
|
||||
struct iovec iov = { buf, buflen };
|
||||
struct msghdr msg;
|
||||
struct timespec *ts = NULL;
|
||||
struct timespec *sw, *ts = NULL;
|
||||
|
||||
memset(control, 0, sizeof(control));
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
@ -241,7 +252,14 @@ int sk_receive(int fd, void *buf, int buflen,
|
|||
return -1;
|
||||
}
|
||||
ts = (struct timespec *) CMSG_DATA(cm);
|
||||
break;
|
||||
}
|
||||
if (SOL_SOCKET == level && SO_TIMESTAMPNS == type) {
|
||||
if (cm->cmsg_len < sizeof(*sw)) {
|
||||
pr_warning("short SO_TIMESTAMPNS message");
|
||||
return -1;
|
||||
}
|
||||
sw = (struct timespec *) CMSG_DATA(cm);
|
||||
hwts->sw = *sw;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -325,5 +343,10 @@ int sk_timestamping_init(int fd, char *device, enum timestamp_type type,
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Enable the sk_check_fupsync option, perhaps. */
|
||||
if (sk_general_init(fd)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
14
sk.h
14
sk.h
|
@ -46,6 +46,13 @@ struct sk_ts_info {
|
|||
*/
|
||||
int sk_interface_index(int fd, char *device);
|
||||
|
||||
/**
|
||||
* Prepare a given socket for PTP "general" messages.
|
||||
* @param fd An open socket.
|
||||
* @return Zero on success, non-zero otherwise.
|
||||
*/
|
||||
int sk_general_init(int fd);
|
||||
|
||||
/**
|
||||
* Obtain supported timestamping information
|
||||
* @param name The name of the interface
|
||||
|
@ -102,4 +109,11 @@ int sk_timestamping_init(int fd, char *device, enum timestamp_type type,
|
|||
*/
|
||||
extern int sk_tx_timeout;
|
||||
|
||||
/**
|
||||
* Enables the SO_TIMESTAMPNS socket option on the both the event and
|
||||
* general sockets in order to test the order of paired sync and
|
||||
* follow up messages using their network stack receipt time stamps.
|
||||
*/
|
||||
extern int sk_check_fupsync;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -57,6 +57,7 @@ enum timestamp_type {
|
|||
struct hw_timestamp {
|
||||
enum timestamp_type type;
|
||||
struct timespec ts;
|
||||
struct timespec sw;
|
||||
};
|
||||
|
||||
struct transport;
|
||||
|
|
3
udp.c
3
udp.c
|
@ -179,6 +179,9 @@ static int udp_open(struct transport *t, char *name, struct fdarray *fda,
|
|||
if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV4))
|
||||
goto no_timestamping;
|
||||
|
||||
if (sk_general_init(gfd))
|
||||
goto no_timestamping;
|
||||
|
||||
fda->fd[FD_EVENT] = efd;
|
||||
fda->fd[FD_GENERAL] = gfd;
|
||||
return 0;
|
||||
|
|
3
udp6.c
3
udp6.c
|
@ -191,6 +191,9 @@ static int udp6_open(struct transport *t, char *name, struct fdarray *fda,
|
|||
if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV6))
|
||||
goto no_timestamping;
|
||||
|
||||
if (sk_general_init(gfd))
|
||||
goto no_timestamping;
|
||||
|
||||
fda->fd[FD_EVENT] = efd;
|
||||
fda->fd[FD_GENERAL] = gfd;
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue