mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-04 10:45:07 -05:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ac791665e | ||
|
|
a4e3f83611 | ||
|
|
8a837f9c2b | ||
|
|
da2d33e9a8 | ||
|
|
4b98dadae9 | ||
|
|
86acea5c46 | ||
|
|
a60fc73e7b | ||
|
|
50f99ec5f4 | ||
|
|
31b6a14444 | ||
|
|
9df4d36157 | ||
|
|
b70f0b674f | ||
|
|
510784077f | ||
|
|
9800e397fb | ||
|
|
1436d9961f | ||
|
|
98f5d05925 | ||
|
|
7a937c7652 | ||
|
|
b198d76676 | ||
|
|
97d4203354 | ||
|
|
beaaaad162 | ||
|
|
4e78975909 | ||
|
|
99147ed8f2 | ||
|
|
dec0d3bfc2 | ||
|
|
cd84c99e70 |
13
NEWS
13
NEWS
@@ -1,3 +1,16 @@
|
|||||||
|
New in version 3.1
|
||||||
|
==================
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
------------
|
||||||
|
* Add support for precise cross timestamping of PHC on Linux
|
||||||
|
* Add minpoll, precision, nocrossts options to hwtimestamp directive
|
||||||
|
* Allow sub-second polling interval with NTP sources
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
---------
|
||||||
|
* Fix time smoothing in interleaved mode
|
||||||
|
|
||||||
New in version 3.0
|
New in version 3.0
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
|||||||
@@ -50,8 +50,11 @@ typedef struct {
|
|||||||
unsigned short port;
|
unsigned short port;
|
||||||
} NTP_Remote_Address;
|
} NTP_Remote_Address;
|
||||||
|
|
||||||
|
#define INVALID_IF_INDEX -1
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
IPAddr ip_addr;
|
IPAddr ip_addr;
|
||||||
|
int if_index;
|
||||||
int sock_fd;
|
int sock_fd;
|
||||||
} NTP_Local_Address;
|
} NTP_Local_Address;
|
||||||
|
|
||||||
|
|||||||
38
conf.c
38
conf.c
@@ -223,13 +223,7 @@ static char *leapsec_tz = NULL;
|
|||||||
/* Name of the user to which will be dropped root privileges. */
|
/* Name of the user to which will be dropped root privileges. */
|
||||||
static char *user;
|
static char *user;
|
||||||
|
|
||||||
typedef struct {
|
/* Array of CNF_HwTsInterface */
|
||||||
char *name;
|
|
||||||
double tx_comp;
|
|
||||||
double rx_comp;
|
|
||||||
} HwTs_Interface;
|
|
||||||
|
|
||||||
/* Array of HwTs_Interface */
|
|
||||||
static ARR_Instance hwts_interfaces;
|
static ARR_Instance hwts_interfaces;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -333,7 +327,7 @@ CNF_Initialise(int r)
|
|||||||
{
|
{
|
||||||
restarted = r;
|
restarted = r;
|
||||||
|
|
||||||
hwts_interfaces = ARR_CreateInstance(sizeof (HwTs_Interface));
|
hwts_interfaces = ARR_CreateInstance(sizeof (CNF_HwTsInterface));
|
||||||
|
|
||||||
init_sources = ARR_CreateInstance(sizeof (IPAddr));
|
init_sources = ARR_CreateInstance(sizeof (IPAddr));
|
||||||
ntp_sources = ARR_CreateInstance(sizeof (NTP_Source));
|
ntp_sources = ARR_CreateInstance(sizeof (NTP_Source));
|
||||||
@@ -360,7 +354,7 @@ CNF_Finalise(void)
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < ARR_GetSize(hwts_interfaces); i++)
|
for (i = 0; i < ARR_GetSize(hwts_interfaces); i++)
|
||||||
Free(((HwTs_Interface *)ARR_GetElement(hwts_interfaces, i))->name);
|
Free(((CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, i))->name);
|
||||||
ARR_DestroyInstance(hwts_interfaces);
|
ARR_DestroyInstance(hwts_interfaces);
|
||||||
|
|
||||||
for (i = 0; i < ARR_GetSize(ntp_sources); i++)
|
for (i = 0; i < ARR_GetSize(ntp_sources); i++)
|
||||||
@@ -1251,7 +1245,7 @@ parse_tempcomp(char *line)
|
|||||||
static void
|
static void
|
||||||
parse_hwtimestamp(char *line)
|
parse_hwtimestamp(char *line)
|
||||||
{
|
{
|
||||||
HwTs_Interface *iface;
|
CNF_HwTsInterface *iface;
|
||||||
char *p;
|
char *p;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
@@ -1265,18 +1259,30 @@ parse_hwtimestamp(char *line)
|
|||||||
|
|
||||||
iface = ARR_GetNewElement(hwts_interfaces);
|
iface = ARR_GetNewElement(hwts_interfaces);
|
||||||
iface->name = Strdup(p);
|
iface->name = Strdup(p);
|
||||||
|
iface->minpoll = 0;
|
||||||
|
iface->nocrossts = 0;
|
||||||
|
iface->precision = 100.0e-9;
|
||||||
iface->tx_comp = 0.0;
|
iface->tx_comp = 0.0;
|
||||||
iface->rx_comp = 0.0;
|
iface->rx_comp = 0.0;
|
||||||
|
|
||||||
for (p = line; *p; line += n, p = line) {
|
for (p = line; *p; line += n, p = line) {
|
||||||
line = CPS_SplitWord(line);
|
line = CPS_SplitWord(line);
|
||||||
|
|
||||||
if (!strcasecmp(p, "rxcomp")) {
|
if (!strcasecmp(p, "minpoll")) {
|
||||||
|
if (sscanf(line, "%d%n", &iface->minpoll, &n) != 1)
|
||||||
|
break;
|
||||||
|
} else if (!strcasecmp(p, "precision")) {
|
||||||
|
if (sscanf(line, "%lf%n", &iface->precision, &n) != 1)
|
||||||
|
break;
|
||||||
|
} else if (!strcasecmp(p, "rxcomp")) {
|
||||||
if (sscanf(line, "%lf%n", &iface->rx_comp, &n) != 1)
|
if (sscanf(line, "%lf%n", &iface->rx_comp, &n) != 1)
|
||||||
break;
|
break;
|
||||||
} else if (!strcasecmp(p, "txcomp")) {
|
} else if (!strcasecmp(p, "txcomp")) {
|
||||||
if (sscanf(line, "%lf%n", &iface->tx_comp, &n) != 1)
|
if (sscanf(line, "%lf%n", &iface->tx_comp, &n) != 1)
|
||||||
break;
|
break;
|
||||||
|
} else if (!strcasecmp(p, "nocrossts")) {
|
||||||
|
n = 0;
|
||||||
|
iface->nocrossts = 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1968,17 +1974,11 @@ CNF_GetInitStepThreshold(void)
|
|||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
int
|
int
|
||||||
CNF_GetHwTsInterface(unsigned int index, char **name, double *tx_comp, double *rx_comp)
|
CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface)
|
||||||
{
|
{
|
||||||
HwTs_Interface *iface;
|
|
||||||
|
|
||||||
if (index >= ARR_GetSize(hwts_interfaces))
|
if (index >= ARR_GetSize(hwts_interfaces))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
iface = ARR_GetElement(hwts_interfaces, index);
|
*iface = (CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, index);
|
||||||
*name = iface->name;
|
|
||||||
*tx_comp = iface->tx_comp;
|
|
||||||
*rx_comp = iface->rx_comp;
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
11
conf.h
11
conf.h
@@ -119,6 +119,15 @@ extern char *CNF_GetHwclockFile(void);
|
|||||||
extern int CNF_GetInitSources(void);
|
extern int CNF_GetInitSources(void);
|
||||||
extern double CNF_GetInitStepThreshold(void);
|
extern double CNF_GetInitStepThreshold(void);
|
||||||
|
|
||||||
extern int CNF_GetHwTsInterface(unsigned int index, char **name, double *tx_comp, double *rx_comp);
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
int minpoll;
|
||||||
|
int nocrossts;
|
||||||
|
double precision;
|
||||||
|
double tx_comp;
|
||||||
|
double rx_comp;
|
||||||
|
} CNF_HwTsInterface;
|
||||||
|
|
||||||
|
extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
|
||||||
|
|
||||||
#endif /* GOT_CONF_H */
|
#endif /* GOT_CONF_H */
|
||||||
|
|||||||
2
configure
vendored
2
configure
vendored
@@ -732,7 +732,7 @@ fi
|
|||||||
if [ $feat_refclock = "1" ] && [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
|
if [ $feat_refclock = "1" ] && [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
|
||||||
grep '#define HAVE_CLOCK_GETTIME' config.h > /dev/null && \
|
grep '#define HAVE_CLOCK_GETTIME' config.h > /dev/null && \
|
||||||
test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
|
test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
|
||||||
'ioctl(1, PTP_CLOCK_GETCAPS, 0);'
|
'ioctl(1, PTP_CLOCK_GETCAPS + PTP_SYS_OFFSET, 0);'
|
||||||
then
|
then
|
||||||
add_def FEAT_PHC
|
add_def FEAT_PHC
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -68,11 +68,15 @@ options:
|
|||||||
Although *chronyd* will trim the rate at which it samples the server during
|
Although *chronyd* will trim the rate at which it samples the server during
|
||||||
normal operation, the user might want to constrain the minimum polling interval.
|
normal operation, the user might want to constrain the minimum polling interval.
|
||||||
This is always defined as a power of 2, so *minpoll 5* would mean that the
|
This is always defined as a power of 2, so *minpoll 5* would mean that the
|
||||||
polling interval cannot drop below 32 seconds. The default is 6 (64 seconds).
|
polling interval cannot drop below 32 seconds. The default is 6 (64 seconds),
|
||||||
|
the minimum is -4 (1/16th of a second), and the maximum is 24 (6 months). Note
|
||||||
|
that intervals shorter than 6 (64 seconds) should generally not be used with
|
||||||
|
public servers on the Internet as their administrators may consider it abuse.
|
||||||
*maxpoll* _poll_:::
|
*maxpoll* _poll_:::
|
||||||
In a similar way, the user might want to constrain the maximum polling interval.
|
In a similar way, the user might want to constrain the maximum polling interval.
|
||||||
Again this is specified as a power of 2, *maxpoll 9* indicates that the polling
|
Again this is specified as a power of 2, *maxpoll 9* indicates that the polling
|
||||||
interval must stay at or below 512 seconds. The default is 10 (1024 seconds).
|
interval must stay at or below 512 seconds. The default is 10 (1024 seconds),
|
||||||
|
the minimum is 0 (1 second), and the maximum is 24 (6 months).
|
||||||
*iburst*:::
|
*iburst*:::
|
||||||
If this option is set, the interval between the first four polls will be 2
|
If this option is set, the interval between the first four polls will be 2
|
||||||
seconds instead of _minpoll_. This is useful to quickly get the first update of
|
seconds instead of _minpoll_. This is useful to quickly get the first update of
|
||||||
@@ -398,9 +402,10 @@ refclock SOCK /var/run/chrony.ttyS0.sock
|
|||||||
*PHC*:::
|
*PHC*:::
|
||||||
PTP hardware clock (PHC) driver. The parameter is the path to the device of
|
PTP hardware clock (PHC) driver. The parameter is the path to the device of
|
||||||
the PTP clock, which for example can be synchronised by *ptp4l* from
|
the PTP clock, which for example can be synchronised by *ptp4l* from
|
||||||
http://linuxptp.sourceforge.net[*linuxptp*]. PTP clocks are typically kept in
|
http://linuxptp.sourceforge.net[*linuxptp*]. String *:nocrossts* can be
|
||||||
TAI instead of UTC, so the *offset* option should be used to compensate for the
|
appended to the path to disable use of precise cross timestamping. PTP clocks
|
||||||
current UTC-TAI offset. For example:
|
are typically kept in TAI instead of UTC, so the *offset* option should be used
|
||||||
|
to compensate for the current UTC-TAI offset. For example:
|
||||||
+
|
+
|
||||||
----
|
----
|
||||||
refclock PHC /dev/ptp0 poll 3 dpoll -2 offset -36
|
refclock PHC /dev/ptp0 poll 3 dpoll -2 offset -36
|
||||||
@@ -1814,6 +1819,15 @@ on all available interfaces.
|
|||||||
+
|
+
|
||||||
The *hwtimestamp* directive has the following options:
|
The *hwtimestamp* directive has the following options:
|
||||||
+
|
+
|
||||||
|
*minpoll* _poll_:::
|
||||||
|
This option specifies the minimum interval between readings of the NIC clock.
|
||||||
|
It's defined as a power of two. It should correspond to the minimum polling
|
||||||
|
interval of all NTP sources and the minimum expected polling interval of NTP
|
||||||
|
clients. The default value is 0 (1 second) and the minimum value is -6 (1/64th
|
||||||
|
of a second).
|
||||||
|
*precision* _precision_:::
|
||||||
|
This option specifies the assumed precision of reading of the NIC clock. The
|
||||||
|
default value is 100e-9 (100 nanoseconds).
|
||||||
*txcomp* _compensation_:::
|
*txcomp* _compensation_:::
|
||||||
This option specifies the difference in seconds between the actual transmission
|
This option specifies the difference in seconds between the actual transmission
|
||||||
time at the physical layer and the reported transmit timestamp. This value will
|
time at the physical layer and the reported transmit timestamp. This value will
|
||||||
@@ -1823,6 +1837,9 @@ This option specifies the difference in seconds between the reported receive
|
|||||||
timestamp and the actual reception time at the physical layer. This value will
|
timestamp and the actual reception time at the physical layer. This value will
|
||||||
be subtracted from receive timestamps obtained from the NIC. The default value
|
be subtracted from receive timestamps obtained from the NIC. The default value
|
||||||
is 0.
|
is 0.
|
||||||
|
*nocrossts*:::
|
||||||
|
Some hardware can precisely cross timestamp the NIC clock with the system
|
||||||
|
clock. This option disables the use of the cross timestamping.
|
||||||
::
|
::
|
||||||
+
|
+
|
||||||
Examples of the directive are:
|
Examples of the directive are:
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=NTP client/server
|
Description=NTP client/server
|
||||||
|
Documentation=man:chronyd(8) man:chrony.conf(5)
|
||||||
After=ntpdate.service sntp.service ntpd.service
|
After=ntpdate.service sntp.service ntpd.service
|
||||||
Conflicts=ntpd.service systemd-timesyncd.service
|
Conflicts=ntpd.service systemd-timesyncd.service
|
||||||
|
ConditionCapability=CAP_SYS_TIME
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=forking
|
Type=forking
|
||||||
|
|||||||
13
hwclock.c
13
hwclock.c
@@ -39,9 +39,6 @@
|
|||||||
/* Maximum number of samples per clock */
|
/* Maximum number of samples per clock */
|
||||||
#define MAX_SAMPLES 16
|
#define MAX_SAMPLES 16
|
||||||
|
|
||||||
/* Minimum interval between samples (in seconds) */
|
|
||||||
#define MIN_SAMPLE_SEPARATION 1.0
|
|
||||||
|
|
||||||
struct HCL_Instance_Record {
|
struct HCL_Instance_Record {
|
||||||
/* HW and local reference timestamp */
|
/* HW and local reference timestamp */
|
||||||
struct timespec hw_ref;
|
struct timespec hw_ref;
|
||||||
@@ -58,6 +55,9 @@ struct HCL_Instance_Record {
|
|||||||
/* Maximum error of the last sample */
|
/* Maximum error of the last sample */
|
||||||
double last_err;
|
double last_err;
|
||||||
|
|
||||||
|
/* Minimum interval between samples */
|
||||||
|
double min_separation;
|
||||||
|
|
||||||
/* Flag indicating the offset and frequency values are valid */
|
/* Flag indicating the offset and frequency values are valid */
|
||||||
int valid_coefs;
|
int valid_coefs;
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
|
|||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
HCL_Instance
|
HCL_Instance
|
||||||
HCL_CreateInstance(void)
|
HCL_CreateInstance(double min_separation)
|
||||||
{
|
{
|
||||||
HCL_Instance clock;
|
HCL_Instance clock;
|
||||||
|
|
||||||
@@ -95,6 +95,7 @@ HCL_CreateInstance(void)
|
|||||||
clock->y_data[MAX_SAMPLES - 1] = 0.0;
|
clock->y_data[MAX_SAMPLES - 1] = 0.0;
|
||||||
clock->n_samples = 0;
|
clock->n_samples = 0;
|
||||||
clock->valid_coefs = 0;
|
clock->valid_coefs = 0;
|
||||||
|
clock->min_separation = min_separation;
|
||||||
|
|
||||||
LCL_AddParameterChangeHandler(handle_slew, clock);
|
LCL_AddParameterChangeHandler(handle_slew, clock);
|
||||||
|
|
||||||
@@ -115,7 +116,7 @@ int
|
|||||||
HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now)
|
HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now)
|
||||||
{
|
{
|
||||||
if (!clock->n_samples ||
|
if (!clock->n_samples ||
|
||||||
fabs(UTI_DiffTimespecsToDouble(now, &clock->local_ref)) >= MIN_SAMPLE_SEPARATION)
|
fabs(UTI_DiffTimespecsToDouble(now, &clock->local_ref)) >= clock->min_separation)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -140,7 +141,7 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
|
|||||||
hw_delta = UTI_DiffTimespecsToDouble(hw_ts, &clock->hw_ref);
|
hw_delta = UTI_DiffTimespecsToDouble(hw_ts, &clock->hw_ref);
|
||||||
local_delta = UTI_DiffTimespecsToDouble(local_ts, &clock->local_ref) / local_freq;
|
local_delta = UTI_DiffTimespecsToDouble(local_ts, &clock->local_ref) / local_freq;
|
||||||
|
|
||||||
if (hw_delta <= 0.0 || local_delta < MIN_SAMPLE_SEPARATION / 2.0) {
|
if (hw_delta <= 0.0 || local_delta < clock->min_separation / 2.0) {
|
||||||
clock->n_samples = 0;
|
clock->n_samples = 0;
|
||||||
DEBUG_LOG(LOGF_HwClocks, "HW clock reset interval=%f", local_delta);
|
DEBUG_LOG(LOGF_HwClocks, "HW clock reset interval=%f", local_delta);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
typedef struct HCL_Instance_Record *HCL_Instance;
|
typedef struct HCL_Instance_Record *HCL_Instance;
|
||||||
|
|
||||||
/* Create a new HW clock instance */
|
/* Create a new HW clock instance */
|
||||||
extern HCL_Instance HCL_CreateInstance(void);
|
extern HCL_Instance HCL_CreateInstance(double min_separation);
|
||||||
|
|
||||||
/* Destroy a HW clock instance */
|
/* Destroy a HW clock instance */
|
||||||
extern void HCL_DestroyInstance(HCL_Instance clock);
|
extern void HCL_DestroyInstance(HCL_Instance clock);
|
||||||
|
|||||||
2
main.c
2
main.c
@@ -4,7 +4,7 @@
|
|||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) John G. Hasler 2009
|
* Copyright (C) John G. Hasler 2009
|
||||||
* Copyright (C) Miroslav Lichvar 2012-2015
|
* Copyright (C) Miroslav Lichvar 2012-2016
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
|||||||
90
ntp_core.c
90
ntp_core.c
@@ -205,7 +205,8 @@ static ARR_Instance broadcasts;
|
|||||||
|
|
||||||
/* Spacing required between samples for any two servers/peers (to
|
/* Spacing required between samples for any two servers/peers (to
|
||||||
minimise risk of network collisions) (in seconds) */
|
minimise risk of network collisions) (in seconds) */
|
||||||
#define SAMPLING_SEPARATION 0.2
|
#define MIN_SAMPLING_SEPARATION 0.02
|
||||||
|
#define MAX_SAMPLING_SEPARATION 0.2
|
||||||
|
|
||||||
/* Randomness added to spacing between samples for one server/peer */
|
/* Randomness added to spacing between samples for one server/peer */
|
||||||
#define SAMPLING_RANDOMNESS 0.02
|
#define SAMPLING_RANDOMNESS 0.02
|
||||||
@@ -244,12 +245,13 @@ static ARR_Instance broadcasts;
|
|||||||
#define MAX_TX_DELAY 1.0
|
#define MAX_TX_DELAY 1.0
|
||||||
|
|
||||||
/* Maximum allowed values of maxdelay parameters */
|
/* Maximum allowed values of maxdelay parameters */
|
||||||
#define MAX_MAX_DELAY 1.0e3
|
#define MAX_MAXDELAY 1.0e3
|
||||||
#define MAX_MAX_DELAY_RATIO 1.0e6
|
#define MAX_MAXDELAYRATIO 1.0e6
|
||||||
#define MAX_MAX_DELAY_DEV_RATIO 1.0e6
|
#define MAX_MAXDELAYDEVRATIO 1.0e6
|
||||||
|
|
||||||
/* Minimum and maximum allowed poll interval */
|
/* Minimum and maximum allowed poll interval */
|
||||||
#define MIN_POLL 0
|
#define MIN_MINPOLL -4
|
||||||
|
#define MIN_MAXPOLL 0
|
||||||
#define MAX_POLL 24
|
#define MAX_POLL 24
|
||||||
|
|
||||||
/* Kiss-o'-Death codes */
|
/* Kiss-o'-Death codes */
|
||||||
@@ -278,6 +280,7 @@ static const char tss_chars[3] = {'D', 'K', 'H'};
|
|||||||
|
|
||||||
static void transmit_timeout(void *arg);
|
static void transmit_timeout(void *arg);
|
||||||
static double get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx);
|
static double get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx);
|
||||||
|
static double get_separation(int poll);
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
@@ -398,7 +401,7 @@ restart_timeout(NCR_Instance inst, double delay)
|
|||||||
SCH_RemoveTimeout(inst->tx_timeout_id);
|
SCH_RemoveTimeout(inst->tx_timeout_id);
|
||||||
|
|
||||||
/* Start new timer for transmission */
|
/* Start new timer for transmission */
|
||||||
inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, SAMPLING_SEPARATION,
|
inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, get_separation(inst->local_poll),
|
||||||
SAMPLING_RANDOMNESS,
|
SAMPLING_RANDOMNESS,
|
||||||
SCH_NtpSamplingClass,
|
SCH_NtpSamplingClass,
|
||||||
transmit_timeout, (void *)inst);
|
transmit_timeout, (void *)inst);
|
||||||
@@ -479,6 +482,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
|
|||||||
|
|
||||||
result->remote_addr = *remote_addr;
|
result->remote_addr = *remote_addr;
|
||||||
result->local_addr.ip_addr.family = IPADDR_UNSPEC;
|
result->local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||||
|
result->local_addr.if_index = INVALID_IF_INDEX;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case NTP_SERVER:
|
case NTP_SERVER:
|
||||||
@@ -497,12 +501,12 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
|
|||||||
result->interleaved = params->interleaved;
|
result->interleaved = params->interleaved;
|
||||||
|
|
||||||
result->minpoll = params->minpoll;
|
result->minpoll = params->minpoll;
|
||||||
if (result->minpoll < MIN_POLL)
|
if (result->minpoll < MIN_MINPOLL)
|
||||||
result->minpoll = SRC_DEFAULT_MINPOLL;
|
result->minpoll = SRC_DEFAULT_MINPOLL;
|
||||||
else if (result->minpoll > MAX_POLL)
|
else if (result->minpoll > MAX_POLL)
|
||||||
result->minpoll = MAX_POLL;
|
result->minpoll = MAX_POLL;
|
||||||
result->maxpoll = params->maxpoll;
|
result->maxpoll = params->maxpoll;
|
||||||
if (result->maxpoll < MIN_POLL)
|
if (result->maxpoll < MIN_MAXPOLL)
|
||||||
result->maxpoll = SRC_DEFAULT_MAXPOLL;
|
result->maxpoll = SRC_DEFAULT_MAXPOLL;
|
||||||
else if (result->maxpoll > MAX_POLL)
|
else if (result->maxpoll > MAX_POLL)
|
||||||
result->maxpoll = MAX_POLL;
|
result->maxpoll = MAX_POLL;
|
||||||
@@ -518,9 +522,9 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
|
|||||||
if (result->presend_minpoll <= MAX_POLL && result->mode != MODE_CLIENT)
|
if (result->presend_minpoll <= MAX_POLL && result->mode != MODE_CLIENT)
|
||||||
result->presend_minpoll = MAX_POLL + 1;
|
result->presend_minpoll = MAX_POLL + 1;
|
||||||
|
|
||||||
result->max_delay = CLAMP(0.0, params->max_delay, MAX_MAX_DELAY);
|
result->max_delay = CLAMP(0.0, params->max_delay, MAX_MAXDELAY);
|
||||||
result->max_delay_ratio = CLAMP(0.0, params->max_delay_ratio, MAX_MAX_DELAY_RATIO);
|
result->max_delay_ratio = CLAMP(0.0, params->max_delay_ratio, MAX_MAXDELAYRATIO);
|
||||||
result->max_delay_dev_ratio = CLAMP(0.0, params->max_delay_dev_ratio, MAX_MAX_DELAY_DEV_RATIO);
|
result->max_delay_dev_ratio = CLAMP(0.0, params->max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
|
||||||
result->offset_correction = params->offset;
|
result->offset_correction = params->offset;
|
||||||
result->auto_offline = params->auto_offline;
|
result->auto_offline = params->auto_offline;
|
||||||
result->poll_target = params->poll_target;
|
result->poll_target = params->poll_target;
|
||||||
@@ -653,6 +657,7 @@ NCR_ResetPoll(NCR_Instance instance)
|
|||||||
void
|
void
|
||||||
NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr)
|
NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr)
|
||||||
{
|
{
|
||||||
|
memset(&inst->report, 0, sizeof (inst->report));
|
||||||
NCR_ResetInstance(inst);
|
NCR_ResetInstance(inst);
|
||||||
inst->remote_addr = *remote_addr;
|
inst->remote_addr = *remote_addr;
|
||||||
|
|
||||||
@@ -661,6 +666,7 @@ NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr)
|
|||||||
else {
|
else {
|
||||||
NIO_CloseServerSocket(inst->local_addr.sock_fd);
|
NIO_CloseServerSocket(inst->local_addr.sock_fd);
|
||||||
inst->local_addr.ip_addr.family = IPADDR_UNSPEC;
|
inst->local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||||
|
inst->local_addr.if_index = INVALID_IF_INDEX;
|
||||||
inst->local_addr.sock_fd = NIO_OpenServerSocket(remote_addr);
|
inst->local_addr.sock_fd = NIO_OpenServerSocket(remote_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -764,7 +770,7 @@ get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
|
|||||||
approx the poll interval away */
|
approx the poll interval away */
|
||||||
poll_to_use = inst->local_poll;
|
poll_to_use = inst->local_poll;
|
||||||
|
|
||||||
delay_time = (double) (1UL<<poll_to_use);
|
delay_time = UTI_Log2ToDouble(poll_to_use);
|
||||||
if (inst->presend_done)
|
if (inst->presend_done)
|
||||||
delay_time = WARM_UP_DELAY;
|
delay_time = WARM_UP_DELAY;
|
||||||
|
|
||||||
@@ -782,7 +788,7 @@ get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
|
|||||||
if (poll_to_use < inst->minpoll)
|
if (poll_to_use < inst->minpoll)
|
||||||
poll_to_use = inst->minpoll;
|
poll_to_use = inst->minpoll;
|
||||||
|
|
||||||
delay_time = (double) (1UL<<poll_to_use);
|
delay_time = UTI_Log2ToDouble(poll_to_use);
|
||||||
|
|
||||||
/* If the remote stratum is higher than ours, try to lock on the
|
/* If the remote stratum is higher than ours, try to lock on the
|
||||||
peer's polling to minimize our response time by slightly extending
|
peer's polling to minimize our response time by slightly extending
|
||||||
@@ -821,6 +827,21 @@ get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
|
|||||||
return delay_time;
|
return delay_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
/* Calculate sampling separation for given polling interval */
|
||||||
|
|
||||||
|
static double
|
||||||
|
get_separation(int poll)
|
||||||
|
{
|
||||||
|
double separation;
|
||||||
|
|
||||||
|
/* Allow up to 8 sources using the same short interval to not be limited
|
||||||
|
by the separation */
|
||||||
|
separation = UTI_Log2ToDouble(poll - 3);
|
||||||
|
|
||||||
|
return CLAMP(MIN_SAMPLING_SEPARATION, separation, MAX_SAMPLING_SEPARATION);
|
||||||
|
}
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
/* Timeout handler for closing the client socket when no acceptable
|
/* Timeout handler for closing the client socket when no acceptable
|
||||||
reply can be received from the server */
|
reply can be received from the server */
|
||||||
@@ -1075,6 +1096,7 @@ transmit_timeout(void *arg)
|
|||||||
|
|
||||||
/* Don't require the packet to be sent from the same address as before */
|
/* Don't require the packet to be sent from the same address as before */
|
||||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||||
|
local_addr.if_index = INVALID_IF_INDEX;
|
||||||
local_addr.sock_fd = inst->local_addr.sock_fd;
|
local_addr.sock_fd = inst->local_addr.sock_fd;
|
||||||
|
|
||||||
/* Check whether we need to 'warm up' the link to the other end by
|
/* Check whether we need to 'warm up' the link to the other end by
|
||||||
@@ -1456,7 +1478,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
|||||||
processing time is sane, and in the interleaved symmetric mode that
|
processing time is sane, and in the interleaved symmetric mode that
|
||||||
the delay is not longer than half of the remote polling interval to
|
the delay is not longer than half of the remote polling interval to
|
||||||
detect missed packets */
|
detect missed packets */
|
||||||
testA = delay - dispersion <= inst->max_delay &&
|
testA = delay - dispersion <= inst->max_delay && precision <= inst->max_delay &&
|
||||||
!(inst->mode == MODE_CLIENT && server_interval > MAX_SERVER_INTERVAL) &&
|
!(inst->mode == MODE_CLIENT && server_interval > MAX_SERVER_INTERVAL) &&
|
||||||
!(inst->mode == MODE_ACTIVE && interleaved_packet &&
|
!(inst->mode == MODE_ACTIVE && interleaved_packet &&
|
||||||
delay > UTI_Log2ToDouble(message->poll - 1));
|
delay > UTI_Log2ToDouble(message->poll - 1));
|
||||||
@@ -1608,8 +1630,9 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
|||||||
server and the socket can be closed */
|
server and the socket can be closed */
|
||||||
close_client_socket(inst);
|
close_client_socket(inst);
|
||||||
|
|
||||||
/* Update the local address */
|
/* Update the local address and interface */
|
||||||
inst->local_addr.ip_addr = local_addr->ip_addr;
|
inst->local_addr.ip_addr = local_addr->ip_addr;
|
||||||
|
inst->local_addr.if_index = local_addr->if_index;
|
||||||
|
|
||||||
/* And now, requeue the timer */
|
/* And now, requeue the timer */
|
||||||
if (inst->opmode != MD_OFFLINE) {
|
if (inst->opmode != MD_OFFLINE) {
|
||||||
@@ -1621,7 +1644,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
|||||||
UTI_IPToString(&inst->remote_addr.ip_addr));
|
UTI_IPToString(&inst->remote_addr.ip_addr));
|
||||||
|
|
||||||
/* Back off for a while and stop ongoing burst */
|
/* Back off for a while and stop ongoing burst */
|
||||||
delay_time += 4 * (1UL << inst->minpoll);
|
delay_time += 4 * UTI_Log2ToDouble(inst->local_poll);
|
||||||
|
|
||||||
if (inst->opmode == MD_BURST_WAS_OFFLINE || inst->opmode == MD_BURST_WAS_ONLINE) {
|
if (inst->opmode == MD_BURST_WAS_OFFLINE || inst->opmode == MD_BURST_WAS_ONLINE) {
|
||||||
inst->burst_good_samples_to_go = 0;
|
inst->burst_good_samples_to_go = 0;
|
||||||
@@ -1920,10 +1943,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
|||||||
!UTI_CompareNtp64(&message->originate_ts, local_ntp_rx);
|
!UTI_CompareNtp64(&message->originate_ts, local_ntp_rx);
|
||||||
|
|
||||||
if (interleaved) {
|
if (interleaved) {
|
||||||
if (!UTI_IsZeroNtp64(local_ntp_tx))
|
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
|
||||||
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
|
|
||||||
else
|
|
||||||
interleaved = 0;
|
|
||||||
tx_ts = &local_tx;
|
tx_ts = &local_tx;
|
||||||
} else {
|
} else {
|
||||||
UTI_ZeroNtp64(local_ntp_tx);
|
UTI_ZeroNtp64(local_ntp_tx);
|
||||||
@@ -2016,10 +2036,10 @@ NCR_ProcessTxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
|||||||
if (log_index < 0)
|
if (log_index < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
|
if (SMT_IsEnabled() && NTP_LVM_TO_MODE(message->lvm) == MODE_SERVER)
|
||||||
|
UTI_AddDoubleToTimespec(&tx_ts->ts, SMT_GetOffset(&tx_ts->ts), &tx_ts->ts);
|
||||||
|
|
||||||
if (UTI_IsZeroNtp64(local_ntp_tx))
|
CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
|
||||||
return;
|
|
||||||
|
|
||||||
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
|
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
|
||||||
update_tx_timestamp(&local_tx, tx_ts, local_ntp_rx, NULL, message);
|
update_tx_timestamp(&local_tx, tx_ts, local_ntp_rx, NULL, message);
|
||||||
@@ -2091,7 +2111,7 @@ NCR_TakeSourceOffline(NCR_Instance inst)
|
|||||||
void
|
void
|
||||||
NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
|
NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
|
||||||
{
|
{
|
||||||
if (new_minpoll < MIN_POLL || new_minpoll > MAX_POLL)
|
if (new_minpoll < MIN_MINPOLL || new_minpoll > MAX_POLL)
|
||||||
return;
|
return;
|
||||||
inst->minpoll = new_minpoll;
|
inst->minpoll = new_minpoll;
|
||||||
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new minpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_minpoll);
|
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new minpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_minpoll);
|
||||||
@@ -2104,7 +2124,7 @@ NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
|
|||||||
void
|
void
|
||||||
NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll)
|
NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll)
|
||||||
{
|
{
|
||||||
if (new_maxpoll < MIN_POLL || new_maxpoll > MAX_POLL)
|
if (new_maxpoll < MIN_MAXPOLL || new_maxpoll > MAX_POLL)
|
||||||
return;
|
return;
|
||||||
inst->maxpoll = new_maxpoll;
|
inst->maxpoll = new_maxpoll;
|
||||||
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new maxpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_maxpoll);
|
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new maxpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_maxpoll);
|
||||||
@@ -2117,7 +2137,7 @@ NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll)
|
|||||||
void
|
void
|
||||||
NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay)
|
NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay)
|
||||||
{
|
{
|
||||||
inst->max_delay = CLAMP(0.0, new_max_delay, MAX_MAX_DELAY);
|
inst->max_delay = CLAMP(0.0, new_max_delay, MAX_MAXDELAY);
|
||||||
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay %f",
|
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay %f",
|
||||||
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay);
|
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay);
|
||||||
}
|
}
|
||||||
@@ -2127,7 +2147,7 @@ NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay)
|
|||||||
void
|
void
|
||||||
NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio)
|
NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio)
|
||||||
{
|
{
|
||||||
inst->max_delay_ratio = CLAMP(0.0, new_max_delay_ratio, MAX_MAX_DELAY_RATIO);
|
inst->max_delay_ratio = CLAMP(0.0, new_max_delay_ratio, MAX_MAXDELAYRATIO);
|
||||||
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay ratio %f",
|
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay ratio %f",
|
||||||
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_ratio);
|
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_ratio);
|
||||||
}
|
}
|
||||||
@@ -2137,7 +2157,7 @@ NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio)
|
|||||||
void
|
void
|
||||||
NCR_ModifyMaxdelaydevratio(NCR_Instance inst, double new_max_delay_dev_ratio)
|
NCR_ModifyMaxdelaydevratio(NCR_Instance inst, double new_max_delay_dev_ratio)
|
||||||
{
|
{
|
||||||
inst->max_delay_dev_ratio = CLAMP(0.0, new_max_delay_dev_ratio, MAX_MAX_DELAY_DEV_RATIO);
|
inst->max_delay_dev_ratio = CLAMP(0.0, new_max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
|
||||||
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay dev ratio %f",
|
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay dev ratio %f",
|
||||||
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_dev_ratio);
|
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_dev_ratio);
|
||||||
}
|
}
|
||||||
@@ -2343,20 +2363,21 @@ broadcast_timeout(void *arg)
|
|||||||
BroadcastDestination *destination;
|
BroadcastDestination *destination;
|
||||||
NTP_int64 orig_ts;
|
NTP_int64 orig_ts;
|
||||||
NTP_Local_Timestamp recv_ts;
|
NTP_Local_Timestamp recv_ts;
|
||||||
|
int poll;
|
||||||
|
|
||||||
destination = ARR_GetElement(broadcasts, (long)arg);
|
destination = ARR_GetElement(broadcasts, (long)arg);
|
||||||
|
poll = log(destination->interval) / log(2.0) + 0.5;
|
||||||
|
|
||||||
UTI_ZeroNtp64(&orig_ts);
|
UTI_ZeroNtp64(&orig_ts);
|
||||||
UTI_ZeroTimespec(&recv_ts.ts);
|
UTI_ZeroTimespec(&recv_ts.ts);
|
||||||
recv_ts.source = NTP_TS_DAEMON;
|
recv_ts.source = NTP_TS_DAEMON;
|
||||||
recv_ts.err = 0.0;
|
recv_ts.err = 0.0;
|
||||||
|
|
||||||
transmit_packet(MODE_BROADCAST, 0, log(destination->interval) / log(2.0) + 0.5,
|
transmit_packet(MODE_BROADCAST, 0, poll, NTP_VERSION, 0, 0, &orig_ts, &orig_ts, &recv_ts,
|
||||||
NTP_VERSION, 0, 0, &orig_ts, &orig_ts, &recv_ts, NULL, NULL, NULL,
|
NULL, NULL, NULL, &destination->addr, &destination->local_addr);
|
||||||
&destination->addr, &destination->local_addr);
|
|
||||||
|
|
||||||
/* Requeue timeout. We don't care if interval drifts gradually. */
|
/* Requeue timeout. We don't care if interval drifts gradually. */
|
||||||
SCH_AddTimeoutInClass(destination->interval, SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
|
SCH_AddTimeoutInClass(destination->interval, get_separation(poll), SAMPLING_RANDOMNESS,
|
||||||
SCH_NtpBroadcastClass, broadcast_timeout, arg);
|
SCH_NtpBroadcastClass, broadcast_timeout, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2372,10 +2393,11 @@ NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval)
|
|||||||
destination->addr.ip_addr = *addr;
|
destination->addr.ip_addr = *addr;
|
||||||
destination->addr.port = port;
|
destination->addr.port = port;
|
||||||
destination->local_addr.ip_addr.family = IPADDR_UNSPEC;
|
destination->local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||||
|
destination->local_addr.if_index = INVALID_IF_INDEX;
|
||||||
destination->local_addr.sock_fd = NIO_OpenServerSocket(&destination->addr);
|
destination->local_addr.sock_fd = NIO_OpenServerSocket(&destination->addr);
|
||||||
destination->interval = CLAMP(1 << MIN_POLL, interval, 1 << MAX_POLL);
|
destination->interval = CLAMP(1, interval, 1 << MAX_POLL);
|
||||||
|
|
||||||
SCH_AddTimeoutInClass(destination->interval, SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
|
SCH_AddTimeoutInClass(destination->interval, MAX_SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
|
||||||
SCH_NtpBroadcastClass, broadcast_timeout,
|
SCH_NtpBroadcastClass, broadcast_timeout,
|
||||||
(void *)(long)(ARR_GetSize(broadcasts) - 1));
|
(void *)(long)(ARR_GetSize(broadcasts) - 1));
|
||||||
}
|
}
|
||||||
|
|||||||
19
ntp_io.c
19
ntp_io.c
@@ -4,7 +4,7 @@
|
|||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) Timo Teras 2009
|
* Copyright (C) Timo Teras 2009
|
||||||
* Copyright (C) Miroslav Lichvar 2009, 2013-2015
|
* Copyright (C) Miroslav Lichvar 2009, 2013-2016
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -365,9 +365,8 @@ NIO_Initialise(int family)
|
|||||||
NIO_Linux_Initialise();
|
NIO_Linux_Initialise();
|
||||||
#else
|
#else
|
||||||
if (1) {
|
if (1) {
|
||||||
double tx_comp, rx_comp;
|
CNF_HwTsInterface *conf_iface;
|
||||||
char *name;
|
if (CNF_GetHwTsInterface(0, &conf_iface))
|
||||||
if (CNF_GetHwTsInterface(0, &name, &tx_comp, &rx_comp))
|
|
||||||
LOG_FATAL(LOGF_NtpIO, "HW timestamping not supported");
|
LOG_FATAL(LOGF_NtpIO, "HW timestamping not supported");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -579,7 +578,6 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
|||||||
NTP_Local_Timestamp local_ts;
|
NTP_Local_Timestamp local_ts;
|
||||||
struct timespec sched_ts;
|
struct timespec sched_ts;
|
||||||
struct cmsghdr *cmsg;
|
struct cmsghdr *cmsg;
|
||||||
int if_index;
|
|
||||||
|
|
||||||
SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL);
|
SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL);
|
||||||
local_ts.source = NTP_TS_DAEMON;
|
local_ts.source = NTP_TS_DAEMON;
|
||||||
@@ -599,8 +597,8 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||||
|
local_addr.if_index = INVALID_IF_INDEX;
|
||||||
local_addr.sock_fd = sock_fd;
|
local_addr.sock_fd = sock_fd;
|
||||||
if_index = -1;
|
|
||||||
|
|
||||||
if (hdr->msg_flags & MSG_TRUNC) {
|
if (hdr->msg_flags & MSG_TRUNC) {
|
||||||
DEBUG_LOG(LOGF_NtpIO, "Received truncated message from %s:%d",
|
DEBUG_LOG(LOGF_NtpIO, "Received truncated message from %s:%d",
|
||||||
@@ -621,7 +619,7 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
|||||||
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
|
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
|
||||||
local_addr.ip_addr.addr.in4 = ntohl(ipi.ipi_addr.s_addr);
|
local_addr.ip_addr.addr.in4 = ntohl(ipi.ipi_addr.s_addr);
|
||||||
local_addr.ip_addr.family = IPADDR_INET4;
|
local_addr.ip_addr.family = IPADDR_INET4;
|
||||||
if_index = ipi.ipi_ifindex;
|
local_addr.if_index = ipi.ipi_ifindex;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -633,7 +631,7 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
|||||||
memcpy(&local_addr.ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr,
|
memcpy(&local_addr.ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr,
|
||||||
sizeof (local_addr.ip_addr.addr.in6));
|
sizeof (local_addr.ip_addr.addr.in6));
|
||||||
local_addr.ip_addr.family = IPADDR_INET6;
|
local_addr.ip_addr.family = IPADDR_INET6;
|
||||||
if_index = ipi.ipi6_ifindex;
|
local_addr.if_index = ipi.ipi6_ifindex;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -661,14 +659,13 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||||
if (NIO_Linux_ProcessMessage(&remote_addr, &local_addr, &local_ts,
|
if (NIO_Linux_ProcessMessage(&remote_addr, &local_addr, &local_ts, hdr, length))
|
||||||
hdr, length, sock_fd, if_index))
|
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd=%d if=%d tss=%d delay=%.9f",
|
DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd=%d if=%d tss=%d delay=%.9f",
|
||||||
length, UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
|
length, UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
|
||||||
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd, if_index,
|
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd, local_addr.if_index,
|
||||||
local_ts.source, UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts));
|
local_ts.source, UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts));
|
||||||
|
|
||||||
/* Just ignore the packet if it's not of a recognized length */
|
/* Just ignore the packet if it's not of a recognized length */
|
||||||
|
|||||||
150
ntp_io_linux.c
150
ntp_io_linux.c
@@ -61,11 +61,15 @@ struct Interface {
|
|||||||
char name[IF_NAMESIZE];
|
char name[IF_NAMESIZE];
|
||||||
int if_index;
|
int if_index;
|
||||||
int phc_fd;
|
int phc_fd;
|
||||||
|
int phc_mode;
|
||||||
|
int phc_nocrossts;
|
||||||
/* Link speed in mbit/s */
|
/* Link speed in mbit/s */
|
||||||
int link_speed;
|
int link_speed;
|
||||||
/* Start of UDP data at layer 2 for IPv4 and IPv6 */
|
/* Start of UDP data at layer 2 for IPv4 and IPv6 */
|
||||||
int l2_udp4_ntp_start;
|
int l2_udp4_ntp_start;
|
||||||
int l2_udp6_ntp_start;
|
int l2_udp6_ntp_start;
|
||||||
|
/* Precision of PHC readings */
|
||||||
|
double precision;
|
||||||
/* Compensation of errors in TX and RX timestamping */
|
/* Compensation of errors in TX and RX timestamping */
|
||||||
double tx_comp;
|
double tx_comp;
|
||||||
double rx_comp;
|
double rx_comp;
|
||||||
@@ -75,6 +79,9 @@ struct Interface {
|
|||||||
/* Number of PHC readings per HW clock sample */
|
/* Number of PHC readings per HW clock sample */
|
||||||
#define PHC_READINGS 10
|
#define PHC_READINGS 10
|
||||||
|
|
||||||
|
/* Minimum interval between PHC readings */
|
||||||
|
#define MIN_PHC_POLL -6
|
||||||
|
|
||||||
/* Maximum acceptable offset between HW and daemon/kernel timestamp */
|
/* Maximum acceptable offset between HW and daemon/kernel timestamp */
|
||||||
#define MAX_TS_DELAY 1.0
|
#define MAX_TS_DELAY 1.0
|
||||||
|
|
||||||
@@ -91,19 +98,18 @@ static int permanent_ts_options;
|
|||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
add_interface(const char *name, double tx_comp, double rx_comp)
|
add_interface(CNF_HwTsInterface *conf_iface)
|
||||||
{
|
{
|
||||||
struct ethtool_ts_info ts_info;
|
struct ethtool_ts_info ts_info;
|
||||||
struct hwtstamp_config ts_config;
|
struct hwtstamp_config ts_config;
|
||||||
struct ifreq req;
|
struct ifreq req;
|
||||||
int sock_fd, if_index, phc_index, phc_fd;
|
int sock_fd, if_index, phc_fd;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct Interface *iface;
|
struct Interface *iface;
|
||||||
char phc_path[64];
|
|
||||||
|
|
||||||
/* Check if the interface was not already added */
|
/* Check if the interface was not already added */
|
||||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||||
if (!strcmp(name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
|
if (!strcmp(conf_iface->name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +120,8 @@ add_interface(const char *name, double tx_comp, double rx_comp)
|
|||||||
memset(&req, 0, sizeof (req));
|
memset(&req, 0, sizeof (req));
|
||||||
memset(&ts_info, 0, sizeof (ts_info));
|
memset(&ts_info, 0, sizeof (ts_info));
|
||||||
|
|
||||||
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", name) >= sizeof (req.ifr_name)) {
|
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", conf_iface->name) >=
|
||||||
|
sizeof (req.ifr_name)) {
|
||||||
close(sock_fd);
|
close(sock_fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -148,36 +155,31 @@ add_interface(const char *name, double tx_comp, double rx_comp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
close(sock_fd);
|
close(sock_fd);
|
||||||
phc_index = ts_info.phc_index;
|
|
||||||
|
|
||||||
if (snprintf(phc_path, sizeof (phc_path), "/dev/ptp%d", phc_index) >= sizeof (phc_path))
|
phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index);
|
||||||
|
if (phc_fd < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
phc_fd = open(phc_path, O_RDONLY);
|
|
||||||
if (phc_fd < 0) {
|
|
||||||
LOG(LOGS_ERR, LOGF_NtpIOLinux, "Could not open %s : %s", phc_path, strerror(errno));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
UTI_FdSetCloexec(phc_fd);
|
|
||||||
|
|
||||||
iface = ARR_GetNewElement(interfaces);
|
iface = ARR_GetNewElement(interfaces);
|
||||||
|
|
||||||
snprintf(iface->name, sizeof (iface->name), "%s", name);
|
snprintf(iface->name, sizeof (iface->name), "%s", conf_iface->name);
|
||||||
iface->if_index = if_index;
|
iface->if_index = if_index;
|
||||||
iface->phc_fd = phc_fd;
|
iface->phc_fd = phc_fd;
|
||||||
|
iface->phc_mode = 0;
|
||||||
|
iface->phc_nocrossts = conf_iface->nocrossts;
|
||||||
|
|
||||||
/* Start with 1 gbit and no VLANs or IPv4/IPv6 options */
|
/* Start with 1 gbit and no VLANs or IPv4/IPv6 options */
|
||||||
iface->link_speed = 1000;
|
iface->link_speed = 1000;
|
||||||
iface->l2_udp4_ntp_start = 42;
|
iface->l2_udp4_ntp_start = 42;
|
||||||
iface->l2_udp6_ntp_start = 62;
|
iface->l2_udp6_ntp_start = 62;
|
||||||
|
|
||||||
iface->tx_comp = tx_comp;
|
iface->precision = conf_iface->precision;
|
||||||
iface->rx_comp = rx_comp;
|
iface->tx_comp = conf_iface->tx_comp;
|
||||||
|
iface->rx_comp = conf_iface->rx_comp;
|
||||||
|
|
||||||
iface->clock = HCL_CreateInstance();
|
iface->clock = HCL_CreateInstance(UTI_Log2ToDouble(MAX(conf_iface->minpoll, MIN_PHC_POLL)));
|
||||||
|
|
||||||
DEBUG_LOG(LOGF_NtpIOLinux, "Enabled HW timestamping on %s", name);
|
DEBUG_LOG(LOGF_NtpIOLinux, "Enabled HW timestamping on %s", iface->name);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -185,18 +187,22 @@ add_interface(const char *name, double tx_comp, double rx_comp)
|
|||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
add_all_interfaces(double tx_comp, double rx_comp)
|
add_all_interfaces(CNF_HwTsInterface *conf_iface_all)
|
||||||
{
|
{
|
||||||
|
CNF_HwTsInterface conf_iface;
|
||||||
struct ifaddrs *ifaddr, *ifa;
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
conf_iface = *conf_iface_all;
|
||||||
|
|
||||||
if (getifaddrs(&ifaddr)) {
|
if (getifaddrs(&ifaddr)) {
|
||||||
DEBUG_LOG(LOGF_NtpIOLinux, "getifaddrs() failed : %s", strerror(errno));
|
DEBUG_LOG(LOGF_NtpIOLinux, "getifaddrs() failed : %s", strerror(errno));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (r = 0, ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
for (r = 0, ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||||
if (add_interface(ifa->ifa_name, tx_comp, rx_comp))
|
conf_iface.name = ifa->ifa_name;
|
||||||
|
if (add_interface(&conf_iface))
|
||||||
r = 1;
|
r = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,8 +248,7 @@ update_interface_speed(struct Interface *iface)
|
|||||||
void
|
void
|
||||||
NIO_Linux_Initialise(void)
|
NIO_Linux_Initialise(void)
|
||||||
{
|
{
|
||||||
double tx_comp, rx_comp;
|
CNF_HwTsInterface *conf_iface;
|
||||||
char *name;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int hwts;
|
int hwts;
|
||||||
|
|
||||||
@@ -252,18 +257,18 @@ NIO_Linux_Initialise(void)
|
|||||||
/* Enable HW timestamping on specified interfaces. If "*" was specified, try
|
/* Enable HW timestamping on specified interfaces. If "*" was specified, try
|
||||||
all interfaces. If no interface was specified, enable SW timestamping. */
|
all interfaces. If no interface was specified, enable SW timestamping. */
|
||||||
|
|
||||||
for (i = hwts = 0; CNF_GetHwTsInterface(i, &name, &tx_comp, &rx_comp); i++) {
|
for (i = hwts = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
|
||||||
if (!strcmp("*", name))
|
if (!strcmp("*", conf_iface->name))
|
||||||
continue;
|
continue;
|
||||||
if (!add_interface(name, tx_comp, rx_comp))
|
if (!add_interface(conf_iface))
|
||||||
LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", name);
|
LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", conf_iface->name);
|
||||||
hwts = 1;
|
hwts = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; CNF_GetHwTsInterface(i, &name, &tx_comp, &rx_comp); i++) {
|
for (i = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
|
||||||
if (strcmp("*", name))
|
if (strcmp("*", conf_iface->name))
|
||||||
continue;
|
continue;
|
||||||
if (add_all_interfaces(tx_comp, rx_comp))
|
if (add_all_interfaces(conf_iface))
|
||||||
hwts = 1;
|
hwts = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -337,68 +342,6 @@ NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
|
|||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static int
|
|
||||||
get_phc_sample(int phc_fd, struct timespec *phc_ts, struct timespec *local_ts, double *p_delay)
|
|
||||||
{
|
|
||||||
struct ptp_sys_offset sys_off;
|
|
||||||
struct timespec ts1, ts2, ts3, phc_tss[PHC_READINGS], sys_tss[PHC_READINGS];
|
|
||||||
double min_delay = 0.0, delays[PHC_READINGS], phc_sum, local_sum, local_prec;
|
|
||||||
int i, n;
|
|
||||||
|
|
||||||
/* Silence valgrind */
|
|
||||||
memset(&sys_off, 0, sizeof (sys_off));
|
|
||||||
|
|
||||||
sys_off.n_samples = PHC_READINGS;
|
|
||||||
|
|
||||||
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
|
|
||||||
DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < PHC_READINGS; i++) {
|
|
||||||
ts1.tv_sec = sys_off.ts[i * 2].sec;
|
|
||||||
ts1.tv_nsec = sys_off.ts[i * 2].nsec;
|
|
||||||
ts2.tv_sec = sys_off.ts[i * 2 + 1].sec;
|
|
||||||
ts2.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
|
|
||||||
ts3.tv_sec = sys_off.ts[i * 2 + 2].sec;
|
|
||||||
ts3.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
|
|
||||||
|
|
||||||
sys_tss[i] = ts1;
|
|
||||||
phc_tss[i] = ts2;
|
|
||||||
delays[i] = UTI_DiffTimespecsToDouble(&ts3, &ts1);
|
|
||||||
|
|
||||||
if (delays[i] <= 0.0)
|
|
||||||
/* Step in the middle of a PHC reading? */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!i || delays[i] < min_delay)
|
|
||||||
min_delay = delays[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
local_prec = LCL_GetSysPrecisionAsQuantum();
|
|
||||||
|
|
||||||
/* Combine best readings */
|
|
||||||
for (i = n = 0, phc_sum = local_sum = 0.0; i < PHC_READINGS; i++) {
|
|
||||||
if (delays[i] > min_delay + local_prec)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
phc_sum += UTI_DiffTimespecsToDouble(&phc_tss[i], &phc_tss[0]);
|
|
||||||
local_sum += UTI_DiffTimespecsToDouble(&sys_tss[i], &sys_tss[0]) + delays[i] / 2.0;
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(n);
|
|
||||||
|
|
||||||
UTI_AddDoubleToTimespec(&phc_tss[0], phc_sum / n, phc_ts);
|
|
||||||
UTI_AddDoubleToTimespec(&sys_tss[0], local_sum / n, &ts1);
|
|
||||||
LCL_CookTime(&ts1, local_ts, NULL);
|
|
||||||
*p_delay = min_delay;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================================================== */
|
|
||||||
|
|
||||||
static struct Interface *
|
static struct Interface *
|
||||||
get_interface(int if_index)
|
get_interface(int if_index)
|
||||||
{
|
{
|
||||||
@@ -422,16 +365,17 @@ static void
|
|||||||
process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
|
process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
|
||||||
NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family)
|
NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family)
|
||||||
{
|
{
|
||||||
struct timespec sample_phc_ts, sample_local_ts, ts;
|
struct timespec sample_phc_ts, sample_sys_ts, sample_local_ts, ts;
|
||||||
double sample_delay, rx_correction, ts_delay, err;
|
double rx_correction, ts_delay, err;
|
||||||
int l2_length;
|
int l2_length;
|
||||||
|
|
||||||
if (HCL_NeedsNewSample(iface->clock, &local_ts->ts)) {
|
if (HCL_NeedsNewSample(iface->clock, &local_ts->ts)) {
|
||||||
if (!get_phc_sample(iface->phc_fd, &sample_phc_ts, &sample_local_ts, &sample_delay))
|
if (!SYS_Linux_GetPHCSample(iface->phc_fd, iface->phc_nocrossts, iface->precision,
|
||||||
|
&iface->phc_mode, &sample_phc_ts, &sample_sys_ts, &err))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts,
|
LCL_CookTime(&sample_sys_ts, &sample_local_ts, NULL);
|
||||||
sample_delay / 2.0);
|
HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts, err);
|
||||||
|
|
||||||
update_interface_speed(iface);
|
update_interface_speed(iface);
|
||||||
}
|
}
|
||||||
@@ -536,8 +480,7 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
|||||||
|
|
||||||
int
|
int
|
||||||
NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr,
|
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length)
|
||||||
int length, int sock_fd, int if_index)
|
|
||||||
{
|
{
|
||||||
struct Interface *iface;
|
struct Interface *iface;
|
||||||
struct cmsghdr *cmsg;
|
struct cmsghdr *cmsg;
|
||||||
@@ -556,12 +499,13 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
|
|||||||
LCL_CookTime(&ts3.ts[0], &local_ts->ts, &local_ts->err);
|
LCL_CookTime(&ts3.ts[0], &local_ts->ts, &local_ts->err);
|
||||||
local_ts->source = NTP_TS_KERNEL;
|
local_ts->source = NTP_TS_KERNEL;
|
||||||
} else if (!UTI_IsZeroTimespec(&ts3.ts[2])) {
|
} else if (!UTI_IsZeroTimespec(&ts3.ts[2])) {
|
||||||
iface = get_interface(if_index);
|
iface = get_interface(local_addr->if_index);
|
||||||
if (iface) {
|
if (iface) {
|
||||||
process_hw_timestamp(iface, &ts3.ts[2], local_ts, !is_tx ? length : 0,
|
process_hw_timestamp(iface, &ts3.ts[2], local_ts, !is_tx ? length : 0,
|
||||||
remote_addr->ip_addr.family);
|
remote_addr->ip_addr.family);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_LOG(LOGF_NtpIOLinux, "HW clock not found for interface %d", if_index);
|
DEBUG_LOG(LOGF_NtpIOLinux, "HW clock not found for interface %d",
|
||||||
|
local_addr->if_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -593,7 +537,7 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
|
|||||||
|
|
||||||
DEBUG_LOG(LOGF_NtpIOLinux, "Received %d (%d) bytes from error queue for %s:%d fd=%d if=%d tss=%d",
|
DEBUG_LOG(LOGF_NtpIOLinux, "Received %d (%d) bytes from error queue for %s:%d fd=%d if=%d tss=%d",
|
||||||
l2_length, length, UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
|
l2_length, length, UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
|
||||||
sock_fd, if_index, local_ts->source);
|
local_addr->sock_fd, local_addr->if_index, local_ts->source);
|
||||||
|
|
||||||
/* Update assumed position of UDP data at layer 2 for next received packet */
|
/* Update assumed position of UDP data at layer 2 for next received packet */
|
||||||
if (iface && length) {
|
if (iface && length) {
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ extern void NIO_Linux_Finalise(void);
|
|||||||
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
|
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
|
||||||
|
|
||||||
extern int NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
extern int NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length,
|
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length);
|
||||||
int sock_fd, int if_index);
|
|
||||||
|
|
||||||
extern int NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd);
|
extern int NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014
|
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -505,6 +505,12 @@ RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
RCL_GetPrecision(RCL_Instance instance)
|
||||||
|
{
|
||||||
|
return instance->precision;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
valid_sample_time(RCL_Instance instance, struct timespec *raw, struct timespec *cooked)
|
valid_sample_time(RCL_Instance instance, struct timespec *raw, struct timespec *cooked)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -71,5 +71,6 @@ extern char *RCL_GetDriverParameter(RCL_Instance instance);
|
|||||||
extern char *RCL_GetDriverOption(RCL_Instance instance, char *name);
|
extern char *RCL_GetDriverOption(RCL_Instance instance, char *name);
|
||||||
extern int RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap);
|
extern int RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap);
|
||||||
extern int RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second);
|
extern int RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second);
|
||||||
|
extern double RCL_GetPrecision(RCL_Instance instance);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
137
refclock_phc.c
137
refclock_phc.c
@@ -2,7 +2,7 @@
|
|||||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Miroslav Lichvar 2013
|
* Copyright (C) Miroslav Lichvar 2013, 2017
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -33,144 +33,67 @@
|
|||||||
|
|
||||||
#include "sysincl.h"
|
#include "sysincl.h"
|
||||||
|
|
||||||
#include <linux/ptp_clock.h>
|
|
||||||
|
|
||||||
#include "refclock.h"
|
#include "refclock.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
#include "memory.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "sys_linux.h"
|
||||||
|
|
||||||
/* From linux/include/linux/posix-timers.h */
|
struct phc_instance {
|
||||||
#define CPUCLOCK_MAX 3
|
int fd;
|
||||||
#define CLOCKFD CPUCLOCK_MAX
|
int mode;
|
||||||
#define CLOCKFD_MASK (CPUCLOCK_PERTHREAD_MASK|CPUCLOCK_CLOCK_MASK)
|
int nocrossts;
|
||||||
|
|
||||||
#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
|
|
||||||
|
|
||||||
#define NUM_READINGS 10
|
|
||||||
|
|
||||||
static int no_sys_offset_ioctl = 0;
|
|
||||||
|
|
||||||
struct phc_reading {
|
|
||||||
struct timespec sys_ts1;
|
|
||||||
struct timespec phc_ts;;
|
|
||||||
struct timespec sys_ts2;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int read_phc_ioctl(struct phc_reading *readings, int phc_fd, int n)
|
|
||||||
{
|
|
||||||
#if defined(PTP_SYS_OFFSET) && NUM_READINGS <= PTP_MAX_SAMPLES
|
|
||||||
struct ptp_sys_offset sys_off;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Silence valgrind */
|
|
||||||
memset(&sys_off, 0, sizeof (sys_off));
|
|
||||||
|
|
||||||
sys_off.n_samples = n;
|
|
||||||
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
|
|
||||||
LOG(LOGS_ERR, LOGF_Refclock, "ioctl(PTP_SYS_OFFSET) failed : %s", strerror(errno));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
readings[i].sys_ts1.tv_sec = sys_off.ts[i * 2].sec;
|
|
||||||
readings[i].sys_ts1.tv_nsec = sys_off.ts[i * 2].nsec;
|
|
||||||
readings[i].phc_ts.tv_sec = sys_off.ts[i * 2 + 1].sec;
|
|
||||||
readings[i].phc_ts.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
|
|
||||||
readings[i].sys_ts2.tv_sec = sys_off.ts[i * 2 + 2].sec;
|
|
||||||
readings[i].sys_ts2.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
#else
|
|
||||||
/* Not available */
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_phc_user(struct phc_reading *readings, int phc_fd, int n)
|
|
||||||
{
|
|
||||||
clockid_t phc_id;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
phc_id = FD_TO_CLOCKID(phc_fd);
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
if (clock_gettime(CLOCK_REALTIME, &readings[i].sys_ts1) ||
|
|
||||||
clock_gettime(phc_id, &readings[i].phc_ts) ||
|
|
||||||
clock_gettime(CLOCK_REALTIME, &readings[i].sys_ts2)) {
|
|
||||||
LOG(LOGS_ERR, LOGF_Refclock, "clock_gettime() failed : %s", strerror(errno));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int phc_initialise(RCL_Instance instance)
|
static int phc_initialise(RCL_Instance instance)
|
||||||
{
|
{
|
||||||
struct ptp_clock_caps caps;
|
struct phc_instance *phc;
|
||||||
int phc_fd;
|
int phc_fd;
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
path = RCL_GetDriverParameter(instance);
|
path = RCL_GetDriverParameter(instance);
|
||||||
|
|
||||||
phc_fd = open(path, O_RDONLY);
|
phc_fd = SYS_Linux_OpenPHC(path, 0);
|
||||||
if (phc_fd < 0) {
|
if (phc_fd < 0) {
|
||||||
LOG_FATAL(LOGF_Refclock, "open() failed on %s", path);
|
LOG_FATAL(LOGF_Refclock, "Could not open PHC");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure it is a PHC */
|
phc = MallocNew(struct phc_instance);
|
||||||
if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) {
|
phc->fd = phc_fd;
|
||||||
LOG_FATAL(LOGF_Refclock, "ioctl(PTP_CLOCK_GETCAPS) failed : %s", strerror(errno));
|
phc->mode = 0;
|
||||||
return 0;
|
phc->nocrossts = RCL_GetDriverOption(instance, "nocrossts") ? 1 : 0;
|
||||||
}
|
|
||||||
|
|
||||||
UTI_FdSetCloexec(phc_fd);
|
RCL_SetDriverData(instance, phc);
|
||||||
|
|
||||||
RCL_SetDriverData(instance, (void *)(long)phc_fd);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void phc_finalise(RCL_Instance instance)
|
static void phc_finalise(RCL_Instance instance)
|
||||||
{
|
{
|
||||||
close((long)RCL_GetDriverData(instance));
|
struct phc_instance *phc;
|
||||||
|
|
||||||
|
phc = (struct phc_instance *)RCL_GetDriverData(instance);
|
||||||
|
close(phc->fd);
|
||||||
|
Free(phc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int phc_poll(RCL_Instance instance)
|
static int phc_poll(RCL_Instance instance)
|
||||||
{
|
{
|
||||||
struct phc_reading readings[NUM_READINGS];
|
struct phc_instance *phc;
|
||||||
double offset = 0.0, delay, best_delay = 0.0;
|
struct timespec phc_ts, sys_ts;
|
||||||
int i, phc_fd, best;
|
double offset, err;
|
||||||
|
|
||||||
phc_fd = (long)RCL_GetDriverData(instance);
|
phc = (struct phc_instance *)RCL_GetDriverData(instance);
|
||||||
|
|
||||||
if (!no_sys_offset_ioctl) {
|
if (!SYS_Linux_GetPHCSample(phc->fd, phc->nocrossts, RCL_GetPrecision(instance),
|
||||||
if (!read_phc_ioctl(readings, phc_fd, NUM_READINGS)) {
|
&phc->mode, &phc_ts, &sys_ts, &err))
|
||||||
no_sys_offset_ioctl = 1;
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!read_phc_user(readings, phc_fd, NUM_READINGS))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the fastest reading */
|
offset = UTI_DiffTimespecsToDouble(&phc_ts, &sys_ts);
|
||||||
for (i = 0; i < NUM_READINGS; i++) {
|
|
||||||
delay = UTI_DiffTimespecsToDouble(&readings[i].sys_ts2, &readings[i].sys_ts1);
|
|
||||||
|
|
||||||
if (!i || best_delay > delay) {
|
DEBUG_LOG(LOGF_Refclock, "PHC offset: %+.9f err: %.9f", offset, err);
|
||||||
best = i;
|
|
||||||
best_delay = delay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = UTI_DiffTimespecsToDouble(&readings[best].phc_ts, &readings[best].sys_ts2) +
|
return RCL_AddSample(instance, &sys_ts, offset, LEAP_Normal);
|
||||||
best_delay / 2.0;
|
|
||||||
|
|
||||||
DEBUG_LOG(LOGF_Refclock, "PHC offset: %+.9f delay: %.9f", offset, best_delay);
|
|
||||||
|
|
||||||
return RCL_AddSample(instance, &readings[best].sys_ts2, offset, LEAP_Normal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RefclockDriver RCL_PHC_driver = {
|
RefclockDriver RCL_PHC_driver = {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) Miroslav Lichvar 2011
|
* Copyright (C) Miroslav Lichvar 2011, 2016
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
|||||||
2
sched.c
2
sched.c
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) Miroslav Lichvar 2011, 2013-2015
|
* Copyright (C) Miroslav Lichvar 2011, 2013-2016
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) Miroslav Lichvar 2011-2014
|
* Copyright (C) Miroslav Lichvar 2011-2014, 2016
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
|||||||
2
stubs.c
2
stubs.c
@@ -2,7 +2,7 @@
|
|||||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||||
|
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Miroslav Lichvar 2014-2015
|
* Copyright (C) Miroslav Lichvar 2014-2016
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
|||||||
161
sys_linux.c
161
sys_linux.c
@@ -4,7 +4,7 @@
|
|||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) Richard P. Curnow 1997-2003
|
* Copyright (C) Richard P. Curnow 1997-2003
|
||||||
* Copyright (C) John G. Hasler 2009
|
* Copyright (C) John G. Hasler 2009
|
||||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2015
|
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2016
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of version 2 of the GNU General Public License as
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
@@ -47,13 +47,14 @@
|
|||||||
#include <sys/capability.h>
|
#include <sys/capability.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||||
|
#include <linux/ptp_clock.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef FEAT_SCFILTER
|
#ifdef FEAT_SCFILTER
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <seccomp.h>
|
#include <seccomp.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
|
||||||
#include <linux/ptp_clock.h>
|
|
||||||
#endif
|
|
||||||
#ifdef FEAT_PPS
|
#ifdef FEAT_PPS
|
||||||
#include <linux/pps.h>
|
#include <linux/pps.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -68,6 +69,7 @@
|
|||||||
#include "sys_linux.h"
|
#include "sys_linux.h"
|
||||||
#include "sys_timex.h"
|
#include "sys_timex.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include "local.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "privops.h"
|
#include "privops.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@@ -515,6 +517,9 @@ SYS_Linux_EnableSystemCallFilter(int level)
|
|||||||
FIONREAD, TCGETS,
|
FIONREAD, TCGETS,
|
||||||
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||||
PTP_SYS_OFFSET,
|
PTP_SYS_OFFSET,
|
||||||
|
#ifdef PTP_SYS_OFFSET_PRECISE
|
||||||
|
PTP_SYS_OFFSET_PRECISE,
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef FEAT_PPS
|
#ifdef FEAT_PPS
|
||||||
PPS_FETCH,
|
PPS_FETCH,
|
||||||
@@ -661,3 +666,151 @@ SYS_Linux_CheckKernelVersion(int req_major, int req_minor)
|
|||||||
|
|
||||||
return kernelvercmp(req_major, req_minor, 0, major, minor, patch) <= 0;
|
return kernelvercmp(req_major, req_minor, 0, major, minor, patch) <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||||
|
|
||||||
|
#define PHC_READINGS 10
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
|
||||||
|
struct timespec *sys_ts, double *err)
|
||||||
|
{
|
||||||
|
struct ptp_sys_offset sys_off;
|
||||||
|
struct timespec ts1, ts2, ts3, phc_tss[PHC_READINGS], sys_tss[PHC_READINGS];
|
||||||
|
double min_delay = 0.0, delays[PHC_READINGS], phc_sum, sys_sum, sys_prec;
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
/* Silence valgrind */
|
||||||
|
memset(&sys_off, 0, sizeof (sys_off));
|
||||||
|
|
||||||
|
sys_off.n_samples = PHC_READINGS;
|
||||||
|
|
||||||
|
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
|
||||||
|
DEBUG_LOG(LOGF_SysLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < PHC_READINGS; i++) {
|
||||||
|
ts1.tv_sec = sys_off.ts[i * 2].sec;
|
||||||
|
ts1.tv_nsec = sys_off.ts[i * 2].nsec;
|
||||||
|
ts2.tv_sec = sys_off.ts[i * 2 + 1].sec;
|
||||||
|
ts2.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
|
||||||
|
ts3.tv_sec = sys_off.ts[i * 2 + 2].sec;
|
||||||
|
ts3.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
|
||||||
|
|
||||||
|
sys_tss[i] = ts1;
|
||||||
|
phc_tss[i] = ts2;
|
||||||
|
delays[i] = UTI_DiffTimespecsToDouble(&ts3, &ts1);
|
||||||
|
|
||||||
|
if (delays[i] <= 0.0)
|
||||||
|
/* Step in the middle of a PHC reading? */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!i || delays[i] < min_delay)
|
||||||
|
min_delay = delays[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_prec = LCL_GetSysPrecisionAsQuantum();
|
||||||
|
|
||||||
|
/* Combine best readings */
|
||||||
|
for (i = n = 0, phc_sum = sys_sum = 0.0; i < PHC_READINGS; i++) {
|
||||||
|
if (delays[i] > min_delay + MAX(sys_prec, precision))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
phc_sum += UTI_DiffTimespecsToDouble(&phc_tss[i], &phc_tss[0]);
|
||||||
|
sys_sum += UTI_DiffTimespecsToDouble(&sys_tss[i], &sys_tss[0]) + delays[i] / 2.0;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(n);
|
||||||
|
|
||||||
|
UTI_AddDoubleToTimespec(&phc_tss[0], phc_sum / n, phc_ts);
|
||||||
|
UTI_AddDoubleToTimespec(&sys_tss[0], sys_sum / n, sys_ts);
|
||||||
|
*err = MAX(min_delay / 2.0, precision);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_precise_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
|
||||||
|
struct timespec *sys_ts, double *err)
|
||||||
|
{
|
||||||
|
#ifdef PTP_SYS_OFFSET_PRECISE
|
||||||
|
struct ptp_sys_offset_precise sys_off;
|
||||||
|
|
||||||
|
/* Silence valgrind */
|
||||||
|
memset(&sys_off, 0, sizeof (sys_off));
|
||||||
|
|
||||||
|
if (ioctl(phc_fd, PTP_SYS_OFFSET_PRECISE, &sys_off)) {
|
||||||
|
DEBUG_LOG(LOGF_SysLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET_PRECISE",
|
||||||
|
strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
phc_ts->tv_sec = sys_off.device.sec;
|
||||||
|
phc_ts->tv_nsec = sys_off.device.nsec;
|
||||||
|
sys_ts->tv_sec = sys_off.sys_realtime.sec;
|
||||||
|
sys_ts->tv_nsec = sys_off.sys_realtime.nsec;
|
||||||
|
*err = MAX(LCL_GetSysPrecisionAsQuantum(), precision);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
SYS_Linux_OpenPHC(const char *path, int phc_index)
|
||||||
|
{
|
||||||
|
struct ptp_clock_caps caps;
|
||||||
|
char phc_path[64];
|
||||||
|
int phc_fd;
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
if (snprintf(phc_path, sizeof (phc_path), "/dev/ptp%d", phc_index) >= sizeof (phc_path))
|
||||||
|
return -1;
|
||||||
|
path = phc_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
phc_fd = open(path, O_RDONLY);
|
||||||
|
if (phc_fd < 0) {
|
||||||
|
LOG(LOGS_ERR, LOGF_SysLinux, "Could not open %s : %s", path, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure it is a PHC */
|
||||||
|
if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) {
|
||||||
|
LOG(LOGS_ERR, LOGF_SysLinux, "ioctl(%s) failed : %s", "PTP_CLOCK_GETCAPS", strerror(errno));
|
||||||
|
close(phc_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
UTI_FdSetCloexec(phc_fd);
|
||||||
|
|
||||||
|
return phc_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
SYS_Linux_GetPHCSample(int fd, int nocrossts, double precision, int *reading_mode,
|
||||||
|
struct timespec *phc_ts, struct timespec *sys_ts, double *err)
|
||||||
|
{
|
||||||
|
if ((*reading_mode == 2 || !*reading_mode) && !nocrossts &&
|
||||||
|
get_precise_phc_sample(fd, precision, phc_ts, sys_ts, err)) {
|
||||||
|
*reading_mode = 2;
|
||||||
|
return 1;
|
||||||
|
} else if ((*reading_mode == 1 || !*reading_mode) &&
|
||||||
|
get_phc_sample(fd, precision, phc_ts, sys_ts, err)) {
|
||||||
|
*reading_mode = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -41,4 +41,9 @@ extern void SYS_Linux_SetScheduler(int SchedPriority);
|
|||||||
|
|
||||||
extern int SYS_Linux_CheckKernelVersion(int req_major, int req_minor);
|
extern int SYS_Linux_CheckKernelVersion(int req_major, int req_minor);
|
||||||
|
|
||||||
|
extern int SYS_Linux_OpenPHC(const char *path, int phc_index);
|
||||||
|
|
||||||
|
extern int SYS_Linux_GetPHCSample(int fd, int nocrossts, double precision, int *reading_mode,
|
||||||
|
struct timespec *phc_ts, struct timespec *sys_ts, double *err);
|
||||||
|
|
||||||
#endif /* GOT_SYS_LINUX_H */
|
#endif /* GOT_SYS_LINUX_H */
|
||||||
|
|||||||
@@ -32,6 +32,14 @@ check_chronyd_exit || test_fail
|
|||||||
check_source_selection || test_fail
|
check_source_selection || test_fail
|
||||||
check_sync || test_fail
|
check_sync || test_fail
|
||||||
|
|
||||||
|
client_server_options="minpoll 6 maxpoll 6 xleave maxdelay 1e-1"
|
||||||
|
|
||||||
|
run_test || test_fail
|
||||||
|
check_chronyd_exit || test_fail
|
||||||
|
check_source_selection || test_fail
|
||||||
|
check_sync || test_fail
|
||||||
|
|
||||||
|
client_server_options="minpoll 6 maxpoll 6"
|
||||||
min_sync_time=$default_min_sync_time
|
min_sync_time=$default_min_sync_time
|
||||||
max_sync_time=$default_max_sync_time
|
max_sync_time=$default_max_sync_time
|
||||||
time_max_limit=11
|
time_max_limit=11
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ test_unit(void)
|
|||||||
|
|
||||||
LCL_Initialise();
|
LCL_Initialise();
|
||||||
|
|
||||||
clock = HCL_CreateInstance();
|
clock = HCL_CreateInstance(1.0);
|
||||||
|
|
||||||
for (i = 0; i < 2000; i++) {
|
for (i = 0; i < 2000; i++) {
|
||||||
UTI_ZeroTimespec(&start_hw_ts);
|
UTI_ZeroTimespec(&start_hw_ts);
|
||||||
@@ -43,7 +43,7 @@ test_unit(void)
|
|||||||
|
|
||||||
freq = TST_GetRandomDouble(0.9, 1.1);
|
freq = TST_GetRandomDouble(0.9, 1.1);
|
||||||
jitter = TST_GetRandomDouble(10.0e-9, 1000.0e-9);
|
jitter = TST_GetRandomDouble(10.0e-9, 1000.0e-9);
|
||||||
interval = TST_GetRandomDouble(MIN_SAMPLE_SEPARATION / 10, MIN_SAMPLE_SEPARATION * 10.0);
|
interval = TST_GetRandomDouble(0.1, 10.0);
|
||||||
|
|
||||||
clock->n_samples = 0;
|
clock->n_samples = 0;
|
||||||
clock->valid_coefs = 0;
|
clock->valid_coefs = 0;
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ send_request(void)
|
|||||||
advance_time(1e-4);
|
advance_time(1e-4);
|
||||||
|
|
||||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||||
|
local_addr.if_index = INVALID_IF_INDEX;
|
||||||
local_addr.sock_fd = 101;
|
local_addr.sock_fd = 101;
|
||||||
local_ts.ts = current_time;
|
local_ts.ts = current_time;
|
||||||
local_ts.err = 0.0;
|
local_ts.err = 0.0;
|
||||||
@@ -176,6 +177,7 @@ process_response(int valid, int updated)
|
|||||||
res = &res_buffer.ntp_pkt;
|
res = &res_buffer.ntp_pkt;
|
||||||
|
|
||||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||||
|
local_addr.if_index = INVALID_IF_INDEX;
|
||||||
local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) == MODE_ACTIVE ? 100 : 101;
|
local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) == MODE_ACTIVE ? 100 : 101;
|
||||||
local_ts.ts = current_time;
|
local_ts.ts = current_time;
|
||||||
local_ts.err = 0.0;
|
local_ts.err = 0.0;
|
||||||
|
|||||||
Reference in New Issue
Block a user