mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 18:25:07 -05:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8d546a0d1 | ||
|
|
04e6474b75 | ||
|
|
eb51c500e8 | ||
|
|
6f8fba9a3f | ||
|
|
750afc30f2 | ||
|
|
e0e6ec0d84 | ||
|
|
c9f50fc686 | ||
|
|
83c26b458b | ||
|
|
b711873f45 | ||
|
|
c68ca40ce4 | ||
|
|
51fe80ad95 | ||
|
|
7ffee73524 | ||
|
|
f40b0024bd | ||
|
|
a06c9909a6 | ||
|
|
aee42fada8 | ||
|
|
3e93068c43 | ||
|
|
36291b707b | ||
|
|
6dad2c24bf | ||
|
|
27cbf20d23 | ||
|
|
5c571bbbe7 | ||
|
|
33d65c8614 | ||
|
|
d87db7cdb8 | ||
|
|
45fa4750da | ||
|
|
8472fd8133 | ||
|
|
5ab645e310 | ||
|
|
8ccda538d3 | ||
|
|
b06d74ab73 | ||
|
|
d0964ffa83 | ||
|
|
3d08815efb | ||
|
|
a83f0d3cdc | ||
|
|
702db726d3 | ||
|
|
ed5c43204b | ||
|
|
f91bdd604d | ||
|
|
3a1dbb1354 | ||
|
|
4b511143b8 | ||
|
|
93076e7e1c | ||
|
|
1c51feb3c5 | ||
|
|
c2773dbc2f | ||
|
|
4534db84c4 | ||
|
|
be8215e181 | ||
|
|
ae82bbbace | ||
|
|
2b6ea41062 | ||
|
|
d9f745fe70 | ||
|
|
9aac179367 | ||
|
|
b896bb5a78 | ||
|
|
64c2fd9888 | ||
|
|
2668a12e4e | ||
|
|
e1645966ec | ||
|
|
4f1fc1ee78 | ||
|
|
d70df3daab |
9
NEWS
9
NEWS
@@ -4,14 +4,19 @@ New in version 3.2
|
||||
Enhancements
|
||||
------------
|
||||
* Improve stability with NTP sources and reference clocks
|
||||
* Improve stability with hardware timestamping
|
||||
* Improve support for NTP interleaved modes
|
||||
* Control frequency of system clock on macOS 10.13 and later
|
||||
* Set TAI-UTC offset of system clock with leapsectz directive
|
||||
* Add support for new HW timestamping options added in Linux 4.13
|
||||
* Add rxfilter option to hwtimestamp directive
|
||||
* Minimise data in client requests to improve privacy
|
||||
* Allow transmit-only hardware timestamping
|
||||
* Add support for new timestamping options introduced in Linux 4.13
|
||||
* Add root delay, root dispersion and maximum error to tracking log
|
||||
* Add mindelay and asymmetry options to server/peer/pool directive
|
||||
* Add extpps option to PHC refclock to timestamp external PPS signal
|
||||
* Add pps option to refclock directive to treat any refclock as PPS
|
||||
* Add width option to refclock directive to filter wrong pulse edges
|
||||
* Add rxfilter option to hwtimestamp directive
|
||||
* Add -x option to disable control of system clock
|
||||
* Add -l option to log to specified file instead of syslog
|
||||
* Allow multiple command-line options to be specified together
|
||||
|
||||
2
README
2
README
@@ -4,7 +4,7 @@ What is chrony?
|
||||
===============
|
||||
|
||||
chrony is a versatile implementation of the Network Time Protocol (NTP).
|
||||
It can synchronize the system clock with NTP servers, reference clocks
|
||||
It can synchronise the system clock with NTP servers, reference clocks
|
||||
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
|
||||
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
|
||||
a time service to other computers in the network.
|
||||
|
||||
7
array.c
7
array.c
@@ -66,8 +66,6 @@ ARR_DestroyInstance(ARR_Instance array)
|
||||
static void
|
||||
realloc_array(ARR_Instance array, unsigned int min_size)
|
||||
{
|
||||
size_t data_size;
|
||||
|
||||
assert(min_size <= 2 * min_size);
|
||||
if (array->allocated >= min_size && array->allocated <= 2 * min_size)
|
||||
return;
|
||||
@@ -79,10 +77,7 @@ realloc_array(ARR_Instance array, unsigned int min_size)
|
||||
array->allocated = min_size;
|
||||
}
|
||||
|
||||
data_size = (size_t)array->elem_size * array->allocated;
|
||||
assert(data_size / array->elem_size == array->allocated);
|
||||
|
||||
array->data = Realloc(array->data, data_size);
|
||||
array->data = Realloc2(array->data, array->allocated, array->elem_size);
|
||||
}
|
||||
|
||||
void *
|
||||
|
||||
7
candm.h
7
candm.h
@@ -97,7 +97,9 @@
|
||||
#define REQ_NTP_DATA 57
|
||||
#define REQ_ADD_SERVER2 58
|
||||
#define REQ_ADD_PEER2 59
|
||||
#define N_REQUEST_TYPES 60
|
||||
#define REQ_ADD_SERVER3 60
|
||||
#define REQ_ADD_PEER3 61
|
||||
#define N_REQUEST_TYPES 62
|
||||
|
||||
/* Structure used to exchange timespecs independent of time_t size */
|
||||
typedef struct {
|
||||
@@ -267,8 +269,11 @@ typedef struct {
|
||||
Float max_delay;
|
||||
Float max_delay_ratio;
|
||||
Float max_delay_dev_ratio;
|
||||
Float min_delay;
|
||||
Float asymmetry;
|
||||
Float offset;
|
||||
uint32_t flags;
|
||||
uint32_t reserved[4];
|
||||
int32_t EOR;
|
||||
} REQ_NTP_Source;
|
||||
|
||||
|
||||
12
client.c
12
client.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Lonnie Abelbeck 2016
|
||||
* Copyright (C) Miroslav Lichvar 2009-2016
|
||||
* Copyright (C) Miroslav Lichvar 2009-2017
|
||||
*
|
||||
* 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
|
||||
@@ -1101,6 +1101,8 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
|
||||
msg->data.ntp_source.max_delay_ratio = UTI_FloatHostToNetwork(data.params.max_delay_ratio);
|
||||
msg->data.ntp_source.max_delay_dev_ratio =
|
||||
UTI_FloatHostToNetwork(data.params.max_delay_dev_ratio);
|
||||
msg->data.ntp_source.min_delay = UTI_FloatHostToNetwork(data.params.min_delay);
|
||||
msg->data.ntp_source.asymmetry = UTI_FloatHostToNetwork(data.params.asymmetry);
|
||||
msg->data.ntp_source.offset = UTI_FloatHostToNetwork(data.params.offset);
|
||||
msg->data.ntp_source.flags = htonl(
|
||||
(data.params.online ? REQ_ADDSRC_ONLINE : 0) |
|
||||
@@ -1111,6 +1113,8 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
|
||||
(data.params.sel_options & SRC_SELECT_NOSELECT ? REQ_ADDSRC_NOSELECT : 0) |
|
||||
(data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) |
|
||||
(data.params.sel_options & SRC_SELECT_REQUIRE ? REQ_ADDSRC_REQUIRE : 0));
|
||||
memset(msg->data.ntp_source.reserved, 0, sizeof (msg->data.ntp_source.reserved));
|
||||
|
||||
result = 1;
|
||||
|
||||
break;
|
||||
@@ -1124,7 +1128,7 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
|
||||
static int
|
||||
process_cmd_add_server(CMD_Request *msg, char *line)
|
||||
{
|
||||
msg->command = htons(REQ_ADD_SERVER2);
|
||||
msg->command = htons(REQ_ADD_SERVER3);
|
||||
return process_cmd_add_server_or_peer(msg, line);
|
||||
}
|
||||
|
||||
@@ -1133,7 +1137,7 @@ process_cmd_add_server(CMD_Request *msg, char *line)
|
||||
static int
|
||||
process_cmd_add_peer(CMD_Request *msg, char *line)
|
||||
{
|
||||
msg->command = htons(REQ_ADD_PEER2);
|
||||
msg->command = htons(REQ_ADD_PEER3);
|
||||
return process_cmd_add_server_or_peer(msg, line);
|
||||
}
|
||||
|
||||
@@ -3143,7 +3147,7 @@ main(int argc, char **argv)
|
||||
optind = 1;
|
||||
|
||||
/* Parse short command-line options */
|
||||
while ((opt = getopt(argc, argv, "46acdf:h:mnp:v")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "+46acdf:h:mnp:v")) != -1) {
|
||||
switch (opt) {
|
||||
case '4':
|
||||
case '6':
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2015-2016
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2015-2017
|
||||
*
|
||||
* 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
|
||||
|
||||
8
cmdmon.c
8
cmdmon.c
@@ -136,6 +136,8 @@ static const char permissions[] = {
|
||||
PERMIT_AUTH, /* NTP_DATA */
|
||||
PERMIT_AUTH, /* ADD_SERVER2 */
|
||||
PERMIT_AUTH, /* ADD_PEER2 */
|
||||
PERMIT_AUTH, /* ADD_SERVER3 */
|
||||
PERMIT_AUTH, /* ADD_PEER3 */
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
@@ -791,6 +793,8 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m
|
||||
UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio);
|
||||
params.max_delay_dev_ratio =
|
||||
UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_dev_ratio);
|
||||
params.min_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.min_delay);
|
||||
params.asymmetry = UTI_FloatNetworkToHost(rx_message->data.ntp_source.asymmetry);
|
||||
params.offset = UTI_FloatNetworkToHost(rx_message->data.ntp_source.offset);
|
||||
|
||||
params.online = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ? 1 : 0;
|
||||
@@ -1525,11 +1529,11 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
handle_cmdaccheck(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_ADD_SERVER2:
|
||||
case REQ_ADD_SERVER3:
|
||||
handle_add_source(NTP_SERVER, &rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_ADD_PEER2:
|
||||
case REQ_ADD_PEER3:
|
||||
handle_add_source(NTP_PEER, &rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
|
||||
@@ -64,6 +64,8 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
src->params.max_delay = SRC_DEFAULT_MAXDELAY;
|
||||
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
|
||||
src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
|
||||
src->params.min_delay = 0.0;
|
||||
src->params.asymmetry = SRC_DEFAULT_ASYMMETRY;
|
||||
src->params.offset = 0.0;
|
||||
|
||||
hostname = line;
|
||||
@@ -98,6 +100,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
|
||||
src->params.authkey == INACTIVE_AUTHKEY)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "asymmetry")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.asymmetry, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "maxdelay")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1)
|
||||
return 0;
|
||||
@@ -116,6 +121,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
} else if (!strcasecmp(cmd, "maxsources")) {
|
||||
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "mindelay")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.min_delay, &n) != 1)
|
||||
return 0;
|
||||
} else if (!strcasecmp(cmd, "minpoll")) {
|
||||
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1)
|
||||
return 0;
|
||||
|
||||
8
conf.c
8
conf.c
@@ -1281,7 +1281,7 @@ parse_hwtimestamp(char *line)
|
||||
iface->name = Strdup(p);
|
||||
iface->minpoll = 0;
|
||||
iface->nocrossts = 0;
|
||||
iface->rxfilter = CNF_HWTS_RXFILTER_NTP;
|
||||
iface->rxfilter = CNF_HWTS_RXFILTER_ANY;
|
||||
iface->precision = 100.0e-9;
|
||||
iface->tx_comp = 0.0;
|
||||
iface->rx_comp = 0.0;
|
||||
@@ -1335,7 +1335,11 @@ parse_include(char *line)
|
||||
|
||||
check_number_of_args(line, 1);
|
||||
|
||||
if ((r = glob(line, GLOB_ERR | GLOB_NOMAGIC, NULL, &gl)) != 0) {
|
||||
if ((r = glob(line,
|
||||
#ifdef GLOB_NOMAGIC
|
||||
GLOB_NOMAGIC |
|
||||
#endif
|
||||
GLOB_ERR, NULL, &gl)) != 0) {
|
||||
if (r != GLOB_NOMATCH)
|
||||
LOG_FATAL("Could not search for files matching %s", line);
|
||||
|
||||
|
||||
11
conf.h
11
conf.h
@@ -118,15 +118,18 @@ extern char *CNF_GetHwclockFile(void);
|
||||
extern int CNF_GetInitSources(void);
|
||||
extern double CNF_GetInitStepThreshold(void);
|
||||
|
||||
#define CNF_HWTS_RXFILTER_NONE 0
|
||||
#define CNF_HWTS_RXFILTER_NTP 1
|
||||
#define CNF_HWTS_RXFILTER_ALL 2
|
||||
typedef enum {
|
||||
CNF_HWTS_RXFILTER_ANY,
|
||||
CNF_HWTS_RXFILTER_NONE,
|
||||
CNF_HWTS_RXFILTER_NTP,
|
||||
CNF_HWTS_RXFILTER_ALL,
|
||||
} CNF_HwTs_RxFilter;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int minpoll;
|
||||
int nocrossts;
|
||||
int rxfilter;
|
||||
CNF_HwTs_RxFilter rxfilter;
|
||||
double precision;
|
||||
double tx_comp;
|
||||
double rx_comp;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
//
|
||||
// Copyright (C) Richard P. Curnow 1997-2003
|
||||
// Copyright (C) Stephen Wadeley 2016
|
||||
// Copyright (C) Bryan Christianson 2017
|
||||
// Copyright (C) Miroslav Lichvar 2009-2017
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
@@ -115,13 +116,25 @@ round-trip delay of 0.3 seconds or more should be ignored. The default value is
|
||||
This option is similar to the maxdelay option above. *chronyd* keeps a record
|
||||
of the minimum round-trip delay amongst the previous measurements that it has
|
||||
buffered. If a measurement has a round trip delay that is greater than the
|
||||
maxdelayratio times the minimum delay, it will be rejected. This option works
|
||||
only in the *server* directive when not in the interleaved mode.
|
||||
maxdelayratio times the minimum delay, it will be rejected.
|
||||
*maxdelaydevratio* _ratio_:::
|
||||
If a measurement has a ratio of the increase in the round-trip delay from the
|
||||
minimum delay amongst the previous measurements to the standard deviation of
|
||||
the previous measurements that is greater than the specified ratio, it will be
|
||||
rejected. The default is 10.0.
|
||||
*mindelay* _delay_:::
|
||||
This options specifies a fixed minimum round-trip delay to be used instead of
|
||||
the minimum amongst the previous measurements. This can be useful in networks
|
||||
with static configuration to improve the stability of corrections for
|
||||
asymmetric jitter, weighting of the measurements, and the *maxdelayratio* and
|
||||
*maxdelaydevratio* tests. The value should be set accurately in order to have a
|
||||
positive effect on the synchronisation.
|
||||
*asymmetry* _ratio_:::
|
||||
This options specifies the asymmetry of the network jitter on the path to the
|
||||
source, which is used to correct the measured offset according to the delay.
|
||||
The asymmetry can be between -0.5 and +0.5. A negative value means the delay of
|
||||
packets sent to the source is more variable than the delay of packets sent from
|
||||
the source back. By default, *chronyd* estimates the asymmetry automatically.
|
||||
*offset* _offset_:::
|
||||
This option specifies a correction (in seconds) which will be applied to
|
||||
offsets measured with this source. It's particularly useful to compensate for a
|
||||
@@ -178,10 +191,9 @@ and the state might be dropped when there are too many clients (e.g.
|
||||
by other clients that have the same IP address (e.g. computers behind NAT or
|
||||
someone sending requests with a spoofed source address).
|
||||
+
|
||||
With longer polling intervals, it is recommended to combine the *xleave* option
|
||||
with the *presend* option in order to shorten the interval in which the server
|
||||
has to keep the state to be able to respond in the interleaved mode. The
|
||||
shorter interval also improves accuracy of the measured offset and delay.
|
||||
The *xleave* option can be combined with the *presend* option in order to
|
||||
shorten the interval in which the server has to keep the state to be able to
|
||||
respond in the interleaved mode.
|
||||
*polltarget* _target_:::
|
||||
Target number of measurements to use for the regression algorithm which
|
||||
*chronyd* will try to maintain by adjusting the polling interval between
|
||||
@@ -488,7 +500,7 @@ This option specifies the width of the pulses (in seconds). It is used to
|
||||
filter PPS samples when the driver provides samples for both rising and falling
|
||||
edges. Note that it reduces the maximum allowed error of the time source which
|
||||
completes the PPS samples. If the duty cycle is configurable, 50% should be
|
||||
prefered in order to maximise the allowed error.
|
||||
preferred in order to maximise the allowed error.
|
||||
*pps*:::
|
||||
This options forces *chronyd* to treat any refclock (e.g. SHM or PHC) as a PPS
|
||||
refclock. This can be useful when the refclock provides time with a variable
|
||||
@@ -1611,7 +1623,7 @@ from the example line above):
|
||||
. The root dispersion (_EPSILON_ in RFC 5905). [7.446e-03]
|
||||
. Reference ID of the server's source as a hexadecimal number. [CB00717B]
|
||||
. NTP mode of the received packet (_1_=active peer, _2_=passive peer,
|
||||
_3_=server, _B_=basic, _I_=interleaved). [4B]
|
||||
_4_=server, _B_=basic, _I_=interleaved). [4B]
|
||||
. Source of the local transmit timestamp
|
||||
(_D_=daemon, _K_=kernel, _H_=hardware). [D]
|
||||
. Source of the local receive timestamp
|
||||
@@ -1665,11 +1677,11 @@ from the example line above):
|
||||
to be discarded. The number of runs for the data that is being retained is
|
||||
tabulated. Values of approximately half the number of samples are expected.
|
||||
[8]
|
||||
. The estimated asymmetry of network jitter on the path to the source which was
|
||||
used to correct the measured offsets. The asymmetry can be between -0.5 and
|
||||
0.5. A negative value means the delay of packets sent to the source is
|
||||
more variable than the delay of packets sent from the source back. [0.00,
|
||||
i.e. no correction for asymmetry]
|
||||
. The estimated or configured asymmetry of network jitter on the path to the
|
||||
source which was used to correct the measured offsets. The asymmetry can be
|
||||
between -0.5 and +0.5. A negative value means the delay of packets sent to
|
||||
the source is more variable than the delay of packets sent from the source
|
||||
back. [0.00, i.e. no correction for asymmetry]
|
||||
+
|
||||
*tracking*:::
|
||||
This option logs changes to the estimate of the system's gain or loss rate, and
|
||||
@@ -1678,33 +1690,42 @@ actually appears as a single line in the file) from the log file is shown
|
||||
below.
|
||||
+
|
||||
----
|
||||
2015-02-23 05:40:50 203.0.113.15 3 340.529 1.606 1.046e-03 N \
|
||||
4 6.849e-03 -4.670e-04
|
||||
2017-08-22 13:22:36 203.0.113.15 2 -3.541 0.075 -8.621e-06 N \
|
||||
2 2.940e-03 -2.084e-04 1.534e-02 3.472e-04 8.304e-03
|
||||
----
|
||||
+
|
||||
The columns are as follows (the quantities in square brackets are the
|
||||
values from the example line above) :
|
||||
+
|
||||
. Date [2015-02-03]
|
||||
. Date [2017-08-22]
|
||||
. Hour:Minute:Second. Note that the date-time pair is expressed in UTC, not the
|
||||
local time zone. [05:40:50]
|
||||
local time zone. [13:22:36]
|
||||
. The IP address of the server or peer to which the local system is synchronised.
|
||||
[203.0.113.15]
|
||||
. The stratum of the local system. [3]
|
||||
. The stratum of the local system. [2]
|
||||
. The local system frequency (in ppm, positive means the local system runs fast
|
||||
of UTC). [340.529]
|
||||
. The error bounds on the frequency (in ppm). [1.606]
|
||||
. The estimated local offset at the epoch (which is rapidly corrected by
|
||||
slewing the local clock. (In seconds, positive indicates the local system
|
||||
is fast of UTC). [1.046e-3]
|
||||
of UTC). [-3.541]
|
||||
. The error bounds on the frequency (in ppm). [0.075]
|
||||
. The estimated local offset at the epoch, which is normally corrected by
|
||||
slewing the local clock (in seconds, positive indicates the clock is fast of
|
||||
UTC). [-8.621e-06]
|
||||
. Leap status (_N_ means normal, _+_ means that the last minute of this month
|
||||
has 61 seconds, _-_ means that the last minute of the month has 59 seconds,
|
||||
_?_ means the clock is not currently synchronised.) [N]
|
||||
. The number of combined sources. [4]
|
||||
. The number of combined sources. [2]
|
||||
. The estimated standard deviation of the combined offset (in seconds).
|
||||
[6.849e-03]
|
||||
[2.940e-03]
|
||||
. The remaining offset correction from the previous update (in seconds,
|
||||
positive means the system clock is slow of UTC). [-4.670e-04]
|
||||
positive means the system clock is slow of UTC). [-2.084e-04]
|
||||
. The total of the network path delays to the reference clock to which
|
||||
the local clock is ultimately synchronised (in seconds). [1.534e-02]
|
||||
. The total dispersion accumulated through all the servers back to the
|
||||
reference clock to which the local clock is ultimately synchronised
|
||||
(in seconds). [3.472e-04]
|
||||
. The maximum estimated error of the system clock in the interval since the
|
||||
previous update (in seconds). It includes the offset, remaining offset
|
||||
correction, root delay, and dispersion from the previous update with the
|
||||
dispersion which accumulated in the interval. [8.304e-03]
|
||||
+
|
||||
*rtc*:::
|
||||
This option logs information about the system's real-time clock. An example
|
||||
@@ -1865,20 +1886,18 @@ be enabled by the *xleave* option in the <<server,*server*>> or the
|
||||
This directive is supported on Linux 3.19 and newer. The NIC must support HW
|
||||
timestamping, which can be verified with the *ethtool -T* command. The list of
|
||||
capabilities should include _SOF_TIMESTAMPING_RAW_HARDWARE_,
|
||||
_SOF_TIMESTAMPING_TX_HARDWARE_, _SOF_TIMESTAMPING_RX_HARDWARE_, and the filter
|
||||
modes should include _HWTSTAMP_FILTER_ALL_ or _HWTSTAMP_FILTER_NTP_ALL_. When
|
||||
*chronyd* is running, no other process (e.g. a PTP daemon) should be working
|
||||
with the NIC clock.
|
||||
_SOF_TIMESTAMPING_TX_HARDWARE_, and _SOF_TIMESTAMPING_RX_HARDWARE_. Receive
|
||||
filter _HWTSTAMP_FILTER_ALL_, or _HWTSTAMP_FILTER_NTP_ALL_, is necessary for
|
||||
timestamping of received packets. Timestamping of packets received from bridged
|
||||
and bonded interfaces is supported on Linux 4.13 and newer. When *chronyd* is
|
||||
running, no other process (e.g. a PTP daemon) should be working with the NIC
|
||||
clock.
|
||||
+
|
||||
If the kernel supports software timestamping, it will be enabled for all
|
||||
interfaces. With both hardware and software timestamping there are some
|
||||
limitations on which timestamps can be actually used, e.g. transmit
|
||||
timestamping does not currently work with IPv6 packets using IP options and
|
||||
hardware timestamping of packets received from bridges, bonds, and other
|
||||
virtual interfaces, works only on Linux 4.13 and newer. The source of
|
||||
timestamps (i.e. hardware, kernel, or daemon) is indicated in the
|
||||
_measurements.log_ file if enabled by the <<log,*log measurements*>> directive,
|
||||
and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in *chronyc*.
|
||||
interfaces. The source of timestamps (i.e. hardware, kernel, or daemon) is
|
||||
indicated in the _measurements.log_ file if enabled by the <<log,*log
|
||||
measurements*>> directive, and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in
|
||||
*chronyc*.
|
||||
+
|
||||
If the specified interface is _*_, *chronyd* will try to enable HW timestamping
|
||||
on all available interfaces.
|
||||
@@ -1907,15 +1926,21 @@ is 0.
|
||||
Some hardware can precisely cross timestamp the NIC clock with the system
|
||||
clock. This option disables the use of the cross timestamping.
|
||||
*rxfilter* _filter_:::
|
||||
This option selects the receive timestamping filter. Possible values are:
|
||||
_all_, _ntp_, and _none_. The default value is _ntp_, which enables
|
||||
timestamping of NTP packets (_HWTSTAMP_FILTER_NTP_ALL_) if it is supported, or
|
||||
timestamping of all packets (_HWTSTAMP_FILTER_ALL_). Setting *rxfilter* to
|
||||
_all_ forces timestamping of all packets, which can be useful when the NIC
|
||||
supports both filters and NTP packets are received from or on a non-standard
|
||||
UDP port (e.g. specified by the *port* directive). Setting *rxfilter* to _none_
|
||||
disables receive HW timestamping and allows transmit HW timestamping to be
|
||||
enabled when the NIC supports only PTP-specific receive filters.
|
||||
This option selects the receive timestamping filter. The _filter_ can be one of
|
||||
the following:
|
||||
_all_::::
|
||||
Enables timestamping of all received packets.
|
||||
_ntp_::::
|
||||
Enables timestamping of received NTP packets.
|
||||
_none_::::
|
||||
Disables timestamping of received packets.
|
||||
:::
|
||||
The most specific filter for timestamping NTP packets which is supported by the
|
||||
NIC is selected by default. Some NICs can timestamp only PTP packets, which
|
||||
limits the selection to the _none_ filter. Forcing timestamping of all packets
|
||||
with the _all_ filter when the NIC supports both _all_ and _ntp_ filters can be
|
||||
useful when packets are received from or on a non-standard UDP port (e.g.
|
||||
specified by the *port* directive).
|
||||
::
|
||||
+
|
||||
Examples of the directive are:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// Copyright (C) Richard P. Curnow 1997-2003
|
||||
// Copyright (C) Stephen Wadeley 2016
|
||||
// Copyright (C) Miroslav Lichvar 2009-2016
|
||||
// Copyright (C) Miroslav Lichvar 2009-2017
|
||||
//
|
||||
// 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
|
||||
@@ -216,7 +216,7 @@ An absolute bound on the computer's clock accuracy (assuming the stratum-1
|
||||
computer is correct) is given by:
|
||||
+
|
||||
----
|
||||
clock_error <= root_dispersion + (0.5 * |root_delay|)
|
||||
clock_error <= |system_time_offset| + root_dispersion + (0.5 * root_delay)
|
||||
----
|
||||
*Update interval*:::
|
||||
This is the interval between the last two clock updates.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is part of chrony
|
||||
//
|
||||
// Copyright (C) Richard P. Curnow 1997-2003
|
||||
// Copyright (C) Miroslav Lichvar 2009-2016
|
||||
// Copyright (C) Miroslav Lichvar 2009-2017
|
||||
//
|
||||
// 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
|
||||
|
||||
@@ -50,7 +50,7 @@ directive can be used for names that resolve to multiple addresses. For good
|
||||
reliability the client should have at least three servers. The `iburst` option
|
||||
speeds up the initial synchronisation.
|
||||
|
||||
To stabilize the initial synchronisation on the next start, the estimated drift
|
||||
To stabilise the initial synchronisation on the next start, the estimated drift
|
||||
of the system clock is saved to a file specified by the `driftfile` directive.
|
||||
|
||||
If the system clock can be far from the true time after boot for any reason,
|
||||
@@ -59,7 +59,7 @@ slewing, which would take a very long time. The `makestep` directive does
|
||||
that.
|
||||
|
||||
In order to keep the real-time clock (RTC) close to the true time, so the
|
||||
system time is reasonably close to the true time when it's initialized on the
|
||||
system time is reasonably close to the true time when it's initialised on the
|
||||
next boot from the RTC, the `rtcsync` directive enables a mode in which the
|
||||
system time is periodically copied to the RTC. It is supported on Linux and
|
||||
macOS.
|
||||
@@ -347,14 +347,14 @@ Only by the source code. See _cmdmon.c_ (`chronyd` side) and _client.c_
|
||||
=== What is the real-time clock (RTC)?
|
||||
|
||||
This is the clock which keeps the time even when your computer is turned off.
|
||||
It is used to initialize the system clock on boot. It normally doesn't drift
|
||||
It is used to initialise the system clock on boot. It normally doesn't drift
|
||||
more than few seconds per day.
|
||||
|
||||
There are two approaches how `chronyd` can work with it. One is to use the
|
||||
`rtcsync` directive, which tells `chronyd` to enable a kernel mode which sets
|
||||
the RTC from the system clock every 11 minutes. `chronyd` itself won't touch
|
||||
the RTC. If the computer is not turned off for a long time, the RTC should
|
||||
still be close to the true time when the system clock will be initialized from
|
||||
still be close to the true time when the system clock will be initialised from
|
||||
it on the next boot.
|
||||
|
||||
The other option is to use the `rtcfile` directive, which tells `chronyd` to
|
||||
|
||||
@@ -28,6 +28,9 @@ rtcsync
|
||||
# Specify file containing keys for NTP authentication.
|
||||
#keyfile /etc/chrony.keys
|
||||
|
||||
# Get TAI-UTC offset and leap seconds from the system tz database.
|
||||
#leapsectz right/UTC
|
||||
|
||||
# Specify directory for log files.
|
||||
logdir /var/log/chrony
|
||||
|
||||
|
||||
@@ -97,6 +97,12 @@ driftfile /var/lib/chrony/drift
|
||||
|
||||
! pidfile /var/run/chronyd.pid
|
||||
|
||||
# If the system timezone database is kept up to date and includes the
|
||||
# right/UTC timezone, chronyd can use it to determine the current
|
||||
# TAI-UTC offset and when will the next leap second occur.
|
||||
|
||||
! leapsectz right/UTC
|
||||
|
||||
#######################################################################
|
||||
### INITIAL CLOCK CORRECTION
|
||||
# This option is useful to quickly correct the clock on start if it's
|
||||
|
||||
@@ -1,17 +1,35 @@
|
||||
#!/bin/sh
|
||||
# This is a NetworkManager dispatcher script for chronyd to set its NTP sources
|
||||
# online/offline when a default route is configured/removed on the system.
|
||||
# online or offline when a network interface is configured or removed
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
if [ "$2" = "up" ]; then
|
||||
/sbin/ip route list dev "$1" | grep -q '^default' &&
|
||||
/usr/bin/chronyc online > /dev/null 2>&1
|
||||
# Check if there is a default route
|
||||
|
||||
if /sbin/ip route list 2> /dev/null | grep -q '^default'; then
|
||||
chronyc online > /dev/null 2>&1
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$2" = "down" ]; then
|
||||
/sbin/ip route list | grep -q '^default' ||
|
||||
/usr/bin/chronyc offline > /dev/null 2>&1
|
||||
fi
|
||||
sources=$(chronyc -c -n sources 2> /dev/null)
|
||||
|
||||
[ $? -ne 0 ] && exit 0
|
||||
|
||||
# Check each configured source if it has a route
|
||||
|
||||
echo "$sources" | while IFS=, read mode state address rest; do
|
||||
[ "$mode" != '^' ] && [ "$mode" != '=' ] && continue
|
||||
|
||||
/sbin/ip route get "$address" > /dev/null 2>&1 && command="online" || command="offline"
|
||||
|
||||
# Set priority of sources so that the selected source is set as
|
||||
# last if offline to avoid unnecessary reselection
|
||||
[ "$state" != '*' ] && priority=1 || priority=2
|
||||
|
||||
echo "$priority $command $address"
|
||||
|
||||
done | sort | while read priority command address; do
|
||||
echo "$command $address"
|
||||
done | chronyc > /dev/null 2>&1
|
||||
|
||||
exit 0
|
||||
|
||||
24
hwclock.c
24
hwclock.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016
|
||||
* Copyright (C) Miroslav Lichvar 2016-2017
|
||||
*
|
||||
* 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
|
||||
@@ -39,6 +39,9 @@
|
||||
/* Maximum number of samples per clock */
|
||||
#define MAX_SAMPLES 16
|
||||
|
||||
/* Maximum acceptable frequency offset of the clock */
|
||||
#define MAX_FREQ_OFFSET (2.0 / 3.0)
|
||||
|
||||
struct HCL_Instance_Record {
|
||||
/* HW and local reference timestamp */
|
||||
struct timespec hw_ref;
|
||||
@@ -174,16 +177,17 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
|
||||
/* Drop unneeded samples */
|
||||
clock->n_samples -= best_start;
|
||||
|
||||
/* If the fit doesn't cross the error interval of the last sample, throw away
|
||||
all previous samples and keep only the frequency estimate */
|
||||
if (fabs(clock->offset) > err) {
|
||||
DEBUG_LOG("HW clock reset offset=%e", clock->offset);
|
||||
clock->offset = 0.0;
|
||||
clock->n_samples = 1;
|
||||
/* If the fit doesn't cross the error interval of the last sample,
|
||||
or the frequency is not sane, drop all samples and start again */
|
||||
if (fabs(clock->offset) > err ||
|
||||
fabs(clock->frequency - 1.0) > MAX_FREQ_OFFSET) {
|
||||
DEBUG_LOG("HW clock reset");
|
||||
clock->n_samples = 0;
|
||||
clock->valid_coefs = 0;
|
||||
}
|
||||
|
||||
DEBUG_LOG("HW clock samples=%d offset=%e freq=%.9e raw_freq=%.9e err=%e ref_diff=%e",
|
||||
clock->n_samples, clock->offset, clock->frequency, raw_freq, err,
|
||||
DEBUG_LOG("HW clock samples=%d offset=%e freq=%e raw_freq=%e err=%e ref_diff=%e",
|
||||
clock->n_samples, clock->offset, clock->frequency - 1.0, raw_freq - 1.0, err,
|
||||
UTI_DiffTimespecsToDouble(&clock->hw_ref, &clock->local_ref));
|
||||
}
|
||||
|
||||
@@ -198,7 +202,7 @@ HCL_CookTime(HCL_Instance clock, struct timespec *raw, struct timespec *cooked,
|
||||
return 0;
|
||||
|
||||
elapsed = UTI_DiffTimespecsToDouble(raw, &clock->hw_ref);
|
||||
offset = clock->offset + elapsed / clock->frequency;
|
||||
offset = elapsed / clock->frequency - clock->offset;
|
||||
UTI_AddDoubleToTimespec(&clock->local_ref, offset, cooked);
|
||||
|
||||
/* Fow now, just return the error of the last sample */
|
||||
|
||||
@@ -188,6 +188,9 @@ LOG_OpenFileLog(const char *log_file)
|
||||
if (!f)
|
||||
LOG_FATAL("Could not open log file %s", log_file);
|
||||
|
||||
/* Enable line buffering */
|
||||
setvbuf(f, NULL, _IOLBF, BUFSIZ);
|
||||
|
||||
file_log = f;
|
||||
}
|
||||
|
||||
|
||||
9
main.c
9
main.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) John G. Hasler 2009
|
||||
* Copyright (C) Miroslav Lichvar 2012-2016
|
||||
* Copyright (C) Miroslav Lichvar 2012-2017
|
||||
*
|
||||
* 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
|
||||
@@ -448,8 +448,13 @@ int main
|
||||
sched_priority = parse_int_arg(optarg);
|
||||
break;
|
||||
case 'q':
|
||||
ref_mode = REF_ModeUpdateOnce;
|
||||
nofork = 1;
|
||||
client_only = 0;
|
||||
system_log = 0;
|
||||
break;
|
||||
case 'Q':
|
||||
ref_mode = opt == 'q' ? REF_ModeUpdateOnce : REF_ModePrintOnce;
|
||||
ref_mode = REF_ModePrintOnce;
|
||||
nofork = 1;
|
||||
client_only = 1;
|
||||
clock_control = 0;
|
||||
|
||||
28
memory.c
28
memory.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2014
|
||||
* Copyright (C) Miroslav Lichvar 2014, 2017
|
||||
*
|
||||
* 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
|
||||
@@ -54,6 +54,32 @@ Realloc(void *ptr, size_t size)
|
||||
return r;
|
||||
}
|
||||
|
||||
static size_t
|
||||
get_array_size(size_t nmemb, size_t size)
|
||||
{
|
||||
size_t array_size;
|
||||
|
||||
array_size = nmemb * size;
|
||||
|
||||
/* Check for overflow */
|
||||
if (nmemb > 0 && array_size / nmemb != size)
|
||||
LOG_FATAL("Could not allocate memory");
|
||||
|
||||
return array_size;
|
||||
}
|
||||
|
||||
void *
|
||||
Malloc2(size_t nmemb, size_t size)
|
||||
{
|
||||
return Malloc(get_array_size(nmemb, size));
|
||||
}
|
||||
|
||||
void *
|
||||
Realloc2(void *ptr, size_t nmemb, size_t size)
|
||||
{
|
||||
return Realloc(ptr, get_array_size(nmemb, size));
|
||||
}
|
||||
|
||||
char *
|
||||
Strdup(const char *s)
|
||||
{
|
||||
|
||||
6
memory.h
6
memory.h
@@ -30,12 +30,14 @@
|
||||
/* Wrappers checking for errors */
|
||||
extern void *Malloc(size_t size);
|
||||
extern void *Realloc(void *ptr, size_t size);
|
||||
extern void *Malloc2(size_t nmemb, size_t size);
|
||||
extern void *Realloc2(void *ptr, size_t nmemb, size_t size);
|
||||
extern char *Strdup(const char *s);
|
||||
|
||||
/* Convenient macros */
|
||||
#define MallocNew(T) ((T *) Malloc(sizeof(T)))
|
||||
#define MallocArray(T, n) ((T *) Malloc((n) * sizeof(T)))
|
||||
#define ReallocArray(T,n,x) ((T *) Realloc((void *)(x), (n)*sizeof(T)))
|
||||
#define MallocArray(T, n) ((T *) Malloc2(n, sizeof(T)))
|
||||
#define ReallocArray(T, n, x) ((T *) Realloc2((void *)(x), n, sizeof(T)))
|
||||
#define Free(x) free(x)
|
||||
|
||||
#endif /* GOT_MEMORY_H */
|
||||
|
||||
163
ntp_core.c
163
ntp_core.c
@@ -178,8 +178,10 @@ struct NCR_Instance_Record {
|
||||
NTP_int64 local_ntp_tx;
|
||||
NTP_Local_Timestamp local_tx;
|
||||
|
||||
/* Previous local transmit timestamp for the interleaved mode */
|
||||
/* Previous values of some variables needed in interleaved mode */
|
||||
NTP_Local_Timestamp prev_local_tx;
|
||||
int prev_local_poll;
|
||||
unsigned int prev_tx_count;
|
||||
|
||||
/* The instance record in the main source management module. This
|
||||
performs the statistical analysis on the samples we generate */
|
||||
@@ -425,7 +427,8 @@ restart_timeout(NCR_Instance inst, double delay)
|
||||
/* Start new timer for transmission */
|
||||
inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, get_separation(inst->local_poll),
|
||||
SAMPLING_RANDOMNESS,
|
||||
SCH_NtpSamplingClass,
|
||||
inst->mode == MODE_CLIENT ?
|
||||
SCH_NtpClientClass : SCH_NtpPeerClass,
|
||||
transmit_timeout, (void *)inst);
|
||||
}
|
||||
|
||||
@@ -582,7 +585,8 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
|
||||
result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr),
|
||||
SRC_NTP, params->sel_options,
|
||||
&result->remote_addr.ip_addr,
|
||||
params->min_samples, params->max_samples);
|
||||
params->min_samples, params->max_samples,
|
||||
params->min_delay, params->asymmetry);
|
||||
|
||||
result->rx_timeout_id = 0;
|
||||
result->tx_timeout_id = 0;
|
||||
@@ -654,7 +658,10 @@ NCR_ResetInstance(NCR_Instance instance)
|
||||
UTI_ZeroNtp64(&instance->local_ntp_rx);
|
||||
UTI_ZeroNtp64(&instance->local_ntp_tx);
|
||||
zero_local_timestamp(&instance->local_rx);
|
||||
|
||||
zero_local_timestamp(&instance->prev_local_tx);
|
||||
instance->prev_local_poll = 0;
|
||||
instance->prev_tx_count = 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -976,17 +983,24 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
|
||||
UTI_TimespecToNtp64(&our_ref_time, &message.reference_ts, NULL);
|
||||
|
||||
/* Originate - this comes from the last packet the source sent us */
|
||||
message.originate_ts = interleaved ? *remote_ntp_rx : *remote_ntp_tx;
|
||||
/* Don't reveal timestamps which are not necessary for the protocol */
|
||||
|
||||
/* Prepare random bits which will be added to the receive timestamp */
|
||||
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
|
||||
if (my_mode != MODE_CLIENT || interleaved) {
|
||||
/* Originate - this comes from the last packet the source sent us */
|
||||
message.originate_ts = interleaved ? *remote_ntp_rx : *remote_ntp_tx;
|
||||
|
||||
/* Receive - this is when we received the last packet from the source.
|
||||
This timestamp will have been adjusted so that it will now look to
|
||||
the source like we have been running on our latest estimate of
|
||||
frequency all along */
|
||||
UTI_TimespecToNtp64(&local_receive, &message.receive_ts, &ts_fuzz);
|
||||
/* Prepare random bits which will be added to the receive timestamp */
|
||||
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
|
||||
|
||||
/* Receive - this is when we received the last packet from the source.
|
||||
This timestamp will have been adjusted so that it will now look to
|
||||
the source like we have been running on our latest estimate of
|
||||
frequency all along */
|
||||
UTI_TimespecToNtp64(&local_receive, &message.receive_ts, &ts_fuzz);
|
||||
} else {
|
||||
UTI_ZeroNtp64(&message.originate_ts);
|
||||
UTI_ZeroNtp64(&message.receive_ts);
|
||||
}
|
||||
|
||||
do {
|
||||
/* Prepare random bits which will be added to the transmit timestamp */
|
||||
@@ -1070,7 +1084,7 @@ transmit_timeout(void *arg)
|
||||
{
|
||||
NCR_Instance inst = (NCR_Instance) arg;
|
||||
NTP_Local_Address local_addr;
|
||||
int sent;
|
||||
int interleaved, sent;
|
||||
|
||||
inst->tx_timeout_id = 0;
|
||||
|
||||
@@ -1110,18 +1124,31 @@ transmit_timeout(void *arg)
|
||||
local_addr.if_index = INVALID_IF_INDEX;
|
||||
local_addr.sock_fd = inst->local_addr.sock_fd;
|
||||
|
||||
/* In symmetric mode, don't send a packet in interleaved mode unless it
|
||||
is the first response to the last valid request received from the peer
|
||||
and there was just one response to the previous valid request. This
|
||||
prevents the peer from matching the transmit timestamp with an older
|
||||
response if it can't detect missed responses. In client mode, which has
|
||||
at most one response per request, check how many responses are missing to
|
||||
prevent the server from responding with a very old transmit timestamp. */
|
||||
interleaved = inst->interleaved &&
|
||||
((inst->mode == MODE_CLIENT &&
|
||||
inst->tx_count < MAX_CLIENT_INTERLEAVED_TX) ||
|
||||
(inst->mode == MODE_ACTIVE &&
|
||||
inst->prev_tx_count == 1 && inst->tx_count == 0));
|
||||
|
||||
/* Check whether we need to 'warm up' the link to the other end by
|
||||
sending an NTP exchange to ensure both ends' ARP caches are
|
||||
primed or whether we need to send two packets first to ensure a
|
||||
server in the interleaved mode has a fresh timestamp for us. */
|
||||
if (inst->presend_minpoll <= inst->local_poll && !inst->presend_done &&
|
||||
!inst->burst_total_samples_to_go) {
|
||||
inst->presend_done = inst->interleaved ? 2 : 1;
|
||||
inst->presend_done = interleaved ? 2 : 1;
|
||||
} else if (inst->presend_done > 0) {
|
||||
inst->presend_done--;
|
||||
}
|
||||
|
||||
sent = transmit_packet(inst->mode, inst->interleaved, inst->local_poll,
|
||||
sent = transmit_packet(inst->mode, interleaved, inst->local_poll,
|
||||
inst->version,
|
||||
inst->auth_mode, inst->auth_key_id,
|
||||
&inst->remote_ntp_rx, &inst->remote_ntp_tx,
|
||||
@@ -1298,6 +1325,67 @@ check_packet_auth(NTP_Packet *pkt, int length,
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
check_delay_ratio(NCR_Instance inst, SST_Stats stats,
|
||||
struct timespec *sample_time, double delay)
|
||||
{
|
||||
double last_sample_ago, predicted_offset, min_delay, skew, std_dev;
|
||||
double max_delay;
|
||||
|
||||
if (inst->max_delay_ratio < 1.0 ||
|
||||
!SST_GetDelayTestData(stats, sample_time, &last_sample_ago,
|
||||
&predicted_offset, &min_delay, &skew, &std_dev))
|
||||
return 1;
|
||||
|
||||
max_delay = min_delay * inst->max_delay_ratio +
|
||||
last_sample_ago * (skew + LCL_GetMaxClockError());
|
||||
|
||||
if (delay <= max_delay)
|
||||
return 1;
|
||||
|
||||
DEBUG_LOG("maxdelayratio: delay=%e max_delay=%e", delay, max_delay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
check_delay_dev_ratio(NCR_Instance inst, SST_Stats stats,
|
||||
struct timespec *sample_time, double offset, double delay)
|
||||
{
|
||||
double last_sample_ago, predicted_offset, min_delay, skew, std_dev;
|
||||
double delta, max_delta, error_in_estimate;
|
||||
|
||||
if (!SST_GetDelayTestData(stats, sample_time, &last_sample_ago,
|
||||
&predicted_offset, &min_delay, &skew, &std_dev))
|
||||
return 1;
|
||||
|
||||
/* Require that the ratio of the increase in delay from the minimum to the
|
||||
standard deviation is less than max_delay_dev_ratio. In the allowed
|
||||
increase in delay include also dispersion. */
|
||||
|
||||
max_delta = std_dev * inst->max_delay_dev_ratio +
|
||||
last_sample_ago * (skew + LCL_GetMaxClockError());
|
||||
delta = (delay - min_delay) / 2.0;
|
||||
|
||||
if (delta <= max_delta)
|
||||
return 1;
|
||||
|
||||
error_in_estimate = offset + predicted_offset;
|
||||
|
||||
/* Before we decide to drop the sample, make sure the difference between
|
||||
measured offset and predicted offset is not significantly larger than
|
||||
the increase in delay */
|
||||
if (fabs(error_in_estimate) - delta > max_delta)
|
||||
return 1;
|
||||
|
||||
DEBUG_LOG("maxdelaydevratio: error=%e delay=%e delta=%e max_delta=%e",
|
||||
error_in_estimate, delay, delta, max_delta);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
|
||||
@@ -1424,7 +1512,8 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
if (synced_packet && (!interleaved_packet || inst->valid_timestamps)) {
|
||||
/* These are the timespec equivalents of the remote and local epochs */
|
||||
struct timespec remote_receive, remote_transmit, remote_request_receive;
|
||||
struct timespec local_average, remote_average;
|
||||
struct timespec local_average, remote_average, prev_remote_transmit;
|
||||
double prev_remote_poll_interval;
|
||||
|
||||
/* Select remote and local timestamps for the new sample */
|
||||
if (interleaved_packet) {
|
||||
@@ -1444,10 +1533,12 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
local_transmit = inst->local_tx;
|
||||
}
|
||||
UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
|
||||
UTI_Ntp64ToTimespec(&inst->remote_ntp_tx, &prev_remote_transmit);
|
||||
local_receive = inst->local_rx;
|
||||
} else {
|
||||
UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
|
||||
UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
|
||||
UTI_ZeroTimespec(&prev_remote_transmit);
|
||||
remote_request_receive = remote_receive;
|
||||
local_receive = *rx_ts;
|
||||
local_transmit = inst->local_tx;
|
||||
@@ -1491,35 +1582,38 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
dispersion = MAX(precision, MAX(local_transmit.err, local_receive.err)) +
|
||||
skew * fabs(local_interval);
|
||||
|
||||
/* If the source is an active peer, this is the minimum assumed interval
|
||||
between previous two transmissions (if not constrained by minpoll) */
|
||||
prev_remote_poll_interval = UTI_Log2ToDouble(MIN(inst->remote_poll,
|
||||
inst->prev_local_poll));
|
||||
|
||||
/* Additional tests required to pass before accumulating the sample */
|
||||
|
||||
/* Test A requires that the minimum estimate of the peer delay is not
|
||||
larger than the configured maximum, in client mode that the server
|
||||
processing time is sane, in the interleaved client mode that the
|
||||
timestamps are not too old, and in the interleaved symmetric mode
|
||||
that the delay is not longer than half of the remote polling interval
|
||||
to detect missed packets */
|
||||
larger than the configured maximum, in both client modes that the server
|
||||
processing time is sane, and in interleaved symmetric mode that the
|
||||
measured delay and intervals between remote timestamps don't indicate
|
||||
a missed response */
|
||||
testA = delay - dispersion <= inst->max_delay && precision <= inst->max_delay &&
|
||||
!(inst->mode == MODE_CLIENT &&
|
||||
(response_time > MAX_SERVER_INTERVAL ||
|
||||
(interleaved_packet && inst->tx_count > MAX_CLIENT_INTERLEAVED_TX + 1))) &&
|
||||
!(inst->mode == MODE_CLIENT && response_time > MAX_SERVER_INTERVAL) &&
|
||||
!(inst->mode == MODE_ACTIVE && interleaved_packet &&
|
||||
delay > UTI_Log2ToDouble(message->poll - 1));
|
||||
(delay > 0.5 * prev_remote_poll_interval ||
|
||||
UTI_CompareNtp64(&message->receive_ts, &message->transmit_ts) <= 0 ||
|
||||
(inst->remote_poll <= inst->prev_local_poll &&
|
||||
UTI_DiffTimespecsToDouble(&remote_transmit, &prev_remote_transmit) >
|
||||
1.5 * prev_remote_poll_interval)));
|
||||
|
||||
/* Test B requires in the basic client mode that the ratio of the round
|
||||
trip delay to the minimum one currently in the stats data register is
|
||||
less than an administrator-defined value */
|
||||
testB = inst->max_delay_ratio <= 1.0 ||
|
||||
!(inst->mode == MODE_CLIENT && !interleaved_packet &&
|
||||
(delay - dispersion) / SST_MinRoundTripDelay(stats) > inst->max_delay_ratio);
|
||||
/* Test B requires in client mode that the ratio of the round trip delay
|
||||
to the minimum one currently in the stats data register is less than an
|
||||
administrator-defined value */
|
||||
testB = check_delay_ratio(inst, stats, &sample_time, delay);
|
||||
|
||||
/* Test C requires that the ratio of the increase in delay from the minimum
|
||||
one in the stats data register to the standard deviation of the offsets
|
||||
in the register is less than an administrator-defined value or the
|
||||
difference between measured offset and predicted offset is larger than
|
||||
the increase in delay */
|
||||
testC = SST_IsGoodSample(stats, -offset, delay, inst->max_delay_dev_ratio,
|
||||
LCL_GetMaxClockError(), &sample_time);
|
||||
testC = check_delay_dev_ratio(inst, stats, &sample_time, offset, delay);
|
||||
|
||||
/* Test D requires that the remote peer is not synchronised to us to
|
||||
prevent a synchronisation loop */
|
||||
@@ -1610,7 +1704,10 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
inst->remote_stratum = message->stratum != NTP_INVALID_STRATUM ?
|
||||
message->stratum : NTP_MAX_STRATUM;
|
||||
|
||||
inst->prev_local_poll = inst->local_poll;
|
||||
inst->prev_tx_count = inst->tx_count;
|
||||
inst->tx_count = 0;
|
||||
|
||||
SRC_UpdateReachability(inst->source, synced_packet);
|
||||
|
||||
if (good_packet) {
|
||||
|
||||
@@ -154,17 +154,25 @@ add_interface(CNF_HwTsInterface *conf_iface)
|
||||
ts_config.tx_type = HWTSTAMP_TX_ON;
|
||||
|
||||
switch (conf_iface->rxfilter) {
|
||||
case CNF_HWTS_RXFILTER_ANY:
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
|
||||
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL))
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
||||
else
|
||||
#endif
|
||||
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_ALL))
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
|
||||
else
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
break;
|
||||
case CNF_HWTS_RXFILTER_NONE:
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
break;
|
||||
case CNF_HWTS_RXFILTER_NTP:
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
|
||||
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL)) {
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
||||
break;
|
||||
}
|
||||
case CNF_HWTS_RXFILTER_NTP:
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
|
||||
break;
|
||||
#endif
|
||||
/* Fall through */
|
||||
default:
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
|
||||
break;
|
||||
@@ -203,7 +211,8 @@ add_interface(CNF_HwTsInterface *conf_iface)
|
||||
|
||||
iface->clock = HCL_CreateInstance(UTI_Log2ToDouble(MAX(conf_iface->minpoll, MIN_PHC_POLL)));
|
||||
|
||||
LOG(LOGS_INFO, "Enabled HW timestamping on %s", iface->name);
|
||||
LOG(LOGS_INFO, "Enabled HW timestamping %son %s",
|
||||
ts_config.rx_filter == HWTSTAMP_FILTER_NONE ? "(TX only) " : "", iface->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -512,14 +521,43 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
||||
len -= ihl + 8, msg += ihl + 8;
|
||||
#ifdef FEAT_IPV6
|
||||
} else if (len >= 48 && msg[0] >> 4 == 6) {
|
||||
/* IPv6 extension headers are not supported */
|
||||
if (msg[6] != 17)
|
||||
return 0;
|
||||
int eh_len, next_header = msg[6];
|
||||
|
||||
memcpy(&addr.in6.sin6_addr.s6_addr, msg + 24, 16);
|
||||
addr.in6.sin6_port = *(uint16_t *)(msg + 40 + 2);
|
||||
len -= 40, msg += 40;
|
||||
|
||||
/* Skip IPv6 extension headers if present */
|
||||
while (next_header != 17) {
|
||||
switch (next_header) {
|
||||
case 44: /* Fragment Header */
|
||||
/* Process only the first fragment */
|
||||
if (ntohs(*(uint16_t *)(msg + 2)) >> 3 != 0)
|
||||
return 0;
|
||||
eh_len = 8;
|
||||
break;
|
||||
case 0: /* Hop-by-Hop Options */
|
||||
case 43: /* Routing Header */
|
||||
case 60: /* Destination Options */
|
||||
case 135: /* Mobility Header */
|
||||
eh_len = 8 * (msg[1] + 1);
|
||||
break;
|
||||
case 51: /* Authentication Header */
|
||||
eh_len = 4 * (msg[1] + 2);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (eh_len < 8 || len < eh_len + 8)
|
||||
return 0;
|
||||
|
||||
next_header = msg[0];
|
||||
len -= eh_len, msg += eh_len;
|
||||
}
|
||||
|
||||
addr.in6.sin6_port = *(uint16_t *)(msg + 2);
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
len -= 48, msg += 48;
|
||||
len -= 8, msg += 8;
|
||||
#endif
|
||||
} else {
|
||||
return 0;
|
||||
|
||||
@@ -114,8 +114,10 @@ static const struct request_length request_lengths[] = {
|
||||
client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
|
||||
REQ_LENGTH_ENTRY(local, null), /* LOCAL2 */
|
||||
REQ_LENGTH_ENTRY(ntp_data, ntp_data), /* NTP_DATA */
|
||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SERVER2 */
|
||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_PEER2 */
|
||||
{ 0, 0 }, /* ADD_SERVER2 */
|
||||
{ 0, 0 }, /* ADD_PEER2 */
|
||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SERVER3 */
|
||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_PEER3 */
|
||||
};
|
||||
|
||||
static const uint16_t reply_lengths[] = {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Bryan Christianson 2015
|
||||
* Copyright (C) Miroslav Lichvar 2016
|
||||
* Copyright (C) Miroslav Lichvar 2017
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016
|
||||
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016-2017
|
||||
*
|
||||
* 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
|
||||
@@ -260,7 +260,7 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||
filter_init(&inst->filter, params->filter_length, params->max_dispersion);
|
||||
|
||||
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_options, NULL,
|
||||
params->min_samples, params->max_samples);
|
||||
params->min_samples, params->max_samples, 0.0, 0.0);
|
||||
|
||||
DEBUG_LOG("refclock %s refid=%s poll=%d dpoll=%d filter=%d",
|
||||
params->driver_name, UTI_RefidToString(inst->ref_id),
|
||||
|
||||
132
reference.c
132
reference.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2016
|
||||
* Copyright (C) Miroslav Lichvar 2009-2017
|
||||
*
|
||||
* 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
|
||||
@@ -156,7 +156,8 @@ handle_slew(struct timespec *raw,
|
||||
double delta;
|
||||
struct timespec now;
|
||||
|
||||
UTI_AdjustTimespec(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset);
|
||||
if (!UTI_IsZeroTimespec(&our_ref_time))
|
||||
UTI_AdjustTimespec(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset);
|
||||
|
||||
if (change_type == LCL_ChangeUnknownStep) {
|
||||
UTI_ZeroTimespec(&last_ref_update);
|
||||
@@ -225,7 +226,7 @@ REF_Initialise(void)
|
||||
}
|
||||
|
||||
logfileid = CNF_GetLogTracking() ? LOG_FileOpen("tracking",
|
||||
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset L Co Offset sd Rem. corr.")
|
||||
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset L Co Offset sd Rem. corr. Root delay Root disp. Max. error")
|
||||
: -1;
|
||||
|
||||
max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
|
||||
@@ -267,6 +268,7 @@ REF_Initialise(void)
|
||||
fb_drift_timeout_id = 0;
|
||||
}
|
||||
|
||||
UTI_ZeroTimespec(&our_ref_time);
|
||||
UTI_ZeroTimespec(&last_ref_update);
|
||||
last_ref_update_interval = 0.0;
|
||||
|
||||
@@ -607,7 +609,14 @@ is_offset_ok(double offset)
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
is_leap_second_day(struct tm *stm) {
|
||||
is_leap_second_day(time_t when)
|
||||
{
|
||||
struct tm *stm;
|
||||
|
||||
stm = gmtime(&when);
|
||||
if (!stm)
|
||||
return 0;
|
||||
|
||||
/* Allow leap second only on the last day of June and December */
|
||||
return (stm->tm_mon == 5 && stm->tm_mday == 30) ||
|
||||
(stm->tm_mon == 11 && stm->tm_mday == 31);
|
||||
@@ -622,7 +631,7 @@ get_tz_leap(time_t when, int *tai_offset)
|
||||
static NTP_Leap tz_leap;
|
||||
static int tz_tai_offset;
|
||||
|
||||
struct tm stm;
|
||||
struct tm stm, *tm;
|
||||
time_t t;
|
||||
char *tz_env, tz_orig[128];
|
||||
|
||||
@@ -637,7 +646,11 @@ get_tz_leap(time_t when, int *tai_offset)
|
||||
tz_leap = LEAP_Normal;
|
||||
tz_tai_offset = 0;
|
||||
|
||||
stm = *gmtime(&when);
|
||||
tm = gmtime(&when);
|
||||
if (!tm)
|
||||
return tz_leap;
|
||||
|
||||
stm = *tm;
|
||||
|
||||
/* Temporarily switch to the timezone containing leap seconds */
|
||||
tz_env = getenv("TZ");
|
||||
@@ -782,7 +795,7 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
|
||||
if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) {
|
||||
/* Check that leap second is allowed today */
|
||||
|
||||
if (is_leap_second_day(gmtime(&now))) {
|
||||
if (is_leap_second_day(now)) {
|
||||
if (leap == LEAP_InsertSecond) {
|
||||
leap_sec = 1;
|
||||
} else {
|
||||
@@ -820,18 +833,43 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
get_root_dispersion(struct timespec *ts)
|
||||
{
|
||||
if (UTI_IsZeroTimespec(&our_ref_time))
|
||||
return 1.0;
|
||||
|
||||
return our_root_dispersion +
|
||||
fabs(UTI_DiffTimespecsToDouble(ts, &our_ref_time)) *
|
||||
(our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError());
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
write_log(struct timespec *ref_time, char *ref, int stratum, NTP_Leap leap,
|
||||
double freq, double skew, double offset, int combined_sources,
|
||||
double offset_sd, double uncorrected_offset)
|
||||
write_log(struct timespec *now, int combined_sources, double freq,
|
||||
double offset, double offset_sd, double uncorrected_offset,
|
||||
double orig_root_distance)
|
||||
{
|
||||
const char leap_codes[4] = {'N', '+', '-', '?'};
|
||||
if (logfileid != -1) {
|
||||
LOG_FileWrite(logfileid, "%s %-15s %2d %10.3f %10.3f %10.3e %1c %2d %10.3e %10.3e",
|
||||
UTI_TimeToLogForm(ref_time->tv_sec), ref, stratum, freq, skew,
|
||||
offset, leap_codes[leap], combined_sources, offset_sd,
|
||||
uncorrected_offset);
|
||||
}
|
||||
double root_dispersion, max_error;
|
||||
static double last_sys_offset = 0.0;
|
||||
|
||||
if (logfileid == -1)
|
||||
return;
|
||||
|
||||
max_error = orig_root_distance + fabs(last_sys_offset);
|
||||
root_dispersion = get_root_dispersion(now);
|
||||
last_sys_offset = offset - uncorrected_offset;
|
||||
|
||||
LOG_FileWrite(logfileid,
|
||||
"%s %-15s %2d %10.3f %10.3f %10.3e %1c %2d %10.3e %10.3e %10.3e %10.3e %10.3e",
|
||||
UTI_TimeToLogForm(now->tv_sec),
|
||||
our_ref_ip.family != IPADDR_UNSPEC ?
|
||||
UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
|
||||
our_stratum, freq, 1.0e6 * our_skew, offset,
|
||||
leap_codes[our_leap_status], combined_sources, offset_sd,
|
||||
uncorrected_offset, our_root_delay, root_dispersion, max_error);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -915,8 +953,7 @@ REF_SetReference(int stratum,
|
||||
double our_frequency;
|
||||
double abs_freq_ppm;
|
||||
double update_interval;
|
||||
double elapsed;
|
||||
double correction_rate;
|
||||
double elapsed, correction_rate, orig_root_distance;
|
||||
double uncorrected_offset, accumulate_offset, step_offset;
|
||||
struct timespec now, raw_now;
|
||||
NTP_int64 ref_fuzz;
|
||||
@@ -929,28 +966,10 @@ REF_SetReference(int stratum,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Guard against dividing by zero */
|
||||
if (skew < MIN_SKEW)
|
||||
/* Guard against dividing by zero and NaN */
|
||||
if (!(skew > MIN_SKEW))
|
||||
skew = MIN_SKEW;
|
||||
|
||||
/* If we get a serious rounding error in the source stats regression
|
||||
processing, there is a remote chance that the skew argument is a
|
||||
'not a number'. If such a quantity gets propagated into the
|
||||
machine's kernel clock variables, nasty things will happen ..
|
||||
|
||||
To guard against this we need to check whether the skew argument
|
||||
is a reasonable real number. I don't think isnan, isinf etc are
|
||||
platform independent, so the following algorithm is used. */
|
||||
|
||||
{
|
||||
double t;
|
||||
t = (skew + skew) / skew; /* Skew shouldn't be zero either */
|
||||
if ((t < 1.9) || (t > 2.1)) {
|
||||
LOG(LOGS_WARN, "Bogus skew value encountered");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LCL_ReadRawTime(&raw_now);
|
||||
LCL_GetOffsetCorrection(&raw_now, &uncorrected_offset, NULL);
|
||||
UTI_AddDoubleToTimespec(&raw_now, uncorrected_offset, &now);
|
||||
@@ -961,6 +980,8 @@ REF_SetReference(int stratum,
|
||||
if (!is_offset_ok(our_offset))
|
||||
return;
|
||||
|
||||
orig_root_distance = our_root_delay / 2.0 + get_root_dispersion(&now);
|
||||
|
||||
are_we_synchronised = leap != LEAP_Unsynchronised ? 1 : 0;
|
||||
our_stratum = stratum + 1;
|
||||
our_ref_id = ref_id;
|
||||
@@ -1071,16 +1092,8 @@ REF_SetReference(int stratum,
|
||||
|
||||
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
|
||||
|
||||
write_log(&now,
|
||||
our_ref_ip.family != IPADDR_UNSPEC ? UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
|
||||
our_stratum,
|
||||
our_leap_status,
|
||||
abs_freq_ppm,
|
||||
1.0e6*our_skew,
|
||||
our_offset,
|
||||
combined_sources,
|
||||
offset_sd,
|
||||
uncorrected_offset);
|
||||
write_log(&now, combined_sources, abs_freq_ppm, our_offset, offset_sd,
|
||||
uncorrected_offset, orig_root_distance);
|
||||
|
||||
if (drift_file) {
|
||||
/* Update drift file at most once per hour */
|
||||
@@ -1092,7 +1105,7 @@ REF_SetReference(int stratum,
|
||||
}
|
||||
|
||||
/* Update fallback drifts */
|
||||
if (fb_drifts) {
|
||||
if (fb_drifts && are_we_synchronised) {
|
||||
update_fb_drifts(abs_freq_ppm, update_interval);
|
||||
schedule_fb_drift(&now);
|
||||
}
|
||||
@@ -1154,20 +1167,15 @@ REF_SetUnsynchronised(void)
|
||||
}
|
||||
|
||||
update_leap_status(LEAP_Unsynchronised, 0, 0);
|
||||
our_ref_ip.family = IPADDR_INET4;
|
||||
our_ref_ip.addr.in4 = 0;
|
||||
our_stratum = 0;
|
||||
are_we_synchronised = 0;
|
||||
|
||||
LCL_SetSyncStatus(0, 0.0, 0.0);
|
||||
|
||||
write_log(&now,
|
||||
"0.0.0.0",
|
||||
0,
|
||||
our_leap_status,
|
||||
LCL_ReadAbsoluteFrequency(),
|
||||
1.0e6*our_skew,
|
||||
0.0,
|
||||
0,
|
||||
0.0,
|
||||
uncorrected_offset);
|
||||
write_log(&now, 0, LCL_ReadAbsoluteFrequency(), 0.0, 0.0, uncorrected_offset,
|
||||
our_root_delay / 2.0 + get_root_dispersion(&now));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1185,14 +1193,12 @@ REF_GetReferenceParams
|
||||
double *root_dispersion
|
||||
)
|
||||
{
|
||||
double elapsed, dispersion;
|
||||
double dispersion;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
if (are_we_synchronised) {
|
||||
elapsed = UTI_DiffTimespecsToDouble(local_time, &our_ref_time);
|
||||
dispersion = our_root_dispersion +
|
||||
(our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError()) * elapsed;
|
||||
dispersion = get_root_dispersion(local_time);
|
||||
} else {
|
||||
dispersion = 0.0;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2011, 2016
|
||||
* Copyright (C) Miroslav Lichvar 2011, 2016-2017
|
||||
*
|
||||
* 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
|
||||
|
||||
3
sched.h
3
sched.h
@@ -34,7 +34,8 @@ typedef unsigned int SCH_TimeoutID;
|
||||
|
||||
typedef enum {
|
||||
SCH_ReservedTimeoutValue = 0,
|
||||
SCH_NtpSamplingClass,
|
||||
SCH_NtpClientClass,
|
||||
SCH_NtpPeerClass,
|
||||
SCH_NtpBroadcastClass,
|
||||
SCH_NumberOfClasses /* needs to be last */
|
||||
} SCH_TimeoutClass;
|
||||
|
||||
5
smooth.c
5
smooth.c
@@ -246,7 +246,8 @@ handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
|
||||
update_smoothing(cooked, doffset, dfreq);
|
||||
}
|
||||
|
||||
UTI_AdjustTimespec(&last_update, cooked, &last_update, &delta, dfreq, doffset);
|
||||
if (!UTI_IsZeroTimespec(&last_update))
|
||||
UTI_AdjustTimespec(&last_update, cooked, &last_update, &delta, dfreq, doffset);
|
||||
}
|
||||
|
||||
void SMT_Initialise(void)
|
||||
@@ -264,6 +265,8 @@ void SMT_Initialise(void)
|
||||
max_freq *= 1e-6;
|
||||
max_wander *= 1e-6;
|
||||
|
||||
UTI_ZeroTimespec(&last_update);
|
||||
|
||||
LCL_AddParameterChangeHandler(handle_slew, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +213,9 @@ void SRC_Finalise(void)
|
||||
/* Function to create a new instance. This would be called by one of
|
||||
the individual source-type instance creation routines. */
|
||||
|
||||
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options, IPAddr *addr, int min_samples, int max_samples)
|
||||
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options,
|
||||
IPAddr *addr, int min_samples, int max_samples,
|
||||
double min_delay, double asymmetry)
|
||||
{
|
||||
SRC_Instance result;
|
||||
|
||||
@@ -225,7 +227,8 @@ SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_optio
|
||||
max_samples = CNF_GetMaxSamples();
|
||||
|
||||
result = MallocNew(struct SRC_Instance_Record);
|
||||
result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples);
|
||||
result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples,
|
||||
min_delay, asymmetry);
|
||||
|
||||
if (n_sources == max_n_sources) {
|
||||
/* Reallocate memory */
|
||||
|
||||
@@ -59,7 +59,9 @@ typedef enum {
|
||||
/* Function to create a new instance. This would be called by one of
|
||||
the individual source-type instance creation routines. */
|
||||
|
||||
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options, IPAddr *addr, int min_samples, int max_samples);
|
||||
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options,
|
||||
IPAddr *addr, int min_samples, int max_samples,
|
||||
double min_delay, double asymmetry);
|
||||
|
||||
/* Function to get rid of a source when it is being unconfigured.
|
||||
This may cause the current reference source to be reselected, if this
|
||||
|
||||
124
sourcestats.c
124
sourcestats.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2011-2014, 2016
|
||||
* Copyright (C) Miroslav Lichvar 2011-2014, 2016-2017
|
||||
*
|
||||
* 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
|
||||
@@ -82,6 +82,12 @@ struct SST_Stats_Record {
|
||||
int min_samples;
|
||||
int max_samples;
|
||||
|
||||
/* User defined minimum delay */
|
||||
double fixed_min_delay;
|
||||
|
||||
/* User defined asymmetry of network jitter */
|
||||
double fixed_asymmetry;
|
||||
|
||||
/* Number of samples currently stored. The samples are stored in circular
|
||||
buffer. */
|
||||
int n_samples;
|
||||
@@ -197,13 +203,16 @@ SST_Finalise(void)
|
||||
/* This function creates a new instance of the statistics handler */
|
||||
|
||||
SST_Stats
|
||||
SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples)
|
||||
SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples,
|
||||
double min_delay, double asymmetry)
|
||||
{
|
||||
SST_Stats inst;
|
||||
inst = MallocNew(struct SST_Stats_Record);
|
||||
|
||||
inst->min_samples = min_samples;
|
||||
inst->max_samples = max_samples;
|
||||
inst->fixed_min_delay = min_delay;
|
||||
inst->fixed_asymmetry = asymmetry;
|
||||
|
||||
SST_SetRefid(inst, refid, addr);
|
||||
SST_ResetInstance(inst);
|
||||
@@ -310,6 +319,9 @@ SST_AccumulateSample(SST_Stats inst, struct timespec *sample_time,
|
||||
inst->root_dispersions[m] = root_dispersion;
|
||||
inst->strata[m] = stratum;
|
||||
|
||||
if (inst->peer_delays[n] < inst->fixed_min_delay)
|
||||
inst->peer_delays[n] = 2.0 * inst->fixed_min_delay - inst->peer_delays[n];
|
||||
|
||||
if (!inst->n_samples || inst->peer_delays[n] < inst->peer_delays[inst->min_delay_sample])
|
||||
inst->min_delay_sample = n;
|
||||
|
||||
@@ -415,45 +427,63 @@ find_min_delay_sample(SST_Stats inst)
|
||||
minimum network delay. This can significantly improve the accuracy and
|
||||
stability of the estimated offset and frequency. */
|
||||
|
||||
static int
|
||||
estimate_asymmetry(double *times_back, double *offsets, double *delays, int n,
|
||||
double *asymmetry, int *asymmetry_run)
|
||||
{
|
||||
double a;
|
||||
|
||||
/* Reset the counter when the regression fails or the sign changes */
|
||||
if (!RGR_MultipleRegress(times_back, delays, offsets, n, &a) ||
|
||||
a * *asymmetry_run < 0.0) {
|
||||
*asymmetry = 0;
|
||||
*asymmetry_run = 0.0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (a <= -MIN_ASYMMETRY && *asymmetry_run > -MAX_ASYMMETRY_RUN)
|
||||
(*asymmetry_run)--;
|
||||
else if (a >= MIN_ASYMMETRY && *asymmetry_run < MAX_ASYMMETRY_RUN)
|
||||
(*asymmetry_run)++;
|
||||
|
||||
if (abs(*asymmetry_run) < MIN_ASYMMETRY_RUN)
|
||||
return 0;
|
||||
|
||||
*asymmetry = CLAMP(-MAX_ASYMMETRY, a, MAX_ASYMMETRY);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
correct_asymmetry(SST_Stats inst, double *times_back, double *offsets)
|
||||
{
|
||||
double asymmetry, delays[MAX_SAMPLES * REGRESS_RUNS_RATIO];
|
||||
double min_delay, delays[MAX_SAMPLES * REGRESS_RUNS_RATIO];
|
||||
int i, n;
|
||||
|
||||
/* Don't try to estimate the asymmetry with reference clocks */
|
||||
if (!inst->ip_addr)
|
||||
/* Check if the asymmetry was not specified to be zero */
|
||||
if (inst->fixed_asymmetry == 0.0)
|
||||
return;
|
||||
|
||||
min_delay = SST_MinRoundTripDelay(inst);
|
||||
n = inst->runs_samples + inst->n_samples;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
delays[i] = inst->peer_delays[get_runsbuf_index(inst, i - inst->runs_samples)] -
|
||||
inst->peer_delays[inst->min_delay_sample];
|
||||
min_delay;
|
||||
|
||||
/* Reset the counter when the regression fails or the sign changes */
|
||||
if (!RGR_MultipleRegress(times_back, delays, offsets, n, &asymmetry) ||
|
||||
asymmetry * inst->asymmetry_run < 0.0) {
|
||||
inst->asymmetry_run = 0;
|
||||
inst->asymmetry = 0.0;
|
||||
return;
|
||||
if (fabs(inst->fixed_asymmetry) <= MAX_ASYMMETRY) {
|
||||
inst->asymmetry = inst->fixed_asymmetry;
|
||||
} else {
|
||||
if (!estimate_asymmetry(times_back, offsets, delays, n,
|
||||
&inst->asymmetry, &inst->asymmetry_run))
|
||||
return;
|
||||
}
|
||||
|
||||
asymmetry = CLAMP(-MAX_ASYMMETRY, asymmetry, MAX_ASYMMETRY);
|
||||
|
||||
if (asymmetry <= -MIN_ASYMMETRY && inst->asymmetry_run > -MAX_ASYMMETRY_RUN)
|
||||
inst->asymmetry_run--;
|
||||
else if (asymmetry >= MIN_ASYMMETRY && inst->asymmetry_run < MAX_ASYMMETRY_RUN)
|
||||
inst->asymmetry_run++;
|
||||
|
||||
if (abs(inst->asymmetry_run) < MIN_ASYMMETRY_RUN)
|
||||
return;
|
||||
|
||||
/* Correct the offsets */
|
||||
for (i = 0; i < n; i++)
|
||||
offsets[i] -= asymmetry * delays[i];
|
||||
|
||||
inst->asymmetry = asymmetry;
|
||||
offsets[i] -= inst->asymmetry * delays[i];
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -771,47 +801,33 @@ SST_PredictOffset(SST_Stats inst, struct timespec *when)
|
||||
double
|
||||
SST_MinRoundTripDelay(SST_Stats inst)
|
||||
{
|
||||
if (inst->fixed_min_delay > 0.0)
|
||||
return inst->fixed_min_delay;
|
||||
|
||||
if (!inst->n_samples)
|
||||
return DBL_MAX;
|
||||
|
||||
return inst->peer_delays[inst->min_delay_sample];
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SST_IsGoodSample(SST_Stats inst, double offset, double delay,
|
||||
double max_delay_dev_ratio, double clock_error, struct timespec *when)
|
||||
SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
|
||||
double *last_sample_ago, double *predicted_offset,
|
||||
double *min_delay, double *skew, double *std_dev)
|
||||
{
|
||||
double elapsed, allowed_increase, delay_increase;
|
||||
|
||||
if (inst->n_samples < 6)
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
elapsed = UTI_DiffTimespecsToDouble(when, &inst->offset_time);
|
||||
*last_sample_ago = UTI_DiffTimespecsToDouble(sample_time, &inst->offset_time);
|
||||
*predicted_offset = inst->estimated_offset +
|
||||
*last_sample_ago * inst->estimated_frequency;
|
||||
*min_delay = SST_MinRoundTripDelay(inst);
|
||||
*skew = inst->skew;
|
||||
*std_dev = inst->std_dev;
|
||||
|
||||
/* Require that the ratio of the increase in delay from the minimum to the
|
||||
standard deviation is less than max_delay_dev_ratio. In the allowed
|
||||
increase in delay include also skew and clock_error. */
|
||||
|
||||
allowed_increase = inst->std_dev * max_delay_dev_ratio +
|
||||
elapsed * (inst->skew + clock_error);
|
||||
delay_increase = (delay - SST_MinRoundTripDelay(inst)) / 2.0;
|
||||
|
||||
if (delay_increase < allowed_increase)
|
||||
return 1;
|
||||
|
||||
offset -= inst->estimated_offset + elapsed * inst->estimated_frequency;
|
||||
|
||||
/* Before we decide to drop the sample, make sure the difference between
|
||||
measured offset and predicted offset is not significantly larger than
|
||||
the increase in delay */
|
||||
if (fabs(offset) - delay_increase > allowed_increase)
|
||||
return 1;
|
||||
|
||||
DEBUG_LOG("Bad sample: offset=%f delay=%f incr_delay=%f allowed=%f",
|
||||
offset, delay, delay_increase, allowed_increase);
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -38,7 +38,9 @@ extern void SST_Initialise(void);
|
||||
extern void SST_Finalise(void);
|
||||
|
||||
/* This function creates a new instance of the statistics handler */
|
||||
extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples);
|
||||
extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr,
|
||||
int min_samples, int max_samples,
|
||||
double min_delay, double asymmetry);
|
||||
|
||||
/* This function deletes an instance of the statistics handler. */
|
||||
extern void SST_DeleteInstance(SST_Stats inst);
|
||||
@@ -124,10 +126,10 @@ extern double SST_PredictOffset(SST_Stats inst, struct timespec *when);
|
||||
/* Find the minimum round trip delay in the register */
|
||||
extern double SST_MinRoundTripDelay(SST_Stats inst);
|
||||
|
||||
/* This routine determines if a new sample is good enough that it should be
|
||||
accumulated */
|
||||
extern int SST_IsGoodSample(SST_Stats inst, double offset, double delay,
|
||||
double max_delay_dev_ratio, double clock_error, struct timespec *when);
|
||||
/* Get data needed for testing NTP delay */
|
||||
extern int SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
|
||||
double *last_sample_ago, double *predicted_offset,
|
||||
double *min_delay, double *skew, double *std_dev);
|
||||
|
||||
extern void SST_SaveToFile(SST_Stats inst, FILE *out);
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@ typedef struct {
|
||||
double max_delay;
|
||||
double max_delay_ratio;
|
||||
double max_delay_dev_ratio;
|
||||
double min_delay;
|
||||
double asymmetry;
|
||||
double offset;
|
||||
} SourceParameters;
|
||||
|
||||
@@ -63,6 +65,7 @@ typedef struct {
|
||||
#define SRC_DEFAULT_MAXSOURCES 4
|
||||
#define SRC_DEFAULT_MINSAMPLES (-1)
|
||||
#define SRC_DEFAULT_MAXSAMPLES (-1)
|
||||
#define SRC_DEFAULT_ASYMMETRY 1.0
|
||||
#define INACTIVE_AUTHKEY 0
|
||||
|
||||
/* Flags for source selection */
|
||||
|
||||
14
sys_linux.c
14
sys_linux.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) John G. Hasler 2009
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2016
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2017
|
||||
*
|
||||
* 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
|
||||
@@ -517,7 +517,10 @@ SYS_Linux_EnableSystemCallFilter(int level)
|
||||
const static unsigned long ioctls[] = {
|
||||
FIONREAD, TCGETS,
|
||||
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||
PTP_EXTTS_REQUEST, PTP_PIN_SETFUNC, PTP_SYS_OFFSET,
|
||||
PTP_EXTTS_REQUEST, PTP_SYS_OFFSET,
|
||||
#ifdef PTP_PIN_SETFUNC
|
||||
PTP_PIN_SETFUNC,
|
||||
#endif
|
||||
#ifdef PTP_SYS_OFFSET_PRECISE
|
||||
PTP_SYS_OFFSET_PRECISE,
|
||||
#endif
|
||||
@@ -822,8 +825,9 @@ int
|
||||
SYS_Linux_SetPHCExtTimestamping(int fd, int pin, int channel,
|
||||
int rising, int falling, int enable)
|
||||
{
|
||||
struct ptp_pin_desc pin_desc;
|
||||
struct ptp_extts_request extts_req;
|
||||
#ifdef PTP_PIN_SETFUNC
|
||||
struct ptp_pin_desc pin_desc;
|
||||
|
||||
memset(&pin_desc, 0, sizeof (pin_desc));
|
||||
pin_desc.index = pin;
|
||||
@@ -834,6 +838,10 @@ SYS_Linux_SetPHCExtTimestamping(int fd, int pin, int channel,
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "PTP_PIN_SETFUNC", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
DEBUG_LOG("Missing PTP_PIN_SETFUNC");
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
memset(&extts_req, 0, sizeof (extts_req));
|
||||
extts_req.index = channel;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2001
|
||||
* Copyright (C) J. Hannken-Illjes 2001
|
||||
* Copyright (C) Bryan Christianson 2015
|
||||
* Copyright (C) Bryan Christianson 2015, 2017
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -84,9 +84,18 @@ get_offset_correction(struct timespec *raw,
|
||||
{
|
||||
struct timeval remadj;
|
||||
double adjustment_remaining;
|
||||
#ifdef MACOSX
|
||||
struct timeval tv = {0, 0};
|
||||
|
||||
if (PRV_AdjustTime(&tv, &remadj) < 0)
|
||||
LOG_FATAL("adjtime() failed");
|
||||
|
||||
if (PRV_AdjustTime(&remadj, NULL) < 0)
|
||||
LOG_FATAL("adjtime() failed");
|
||||
#else
|
||||
if (PRV_AdjustTime(NULL, &remadj) < 0)
|
||||
LOG_FATAL("adjtime() failed");
|
||||
#endif
|
||||
|
||||
adjustment_remaining = UTI_TimevalToDouble(&remadj);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2015
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2015, 2017
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -18,7 +18,7 @@ check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
for client_server_options in "maxpoll 6 maxdelay 2e-5" "maxpoll 6 maxdelayratio 1.001"; do
|
||||
for client_server_options in "maxpoll 6 maxdelay 2e-5"; do
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_packet_interval || test_fail
|
||||
|
||||
@@ -17,6 +17,7 @@ max_sync_time=500
|
||||
base_delay="(+ 1e-4 (* -1 (equal 0.1 from 2) (equal 0.1 to 1)))"
|
||||
|
||||
client_lpeer_options="xleave minpoll 5 maxpoll 5"
|
||||
client_rpeer_options="minpoll 5 maxpoll 5"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
|
||||
27
test/simulation/123-mindelay
Executable file
27
test/simulation/123-mindelay
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
. ./test.common
|
||||
|
||||
test_start "mindelay and asymmetry options"
|
||||
|
||||
jitter_asymmetry=0.499
|
||||
time_rms_limit=1e-6
|
||||
time_freq_limit=1e-9
|
||||
wander=1e-12
|
||||
|
||||
for client_server_options in "mindelay 2e-4 asymmetry 0.499"; do
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
done
|
||||
|
||||
for client_server_options in "mindelay 1e-4 asymmetry 0.499" "mindelay 2e-4 asymmetry 0.0"; do
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync && test_fail
|
||||
done
|
||||
|
||||
test_pass
|
||||
@@ -26,14 +26,14 @@ test_unit(void)
|
||||
{
|
||||
struct timespec start_hw_ts, start_local_ts, hw_ts, local_ts, ts;
|
||||
HCL_Instance clock;
|
||||
double freq, jitter, interval, d;
|
||||
int i, j;
|
||||
double freq, jitter, interval, dj, sum;
|
||||
int i, j, count;
|
||||
|
||||
LCL_Initialise();
|
||||
|
||||
clock = HCL_CreateInstance(1.0);
|
||||
|
||||
for (i = 0; i < 2000; i++) {
|
||||
for (i = 0, count = 0, sum = 0.0; i < 2000; i++) {
|
||||
UTI_ZeroTimespec(&start_hw_ts);
|
||||
UTI_ZeroTimespec(&start_local_ts);
|
||||
UTI_AddDoubleToTimespec(&start_hw_ts, TST_GetRandomDouble(0.0, 1e9), &start_hw_ts);
|
||||
@@ -49,17 +49,23 @@ test_unit(void)
|
||||
clock->valid_coefs = 0;
|
||||
|
||||
for (j = 0; j < 100; j++) {
|
||||
UTI_AddDoubleToTimespec(&start_hw_ts, j * interval * freq + TST_GetRandomDouble(-jitter, jitter), &hw_ts);
|
||||
UTI_AddDoubleToTimespec(&start_hw_ts, j * interval * freq, &hw_ts);
|
||||
UTI_AddDoubleToTimespec(&start_local_ts, j * interval, &local_ts);
|
||||
if (HCL_CookTime(clock, &hw_ts, &ts, NULL)) {
|
||||
d = UTI_DiffTimespecsToDouble(&ts, &local_ts);
|
||||
TEST_CHECK(fabs(d) <= 5.0 * jitter);
|
||||
dj = fabs(UTI_DiffTimespecsToDouble(&ts, &local_ts) / jitter);
|
||||
DEBUG_LOG("delta/jitter %f", dj);
|
||||
if (clock->n_samples >= 8)
|
||||
sum += dj, count++;
|
||||
TEST_CHECK(clock->n_samples < 4 || dj <= 4.0);
|
||||
TEST_CHECK(clock->n_samples < 8 || dj <= 3.0);
|
||||
}
|
||||
|
||||
UTI_AddDoubleToTimespec(&start_hw_ts, j * interval * freq + TST_GetRandomDouble(-jitter, jitter), &hw_ts);
|
||||
|
||||
if (HCL_NeedsNewSample(clock, &local_ts))
|
||||
HCL_AccumulateSample(clock, &hw_ts, &local_ts, 2.0 * jitter);
|
||||
|
||||
TEST_CHECK(j < 20 || clock->valid_coefs);
|
||||
TEST_CHECK(clock->valid_coefs || clock->n_samples < 2);
|
||||
|
||||
if (!clock->valid_coefs)
|
||||
continue;
|
||||
@@ -68,6 +74,8 @@ test_unit(void)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CHECK(sum / count < 0.4);
|
||||
|
||||
HCL_DestroyInstance(clock);
|
||||
|
||||
LCL_Finalise();
|
||||
|
||||
@@ -134,8 +134,8 @@ test_unit(void)
|
||||
UTI_GetRandomBytes(&key, sizeof (key));
|
||||
if (KEY_KeyKnown(key))
|
||||
continue;
|
||||
TEST_CHECK(!KEY_GenerateAuth(j, data, data_len, auth, sizeof (auth)));
|
||||
TEST_CHECK(!KEY_CheckAuth(j, data, data_len, auth, auth_len, auth_len));
|
||||
TEST_CHECK(!KEY_GenerateAuth(key, data, data_len, auth, sizeof (auth)));
|
||||
TEST_CHECK(!KEY_CheckAuth(key, data, data_len, auth, auth_len, auth_len));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +251,8 @@ test_unit(void)
|
||||
for (j = 0; j < 50; j++) {
|
||||
DEBUG_LOG("iteration %d, %d", i, j);
|
||||
|
||||
interleaved = random() % 2;
|
||||
interleaved = random() % 2 && (inst->mode != MODE_CLIENT ||
|
||||
inst->tx_count < MAX_CLIENT_INTERLEAVED_TX);
|
||||
authenticated = random() % 2;
|
||||
valid = (!interleaved || (source.params.interleaved && has_updated)) &&
|
||||
(!source.params.authkey || authenticated);
|
||||
|
||||
@@ -53,7 +53,8 @@ test_unit(void)
|
||||
|
||||
DEBUG_LOG("added source %d options %d", j, sel_options);
|
||||
srcs[j] = SRC_CreateNewInstance(UTI_IPToRefid(&addr), SRC_NTP, sel_options, &addr,
|
||||
SRC_DEFAULT_MINSAMPLES, SRC_DEFAULT_MAXSAMPLES);
|
||||
SRC_DEFAULT_MINSAMPLES, SRC_DEFAULT_MAXSAMPLES,
|
||||
0.0, 1.0);
|
||||
SRC_UpdateReachability(srcs[j], 1);
|
||||
|
||||
samples = (i + j) % 5 + 3;
|
||||
|
||||
15
util.c
15
util.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2012-2016
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2012-2017
|
||||
*
|
||||
* 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
|
||||
@@ -610,13 +610,17 @@ UTI_SockaddrFamilyToString(int family)
|
||||
char *
|
||||
UTI_TimeToLogForm(time_t t)
|
||||
{
|
||||
struct tm stm;
|
||||
struct tm *stm;
|
||||
char *result;
|
||||
|
||||
result = NEXT_BUFFER;
|
||||
|
||||
stm = *gmtime(&t);
|
||||
strftime(result, BUFFER_LENGTH, "%Y-%m-%d %H:%M:%S", &stm);
|
||||
stm = gmtime(&t);
|
||||
|
||||
if (stm)
|
||||
strftime(result, BUFFER_LENGTH, "%Y-%m-%d %H:%M:%S", stm);
|
||||
else
|
||||
snprintf(result, BUFFER_LENGTH, "INVALID INVALID ");
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -641,6 +645,7 @@ UTI_GetNtp64Fuzz(NTP_int64 *ts, int precision)
|
||||
int start, bits;
|
||||
|
||||
assert(precision >= -32 && precision <= 32);
|
||||
assert(sizeof (*ts) == 8);
|
||||
|
||||
start = sizeof (*ts) - (precision + 32 + 7) / 8;
|
||||
ts->hi = ts->lo = 0;
|
||||
@@ -855,7 +860,7 @@ UTI_TimespecNetworkToHost(Timespec *src, struct timespec *dest)
|
||||
#endif
|
||||
|
||||
nsec = ntohl(src->tv_nsec);
|
||||
dest->tv_nsec = CLAMP(0U, nsec, 999999999U);
|
||||
dest->tv_nsec = MIN(nsec, 999999999U);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
Reference in New Issue
Block a user