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;
|
pod->logMinPdelayReqInterval = val;
|
||||||
|
|
||||||
} else if (!strcmp(option, "announceReceiptTimeout")) {
|
} 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)
|
if (r != PARSED_OK)
|
||||||
return r;
|
return r;
|
||||||
pod->announceReceiptTimeout = uval;
|
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")) {
|
} else if (!strcmp(option, "transportSpecific")) {
|
||||||
r = get_ranged_uint(value, &uval, 0, 0x0F);
|
r = get_ranged_uint(value, &uval, 0, 0x0F);
|
||||||
if (r != PARSED_OK)
|
if (r != PARSED_OK)
|
||||||
|
@ -295,6 +301,12 @@ static enum parser_result parse_global_setting(const char *option,
|
||||||
return r;
|
return r;
|
||||||
*cfg->tx_timestamp_timeout = val;
|
*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")) {
|
} else if (!strcmp(option, "pi_proportional_const")) {
|
||||||
r = get_ranged_double(value, &df, 0.0, DBL_MAX);
|
r = get_ranged_double(value, &df, 0.0, DBL_MAX);
|
||||||
if (r != PARSED_OK)
|
if (r != PARSED_OK)
|
||||||
|
|
1
config.h
1
config.h
|
@ -70,6 +70,7 @@ struct config {
|
||||||
struct port_defaults pod;
|
struct port_defaults pod;
|
||||||
int *assume_two_step;
|
int *assume_two_step;
|
||||||
int *tx_timestamp_timeout;
|
int *tx_timestamp_timeout;
|
||||||
|
int *check_fup_sync;
|
||||||
|
|
||||||
enum servo_type clock_servo;
|
enum servo_type clock_servo;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ logSyncInterval 0
|
||||||
logMinDelayReqInterval 0
|
logMinDelayReqInterval 0
|
||||||
logMinPdelayReqInterval 0
|
logMinPdelayReqInterval 0
|
||||||
announceReceiptTimeout 3
|
announceReceiptTimeout 3
|
||||||
|
syncReceiptTimeout 0
|
||||||
delayAsymmetry 0
|
delayAsymmetry 0
|
||||||
fault_reset_interval 4
|
fault_reset_interval 4
|
||||||
neighborPropDelayThresh 20000000
|
neighborPropDelayThresh 20000000
|
||||||
|
@ -35,6 +36,7 @@ use_syslog 1
|
||||||
verbose 0
|
verbose 0
|
||||||
summary_interval 0
|
summary_interval 0
|
||||||
kernel_leap 1
|
kernel_leap 1
|
||||||
|
check_fup_sync 0
|
||||||
#
|
#
|
||||||
# Servo Options
|
# Servo Options
|
||||||
#
|
#
|
||||||
|
|
1
ds.h
1
ds.h
|
@ -123,6 +123,7 @@ struct port_defaults {
|
||||||
Integer8 logMinDelayReqInterval;
|
Integer8 logMinDelayReqInterval;
|
||||||
Integer8 logMinPdelayReqInterval;
|
Integer8 logMinPdelayReqInterval;
|
||||||
UInteger8 announceReceiptTimeout;
|
UInteger8 announceReceiptTimeout;
|
||||||
|
UInteger8 syncReceiptTimeout;
|
||||||
UInteger8 transportSpecific;
|
UInteger8 transportSpecific;
|
||||||
int path_trace_enabled;
|
int path_trace_enabled;
|
||||||
int follow_up_info;
|
int follow_up_info;
|
||||||
|
|
5
fd.h
5
fd.h
|
@ -20,16 +20,17 @@
|
||||||
#ifndef HAVE_FD_H
|
#ifndef HAVE_FD_H
|
||||||
#define HAVE_FD_H
|
#define HAVE_FD_H
|
||||||
|
|
||||||
#define N_TIMER_FDS 5
|
#define N_TIMER_FDS 6
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FD_EVENT,
|
FD_EVENT,
|
||||||
FD_GENERAL,
|
FD_GENERAL,
|
||||||
FD_ANNOUNCE_TIMER,
|
FD_ANNOUNCE_TIMER,
|
||||||
|
FD_SYNC_RX_TIMER,
|
||||||
FD_DELAY_TIMER,
|
FD_DELAY_TIMER,
|
||||||
FD_QUALIFICATION_TIMER,
|
FD_QUALIFICATION_TIMER,
|
||||||
FD_MANNO_TIMER,
|
FD_MANNO_TIMER,
|
||||||
FD_SYNC_TIMER,
|
FD_SYNC_TX_TIMER,
|
||||||
N_POLLFD,
|
N_POLLFD,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
2
gPTP.cfg
2
gPTP.cfg
|
@ -19,6 +19,7 @@ logAnnounceInterval 1
|
||||||
logSyncInterval -3
|
logSyncInterval -3
|
||||||
logMinPdelayReqInterval 0
|
logMinPdelayReqInterval 0
|
||||||
announceReceiptTimeout 3
|
announceReceiptTimeout 3
|
||||||
|
syncReceiptTimeout 3
|
||||||
delayAsymmetry 0
|
delayAsymmetry 0
|
||||||
fault_reset_interval 4
|
fault_reset_interval 4
|
||||||
neighborPropDelayThresh 800
|
neighborPropDelayThresh 800
|
||||||
|
@ -34,6 +35,7 @@ use_syslog 1
|
||||||
verbose 0
|
verbose 0
|
||||||
summary_interval 0
|
summary_interval 0
|
||||||
kernel_leap 1
|
kernel_leap 1
|
||||||
|
check_fup_sync 0
|
||||||
#
|
#
|
||||||
# Servo options
|
# Servo options
|
||||||
#
|
#
|
||||||
|
|
54
port.c
54
port.c
|
@ -97,6 +97,7 @@ struct port {
|
||||||
TimeInterval peerMeanPathDelay;
|
TimeInterval peerMeanPathDelay;
|
||||||
Integer8 logAnnounceInterval;
|
Integer8 logAnnounceInterval;
|
||||||
UInteger8 announceReceiptTimeout;
|
UInteger8 announceReceiptTimeout;
|
||||||
|
UInteger8 syncReceiptTimeout;
|
||||||
UInteger8 transportSpecific;
|
UInteger8 transportSpecific;
|
||||||
Integer8 logSyncInterval;
|
Integer8 logSyncInterval;
|
||||||
Enumeration8 delayMechanism;
|
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)
|
static int incapable_ignore(struct port *p, struct ptp_message *m)
|
||||||
{
|
{
|
||||||
if (port_capable(p)) {
|
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);
|
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,
|
static void port_show_transition(struct port *p,
|
||||||
|
@ -832,6 +854,8 @@ static void port_synchronize(struct port *p,
|
||||||
{
|
{
|
||||||
enum servo_state state;
|
enum servo_state state;
|
||||||
|
|
||||||
|
port_set_sync_rx_tmo(p);
|
||||||
|
|
||||||
state = clock_synchronize(p->clock, ingress_ts, origin_ts,
|
state = clock_synchronize(p->clock, ingress_ts, origin_ts,
|
||||||
correction1, correction2);
|
correction1, correction2);
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
@ -1274,6 +1298,7 @@ static int port_initialize(struct port *p)
|
||||||
p->peerMeanPathDelay = 0;
|
p->peerMeanPathDelay = 0;
|
||||||
p->logAnnounceInterval = p->pod.logAnnounceInterval;
|
p->logAnnounceInterval = p->pod.logAnnounceInterval;
|
||||||
p->announceReceiptTimeout = p->pod.announceReceiptTimeout;
|
p->announceReceiptTimeout = p->pod.announceReceiptTimeout;
|
||||||
|
p->syncReceiptTimeout = p->pod.syncReceiptTimeout;
|
||||||
p->transportSpecific = p->pod.transportSpecific;
|
p->transportSpecific = p->pod.transportSpecific;
|
||||||
p->logSyncInterval = p->pod.logSyncInterval;
|
p->logSyncInterval = p->pod.logSyncInterval;
|
||||||
p->logMinPdelayReqInterval = p->pod.logMinPdelayReqInterval;
|
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 &&
|
if (p->syfu == SF_HAVE_FUP &&
|
||||||
|
fup_sync_ok(p->last_syncfup, m) &&
|
||||||
p->last_syncfup->header.sequenceId == m->header.sequenceId) {
|
p->last_syncfup->header.sequenceId == m->header.sequenceId) {
|
||||||
event = SYNC_MATCH;
|
event = SYNC_MATCH;
|
||||||
} else {
|
} 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)
|
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_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_DELAY_TIMER]);
|
||||||
port_clr_tmo(p->fda.fd[FD_QUALIFICATION_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_MANNO_TIMER]);
|
||||||
port_clr_tmo(p->fda.fd[FD_SYNC_TIMER]);
|
port_clr_tmo(p->fda.fd[FD_SYNC_TX_TIMER]);
|
||||||
|
|
||||||
switch (next) {
|
switch (next) {
|
||||||
case PS_INITIALIZING:
|
case PS_INITIALIZING:
|
||||||
|
@ -1871,8 +1898,8 @@ static void port_e2e_transition(struct port *p, enum port_state next)
|
||||||
break;
|
break;
|
||||||
case PS_MASTER:
|
case PS_MASTER:
|
||||||
case PS_GRAND_MASTER:
|
case PS_GRAND_MASTER:
|
||||||
port_set_manno_tmo(p);
|
set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/
|
||||||
port_set_sync_tmo(p);
|
port_set_sync_tx_tmo(p);
|
||||||
break;
|
break;
|
||||||
case PS_PASSIVE:
|
case PS_PASSIVE:
|
||||||
port_set_announce_tmo(p);
|
port_set_announce_tmo(p);
|
||||||
|
@ -1883,6 +1910,7 @@ static void port_e2e_transition(struct port *p, enum port_state next)
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case PS_SLAVE:
|
case PS_SLAVE:
|
||||||
port_set_announce_tmo(p);
|
port_set_announce_tmo(p);
|
||||||
|
port_set_sync_rx_tmo(p);
|
||||||
port_set_delay_tmo(p);
|
port_set_delay_tmo(p);
|
||||||
break;
|
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)
|
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_ANNOUNCE_TIMER]);
|
||||||
|
port_clr_tmo(p->fda.fd[FD_SYNC_RX_TIMER]);
|
||||||
/* Leave FD_DELAY_TIMER running. */
|
/* Leave FD_DELAY_TIMER running. */
|
||||||
port_clr_tmo(p->fda.fd[FD_QUALIFICATION_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_MANNO_TIMER]);
|
||||||
port_clr_tmo(p->fda.fd[FD_SYNC_TIMER]);
|
port_clr_tmo(p->fda.fd[FD_SYNC_TX_TIMER]);
|
||||||
|
|
||||||
switch (next) {
|
switch (next) {
|
||||||
case PS_INITIALIZING:
|
case PS_INITIALIZING:
|
||||||
|
@ -1911,8 +1940,8 @@ static void port_p2p_transition(struct port *p, enum port_state next)
|
||||||
break;
|
break;
|
||||||
case PS_MASTER:
|
case PS_MASTER:
|
||||||
case PS_GRAND_MASTER:
|
case PS_GRAND_MASTER:
|
||||||
port_set_manno_tmo(p);
|
set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/
|
||||||
port_set_sync_tmo(p);
|
port_set_sync_tx_tmo(p);
|
||||||
break;
|
break;
|
||||||
case PS_PASSIVE:
|
case PS_PASSIVE:
|
||||||
port_set_announce_tmo(p);
|
port_set_announce_tmo(p);
|
||||||
|
@ -1923,6 +1952,7 @@ static void port_p2p_transition(struct port *p, enum port_state next)
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case PS_SLAVE:
|
case PS_SLAVE:
|
||||||
port_set_announce_tmo(p);
|
port_set_announce_tmo(p);
|
||||||
|
port_set_sync_rx_tmo(p);
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1987,7 +2017,9 @@ enum fsm_event port_event(struct port *p, int fd_index)
|
||||||
|
|
||||||
switch (fd_index) {
|
switch (fd_index) {
|
||||||
case FD_ANNOUNCE_TIMER:
|
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)
|
if (p->best)
|
||||||
fc_clear(p->best);
|
fc_clear(p->best);
|
||||||
port_set_announce_tmo(p);
|
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);
|
port_set_manno_tmo(p);
|
||||||
return port_tx_announce(p) ? EV_FAULT_DETECTED : EV_NONE;
|
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));
|
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;
|
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.
|
expires.
|
||||||
The default is 3.
|
The default is 3.
|
||||||
.TP
|
.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
|
.B transportSpecific
|
||||||
The transport specific field. Must be in the range 0 to 255.
|
The transport specific field. Must be in the range 0 to 255.
|
||||||
The default is 0.
|
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.
|
when a message has recently been sent.
|
||||||
The default is 1.
|
The default is 1.
|
||||||
.TP
|
.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
|
.B clock_servo
|
||||||
The servo which is used to synchronize the local clock. Currently only one
|
The servo which is used to synchronize the local clock. Currently only one
|
||||||
servo is implemented, a PI controller.
|
servo is implemented, a PI controller.
|
||||||
|
|
2
ptp4l.c
2
ptp4l.c
|
@ -77,6 +77,7 @@ static struct config cfg_settings = {
|
||||||
.logMinDelayReqInterval = 0,
|
.logMinDelayReqInterval = 0,
|
||||||
.logMinPdelayReqInterval = 0,
|
.logMinPdelayReqInterval = 0,
|
||||||
.announceReceiptTimeout = 3,
|
.announceReceiptTimeout = 3,
|
||||||
|
.syncReceiptTimeout = 0,
|
||||||
.transportSpecific = 0,
|
.transportSpecific = 0,
|
||||||
.path_trace_enabled = 0,
|
.path_trace_enabled = 0,
|
||||||
.follow_up_info = 0,
|
.follow_up_info = 0,
|
||||||
|
@ -91,6 +92,7 @@ static struct config cfg_settings = {
|
||||||
|
|
||||||
.assume_two_step = &assume_two_step,
|
.assume_two_step = &assume_two_step,
|
||||||
.tx_timestamp_timeout = &sk_tx_timeout,
|
.tx_timestamp_timeout = &sk_tx_timeout,
|
||||||
|
.check_fup_sync = &sk_check_fupsync,
|
||||||
|
|
||||||
.clock_servo = CLOCK_SERVO_PI,
|
.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))
|
if (sk_timestamping_init(efd, name, ts_type, TRANS_IEEE_802_3))
|
||||||
goto no_timestamping;
|
goto no_timestamping;
|
||||||
|
|
||||||
|
if (sk_general_init(gfd))
|
||||||
|
goto no_timestamping;
|
||||||
|
|
||||||
fda->fd[FD_EVENT] = efd;
|
fda->fd[FD_EVENT] = efd;
|
||||||
fda->fd[FD_GENERAL] = gfd;
|
fda->fd[FD_GENERAL] = gfd;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
27
sk.c
27
sk.c
|
@ -36,6 +36,7 @@
|
||||||
/* globals */
|
/* globals */
|
||||||
|
|
||||||
int sk_tx_timeout = 1;
|
int sk_tx_timeout = 1;
|
||||||
|
int sk_check_fupsync;
|
||||||
|
|
||||||
/* private methods */
|
/* private methods */
|
||||||
|
|
||||||
|
@ -91,6 +92,16 @@ int sk_interface_index(int fd, char *name)
|
||||||
return ifreq.ifr_ifindex;
|
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)
|
int sk_get_ts_info(char *name, struct sk_ts_info *sk_info)
|
||||||
{
|
{
|
||||||
#ifdef ETHTOOL_GET_TS_INFO
|
#ifdef ETHTOOL_GET_TS_INFO
|
||||||
|
@ -205,7 +216,7 @@ int sk_receive(int fd, void *buf, int buflen,
|
||||||
struct cmsghdr *cm;
|
struct cmsghdr *cm;
|
||||||
struct iovec iov = { buf, buflen };
|
struct iovec iov = { buf, buflen };
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct timespec *ts = NULL;
|
struct timespec *sw, *ts = NULL;
|
||||||
|
|
||||||
memset(control, 0, sizeof(control));
|
memset(control, 0, sizeof(control));
|
||||||
memset(&msg, 0, sizeof(msg));
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
@ -241,7 +252,14 @@ int sk_receive(int fd, void *buf, int buflen,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ts = (struct timespec *) CMSG_DATA(cm);
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enable the sk_check_fupsync option, perhaps. */
|
||||||
|
if (sk_general_init(fd)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
14
sk.h
14
sk.h
|
@ -46,6 +46,13 @@ struct sk_ts_info {
|
||||||
*/
|
*/
|
||||||
int sk_interface_index(int fd, char *device);
|
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
|
* Obtain supported timestamping information
|
||||||
* @param name The name of the interface
|
* @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;
|
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
|
#endif
|
||||||
|
|
|
@ -57,6 +57,7 @@ enum timestamp_type {
|
||||||
struct hw_timestamp {
|
struct hw_timestamp {
|
||||||
enum timestamp_type type;
|
enum timestamp_type type;
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
struct timespec sw;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct transport;
|
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))
|
if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV4))
|
||||||
goto no_timestamping;
|
goto no_timestamping;
|
||||||
|
|
||||||
|
if (sk_general_init(gfd))
|
||||||
|
goto no_timestamping;
|
||||||
|
|
||||||
fda->fd[FD_EVENT] = efd;
|
fda->fd[FD_EVENT] = efd;
|
||||||
fda->fd[FD_GENERAL] = gfd;
|
fda->fd[FD_GENERAL] = gfd;
|
||||||
return 0;
|
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))
|
if (sk_timestamping_init(efd, name, ts_type, TRANS_UDP_IPV6))
|
||||||
goto no_timestamping;
|
goto no_timestamping;
|
||||||
|
|
||||||
|
if (sk_general_init(gfd))
|
||||||
|
goto no_timestamping;
|
||||||
|
|
||||||
fda->fd[FD_EVENT] = efd;
|
fda->fd[FD_EVENT] = efd;
|
||||||
fda->fd[FD_GENERAL] = gfd;
|
fda->fd[FD_GENERAL] = gfd;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue