Compare commits

...

50 Commits

Author SHA1 Message Date
Miroslav Lichvar
b8d546a0d1 examples: add leapsectz to configuration examples 2017-09-15 08:32:09 +02:00
Miroslav Lichvar
04e6474b75 reference: check for gmtime() error
Although gmtime() is expected to convert any time of the system clock at
least in the next few NTP eras, a correct code should always check the
returned value and this shouldn't be a fatal error in handling of leap
seconds.
2017-09-15 08:32:08 +02:00
Vincent Blut
eb51c500e8 doc: fix typo in chrony.conf man page 2017-09-11 11:21:13 +02:00
Miroslav Lichvar
6f8fba9a3f conf: check if GLOB_NOMAGIC is defined
This option is not supported by musl and possibly other libc
implementations.
2017-09-01 11:32:16 +02:00
Miroslav Lichvar
750afc30f2 test: fix keys unit test 2017-09-01 11:28:55 +02:00
Miroslav Lichvar
e0e6ec0d84 doc: update NEWS 2017-08-29 14:17:35 +02:00
Miroslav Lichvar
c9f50fc686 update copyright years 2017-08-28 14:38:23 +02:00
Miroslav Lichvar
83c26b458b doc: fix spelling
Don't mix UK and US spelling.
2017-08-28 14:38:19 +02:00
Miroslav Lichvar
b711873f45 test: add 123-mindelay test 2017-08-28 14:27:14 +02:00
Miroslav Lichvar
c68ca40ce4 ntp: improve maxdelayratio test
Similarly to the maxdelaydevratio test, include in the maximum delay
dispersion which accumulated in the interval since the last sample.
Also, enable the test for symmetric associations.
2017-08-28 14:27:14 +02:00
Miroslav Lichvar
51fe80ad95 sourcestats: move maxdelaydevratio test to ntp_core
Instead of giving NTP-specific data to sourcestats in order to perform
the test, provide a function to get all data needed for the test in
ntp_core. While at it, improve the naming of variables.
2017-08-28 14:27:14 +02:00
Miroslav Lichvar
7ffee73524 memory: check for overflow when (re)allocating array
When (re)allocating an array with very large number of elements using
the MallocArray or ReallocArray macros, the calculated size of the array
could overflow size_t and less memory would be allocated than requested.

Add new functions for (re)allocating arrays that check the size and use
them in the MallocArray and ReallocArray macros.

This couldn't be exploited, because all arrays that can grow with cmdmon
or NTP requests already have their size checked before allocation, or
they are much smaller than memory allocated for structures to which they
are related (i.e. ntp_core and sourcestats instances), so a memory
allocation would fail before their size could overflow.

This issue was found in an audit performed by Cure53 and sponsored by
Mozilla.
2017-08-28 14:27:14 +02:00
Miroslav Lichvar
f40b0024bd util: check for gmtime() error
Fix the UTI_TimeToLogForm() function to check if gmtime() didn't fail.
This caused chronyc to crash due to dereferencing a NULL pointer when
a response to the "manual list" request contained time which gmtime()
could not convert to broken-down representation.

This issue was found in an audit performed by Cure53 and sponsored by
Mozilla.
2017-08-28 14:27:14 +02:00
Miroslav Lichvar
a06c9909a6 conf: use enum for RX filter 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
aee42fada8 ntp: allow TX-only HW timestamping by default
If no rxfilter is specified in the hwtimestamp directive and the NIC
doesn't support the all or ntp filter, enable TX-only HW timestamping
with the none filter.
2017-08-23 15:01:30 +02:00
Miroslav Lichvar
3e93068c43 hwclock: improve debug message 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
36291b707b hwclock: check if estimated frequency is sane 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
6dad2c24bf hwclock: drop all samples on reset
On some HW it seems it's possible to get an occasional bad reading of
the PHC (with normal delay), or in a worse case the clock can step due
to a HW/driver bug, which triggers reset of the HW clock instance. To
avoid having a bad estimate of the frequency when the next (good) sample
is accumulated, drop also the last sample which triggered the reset.
2017-08-23 15:01:30 +02:00
Miroslav Lichvar
27cbf20d23 doc: include uncorrected offset in bound on maximum error 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
5c571bbbe7 reference: add new fields to tracking log
Add the root delay, root dispersion and maximum estimated error in the
interval since the previous update to the tracking log.
2017-08-23 15:01:30 +02:00
Miroslav Lichvar
33d65c8614 reference: separate calculation of root dispersion 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
d87db7cdb8 reference: refactor log writing
Remove unnecessary parameters of the write_log() function.
2017-08-23 15:01:30 +02:00
Miroslav Lichvar
45fa4750da reference: don't update fallback drift on manual input
This fixes a crash due to assertion failure in update_fb_drifts() when
fallbackdrift is enabled and manual input is provided.
2017-08-23 15:01:30 +02:00
Miroslav Lichvar
8472fd8133 reference: simplify check for NaN 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
5ab645e310 cmdmon: add new fields to ADD_SERVER/ADD_PEER request 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
8ccda538d3 conf: add mindelay and asymmetry options to NTP sources 2017-08-23 15:01:28 +02:00
Miroslav Lichvar
b06d74ab73 sourcestats: add fixed asymmetry
Rework the code to allow the jitter asymmetry to be specified.
2017-08-23 14:33:23 +02:00
Miroslav Lichvar
d0964ffa83 sourcestats: add fixed minimum delay
If the minimum delay is known (in a static network configuration), it
can replace the measured minimum from the register. This should improve
the stability of corrections for asymmetric jitter, sample weighting and
maxdelay* tests.
2017-08-23 14:14:06 +02:00
Miroslav Lichvar
3d08815efb sys_linux: fix building with older kernel headers
Programming pins for external PHC timestamping was added in Linux 3.15,
but the PHC subsystem is older than that. Compile the programming code
only when the ioctl is defined.
2017-08-15 13:39:39 +02:00
Miroslav Lichvar
a83f0d3cdc util: simplify clamping in UTI_TimespecNetworkToHost()
This should fix a coverity warning.
2017-08-15 13:27:50 +02:00
Miroslav Lichvar
702db726d3 util: add assertion for NTP timestamp size 2017-08-15 13:27:50 +02:00
Miroslav Lichvar
ed5c43204b smooth: don't adjust invalid time of last update 2017-08-15 13:27:50 +02:00
Miroslav Lichvar
f91bdd604d reference: don't adjust invalid reference time 2017-08-15 13:27:50 +02:00
Miroslav Lichvar
3a1dbb1354 test: fix ntp_core unit test
This fixes commit b896bb5a78.
2017-08-09 10:41:30 +02:00
Bryan Christianson
4b511143b8 sys_netbsd: fix adjtime() fault on macOS
On some systems, passing NULL as the first argument to adjtime, will
result in returning the amount of adjustment outstanding from a previous
call to adjtime().

On macOS this is not allowed and the adjtime call will fault. We can
simulate the behaviour of the other systems by cancelling the current
adjustment then restarting the adjustment using the outstanding time
that was returned. On macOS 10.13 and later, the netbsd driver is now
used and must use these semantics when making/measuring corrections.
2017-08-09 09:57:14 +02:00
Miroslav Lichvar
93076e7e1c client: fix parsing of -v command option
The sources and sourcestats commands accept -v as an option, but the
glibc implementation of getopt() reorders the arguments and parses the
option as a command-line option of chronyc.

Add '+' to the getopt string to disable this feature. Other getopt()
implementations should consider it a new command-line option, which will
be handled as an error if present.
2017-08-09 09:57:14 +02:00
Miroslav Lichvar
1c51feb3c5 sched: add new timeout class for peer transmissions
This allows transmissions in symmetric mode to be scheduled
independently from client transmissions. This reduces maximum delay
in scheduling when chronyd is configured with a larger number of
servers.
2017-08-09 09:57:14 +02:00
Miroslav Lichvar
c2773dbc2f test: improve hwclock unit test 2017-08-09 09:57:14 +02:00
Miroslav Lichvar
4534db84c4 hwclock: fix conversion of HW timestamps
Fix a sign error in conversion of HW time to local time, which caused
the jitter to be amplified instead of reduced. NTP with HW timestamping
should now be more stable and able to ignore occasionally delayed
readings of PHC.
2017-08-09 09:57:14 +02:00
Miroslav Lichvar
be8215e181 ntp: minimize data in client mode packets
In basic client mode, set the origin and receive timestamp to zero.
This reduces the amount of information useful for fingerprinting and
improves privacy as the origin timestamp allows a passive observer to
track individual NTP clients as they move across networks. (With chrony
clients that assumes the timestamp wasn't reset by the chronyc offline
and online commands.)

This follows recommendations from the current version of IETF draft on
NTP data minimization [1].

The timestamp could be theoretically useful for enhanced rate limiting
which can limit individual clients behind NAT and better deal with DoS
attacks, but no server implementation is known to do that.

[1] https://tools.ietf.org/html/draft-ietf-ntp-data-minimization-01
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
ae82bbbace examples: improve NetworkManager dispatcher script
When no default route is configured, check each source if it has a
route. If the system has multiple network interfaces, this prevents
setting local NTP servers to offline when they can still be reached over
one of the interfaces.
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
2b6ea41062 doc: fix server mode number in chrony.conf man page 2017-08-09 09:57:13 +02:00
Miroslav Lichvar
d9f745fe70 doc: update chrony.conf man page for recent changes 2017-08-09 09:57:13 +02:00
Miroslav Lichvar
9aac179367 ntp: skip IPv6 extension headers
Handle IPv6 packets with extension headers received from the error queue
on Linux.
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
b896bb5a78 ntp: don't send useless requests in interleaved client mode
In interleaved client mode, when so many consecutive requests were lost
that the first valid (interleaved) response would be dropped for being
too old, switch to basic mode so the response can be accepted if it
doesn't fail in the other tests.

This reworks commit 16afa8eb50.
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
64c2fd9888 ntp: limit number of interleaved responses in symmetric mode
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.
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
2668a12e4e ntp: improve detection of missed packets in interleaved mode
In interleaved symmetric mode, check if the remote TX timestamp is
before RX timestamp. Only the first response from the peer after
receiving a request should pass this test. Check also the interval
between last two remote transmit timestamps when we know the remote poll
can't be constrained by minpoll. Use the minimum of previous remote and
local poll as a lower bound of the actual interval between peer's
transmissions.
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
e1645966ec ntp: enable maxdelayratio test in interleaved client mode
With more accurate delay in interleaved mode the test should now be as
reliable as in basic mode.
2017-08-09 09:57:13 +02:00
Bryan Christianson
4f1fc1ee78 main: fix -q option
Attempting to step the system clock by using the -q option with chronyd
would fail.
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
d70df3daab logging: enable line buffering of file log
The file log specified with the -l option should have the messages as
soon as they are produced.
2017-08-08 15:37:59 +02:00
48 changed files with 653 additions and 300 deletions

9
NEWS
View File

@@ -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
View File

@@ -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.

View File

@@ -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 *

View File

@@ -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;

View File

@@ -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':

View File

@@ -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

View File

@@ -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;

View File

@@ -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
View File

@@ -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
View File

@@ -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;

View File

@@ -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:

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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
View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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 */

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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[] = {

View File

@@ -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

View File

@@ -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),

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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 */

View File

@@ -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

View File

@@ -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;
}
/* ================================================== */

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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
View 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

View File

@@ -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();

View File

@@ -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));
}
}

View File

@@ -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);

View File

@@ -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
View File

@@ -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);
}
/* ================================================== */