Compare commits

..

45 Commits

Author SHA1 Message Date
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
45 changed files with 621 additions and 292 deletions

9
NEWS
View File

@@ -4,14 +4,19 @@ New in version 3.2
Enhancements Enhancements
------------ ------------
* Improve stability with NTP sources and reference clocks * Improve stability with NTP sources and reference clocks
* Improve stability with hardware timestamping
* Improve support for NTP interleaved modes * Improve support for NTP interleaved modes
* Control frequency of system clock on macOS 10.13 and later * Control frequency of system clock on macOS 10.13 and later
* Set TAI-UTC offset of system clock with leapsectz directive * Set TAI-UTC offset of system clock with leapsectz directive
* Add support for new HW timestamping options added in Linux 4.13 * Minimise data in client requests to improve privacy
* Add rxfilter option to hwtimestamp directive * 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 extpps option to PHC refclock to timestamp external PPS signal
* Add pps option to refclock directive to treat any refclock as PPS * Add pps option to refclock directive to treat any refclock as PPS
* Add width option to refclock directive to filter wrong pulse edges * 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 -x option to disable control of system clock
* Add -l option to log to specified file instead of syslog * Add -l option to log to specified file instead of syslog
* Allow multiple command-line options to be specified together * 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). 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. (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 It can also operate as an NTPv4 (RFC 5905) server and peer to provide
a time service to other computers in the network. a time service to other computers in the network.

View File

@@ -66,8 +66,6 @@ ARR_DestroyInstance(ARR_Instance array)
static void static void
realloc_array(ARR_Instance array, unsigned int min_size) realloc_array(ARR_Instance array, unsigned int min_size)
{ {
size_t data_size;
assert(min_size <= 2 * min_size); assert(min_size <= 2 * min_size);
if (array->allocated >= min_size && array->allocated <= 2 * min_size) if (array->allocated >= min_size && array->allocated <= 2 * min_size)
return; return;
@@ -79,10 +77,7 @@ realloc_array(ARR_Instance array, unsigned int min_size)
array->allocated = min_size; array->allocated = min_size;
} }
data_size = (size_t)array->elem_size * array->allocated; array->data = Realloc2(array->data, array->allocated, array->elem_size);
assert(data_size / array->elem_size == array->allocated);
array->data = Realloc(array->data, data_size);
} }
void * void *

View File

@@ -97,7 +97,9 @@
#define REQ_NTP_DATA 57 #define REQ_NTP_DATA 57
#define REQ_ADD_SERVER2 58 #define REQ_ADD_SERVER2 58
#define REQ_ADD_PEER2 59 #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 */ /* Structure used to exchange timespecs independent of time_t size */
typedef struct { typedef struct {
@@ -267,8 +269,11 @@ typedef struct {
Float max_delay; Float max_delay;
Float max_delay_ratio; Float max_delay_ratio;
Float max_delay_dev_ratio; Float max_delay_dev_ratio;
Float min_delay;
Float asymmetry;
Float offset; Float offset;
uint32_t flags; uint32_t flags;
uint32_t reserved[4];
int32_t EOR; int32_t EOR;
} REQ_NTP_Source; } REQ_NTP_Source;

View File

@@ -4,7 +4,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Lonnie Abelbeck 2016 * 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -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_ratio = UTI_FloatHostToNetwork(data.params.max_delay_ratio);
msg->data.ntp_source.max_delay_dev_ratio = msg->data.ntp_source.max_delay_dev_ratio =
UTI_FloatHostToNetwork(data.params.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.offset = UTI_FloatHostToNetwork(data.params.offset);
msg->data.ntp_source.flags = htonl( msg->data.ntp_source.flags = htonl(
(data.params.online ? REQ_ADDSRC_ONLINE : 0) | (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_NOSELECT ? REQ_ADDSRC_NOSELECT : 0) |
(data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) | (data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) |
(data.params.sel_options & SRC_SELECT_REQUIRE ? REQ_ADDSRC_REQUIRE : 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; result = 1;
break; break;
@@ -1124,7 +1128,7 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
static int static int
process_cmd_add_server(CMD_Request *msg, char *line) 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); return process_cmd_add_server_or_peer(msg, line);
} }
@@ -1133,7 +1137,7 @@ process_cmd_add_server(CMD_Request *msg, char *line)
static int static int
process_cmd_add_peer(CMD_Request *msg, char *line) 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); return process_cmd_add_server_or_peer(msg, line);
} }
@@ -3143,7 +3147,7 @@ main(int argc, char **argv)
optind = 1; optind = 1;
/* Parse short command-line options */ /* 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) { switch (opt) {
case '4': case '4':
case '6': case '6':

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as

View File

@@ -136,6 +136,8 @@ static const char permissions[] = {
PERMIT_AUTH, /* NTP_DATA */ PERMIT_AUTH, /* NTP_DATA */
PERMIT_AUTH, /* ADD_SERVER2 */ PERMIT_AUTH, /* ADD_SERVER2 */
PERMIT_AUTH, /* ADD_PEER2 */ 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); UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio);
params.max_delay_dev_ratio = params.max_delay_dev_ratio =
UTI_FloatNetworkToHost(rx_message->data.ntp_source.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.offset = UTI_FloatNetworkToHost(rx_message->data.ntp_source.offset);
params.online = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ? 1 : 0; 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); handle_cmdaccheck(&rx_message, &tx_message);
break; break;
case REQ_ADD_SERVER2: case REQ_ADD_SERVER3:
handle_add_source(NTP_SERVER, &rx_message, &tx_message); handle_add_source(NTP_SERVER, &rx_message, &tx_message);
break; break;
case REQ_ADD_PEER2: case REQ_ADD_PEER3:
handle_add_source(NTP_PEER, &rx_message, &tx_message); handle_add_source(NTP_PEER, &rx_message, &tx_message);
break; 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 = SRC_DEFAULT_MAXDELAY;
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO; src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO; 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; src->params.offset = 0.0;
hostname = line; hostname = line;
@@ -98,6 +100,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 || if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
src->params.authkey == INACTIVE_AUTHKEY) src->params.authkey == INACTIVE_AUTHKEY)
return 0; return 0;
} else if (!strcasecmp(cmd, "asymmetry")) {
if (sscanf(line, "%lf%n", &src->params.asymmetry, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "maxdelay")) { } else if (!strcasecmp(cmd, "maxdelay")) {
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1) if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1)
return 0; return 0;
@@ -116,6 +121,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxsources")) { } else if (!strcasecmp(cmd, "maxsources")) {
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1) if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1)
return 0; 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")) { } else if (!strcasecmp(cmd, "minpoll")) {
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1) if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1)
return 0; return 0;

2
conf.c
View File

@@ -1281,7 +1281,7 @@ parse_hwtimestamp(char *line)
iface->name = Strdup(p); iface->name = Strdup(p);
iface->minpoll = 0; iface->minpoll = 0;
iface->nocrossts = 0; iface->nocrossts = 0;
iface->rxfilter = CNF_HWTS_RXFILTER_NTP; iface->rxfilter = CNF_HWTS_RXFILTER_ANY;
iface->precision = 100.0e-9; iface->precision = 100.0e-9;
iface->tx_comp = 0.0; iface->tx_comp = 0.0;
iface->rx_comp = 0.0; iface->rx_comp = 0.0;

11
conf.h
View File

@@ -118,15 +118,18 @@ extern char *CNF_GetHwclockFile(void);
extern int CNF_GetInitSources(void); extern int CNF_GetInitSources(void);
extern double CNF_GetInitStepThreshold(void); extern double CNF_GetInitStepThreshold(void);
#define CNF_HWTS_RXFILTER_NONE 0 typedef enum {
#define CNF_HWTS_RXFILTER_NTP 1 CNF_HWTS_RXFILTER_ANY,
#define CNF_HWTS_RXFILTER_ALL 2 CNF_HWTS_RXFILTER_NONE,
CNF_HWTS_RXFILTER_NTP,
CNF_HWTS_RXFILTER_ALL,
} CNF_HwTs_RxFilter;
typedef struct { typedef struct {
char *name; char *name;
int minpoll; int minpoll;
int nocrossts; int nocrossts;
int rxfilter; CNF_HwTs_RxFilter rxfilter;
double precision; double precision;
double tx_comp; double tx_comp;
double rx_comp; double rx_comp;

View File

@@ -2,6 +2,7 @@
// //
// Copyright (C) Richard P. Curnow 1997-2003 // Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Stephen Wadeley 2016 // Copyright (C) Stephen Wadeley 2016
// Copyright (C) Bryan Christianson 2017
// Copyright (C) Miroslav Lichvar 2009-2017 // Copyright (C) Miroslav Lichvar 2009-2017
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
@@ -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 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 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 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 maxdelayratio times the minimum delay, it will be rejected.
only in the *server* directive when not in the interleaved mode.
*maxdelaydevratio* _ratio_::: *maxdelaydevratio* _ratio_:::
If a measurement has a ratio of the increase in the round-trip delay from the 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 minimum delay amongst the previous measurements to the standard deviation of
the previous measurements that is greater than the specified ratio, it will be the previous measurements that is greater than the specified ratio, it will be
rejected. The default is 10.0. 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_::: *offset* _offset_:::
This option specifies a correction (in seconds) which will be applied to 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 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 by other clients that have the same IP address (e.g. computers behind NAT or
someone sending requests with a spoofed source address). someone sending requests with a spoofed source address).
+ +
With longer polling intervals, it is recommended to combine the *xleave* option The *xleave* option can be combined with the *presend* option in order to
with the *presend* option in order to shorten the interval in which the server shorten the interval in which the server has to keep the state to be able to
has to keep the state to be able to respond in the interleaved mode. The respond in the interleaved mode.
shorter interval also improves accuracy of the measured offset and delay.
*polltarget* _target_::: *polltarget* _target_:::
Target number of measurements to use for the regression algorithm which Target number of measurements to use for the regression algorithm which
*chronyd* will try to maintain by adjusting the polling interval between *chronyd* will try to maintain by adjusting the polling interval between
@@ -1611,7 +1623,7 @@ from the example line above):
. The root dispersion (_EPSILON_ in RFC 5905). [7.446e-03] . The root dispersion (_EPSILON_ in RFC 5905). [7.446e-03]
. Reference ID of the server's source as a hexadecimal number. [CB00717B] . Reference ID of the server's source as a hexadecimal number. [CB00717B]
. NTP mode of the received packet (_1_=active peer, _2_=passive peer, . 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 . Source of the local transmit timestamp
(_D_=daemon, _K_=kernel, _H_=hardware). [D] (_D_=daemon, _K_=kernel, _H_=hardware). [D]
. Source of the local receive timestamp . 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 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. tabulated. Values of approximately half the number of samples are expected.
[8] [8]
. The estimated asymmetry of network jitter on the path to the source which was . The estimated or configured asymmetry of network jitter on the path to the
used to correct the measured offsets. The asymmetry can be between -0.5 and source which was used to correct the measured offsets. The asymmetry can be
0.5. A negative value means the delay of packets sent to the source is between -0.5 and +0.5. A negative value means the delay of packets sent to
more variable than the delay of packets sent from the source back. [0.00, the source is more variable than the delay of packets sent from the source
i.e. no correction for asymmetry] back. [0.00, i.e. no correction for asymmetry]
+ +
*tracking*::: *tracking*:::
This option logs changes to the estimate of the system's gain or loss rate, and 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. below.
+ +
---- ----
2015-02-23 05:40:50 203.0.113.15 3 340.529 1.606 1.046e-03 N \ 2017-08-22 13:22:36 203.0.113.15 2 -3.541 0.075 -8.621e-06 N \
4 6.849e-03 -4.670e-04 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 The columns are as follows (the quantities in square brackets are the
values from the example line above) : 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 . 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. . The IP address of the server or peer to which the local system is synchronised.
[203.0.113.15] [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 . The local system frequency (in ppm, positive means the local system runs fast
of UTC). [340.529] of UTC). [-3.541]
. The error bounds on the frequency (in ppm). [1.606] . The error bounds on the frequency (in ppm). [0.075]
. The estimated local offset at the epoch (which is rapidly corrected by . The estimated local offset at the epoch, which is normally corrected by
slewing the local clock. (In seconds, positive indicates the local system slewing the local clock (in seconds, positive indicates the clock is fast of
is fast of UTC). [1.046e-3] UTC). [-8.621e-06]
. Leap status (_N_ means normal, _+_ means that the last minute of this month . 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, has 61 seconds, _-_ means that the last minute of the month has 59 seconds,
_?_ means the clock is not currently synchronised.) [N] _?_ 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). . 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, . 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*::: *rtc*:::
This option logs information about the system's real-time clock. An example 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 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 timestamping, which can be verified with the *ethtool -T* command. The list of
capabilities should include _SOF_TIMESTAMPING_RAW_HARDWARE_, capabilities should include _SOF_TIMESTAMPING_RAW_HARDWARE_,
_SOF_TIMESTAMPING_TX_HARDWARE_, _SOF_TIMESTAMPING_RX_HARDWARE_, and the filter _SOF_TIMESTAMPING_TX_HARDWARE_, and _SOF_TIMESTAMPING_RX_HARDWARE_. Receive
modes should include _HWTSTAMP_FILTER_ALL_ or _HWTSTAMP_FILTER_NTP_ALL_. When filter _HWTSTAMP_FILTER_ALL_, or _HWTSTAMP_FILTER_NTP_ALL_, is necessary for
*chronyd* is running, no other process (e.g. a PTP daemon) should be working timestamping of received packets. Timestamping of packets received from bridged
with the NIC clock. 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 If the kernel supports software timestamping, it will be enabled for all
interfaces. With both hardware and software timestamping there are some interfaces. The source of timestamps (i.e. hardware, kernel, or daemon) is
limitations on which timestamps can be actually used, e.g. transmit indicated in the _measurements.log_ file if enabled by the <<log,*log
timestamping does not currently work with IPv6 packets using IP options and measurements*>> directive, and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in
hardware timestamping of packets received from bridges, bonds, and other *chronyc*.
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*.
+ +
If the specified interface is _*_, *chronyd* will try to enable HW timestamping If the specified interface is _*_, *chronyd* will try to enable HW timestamping
on all available interfaces. on all available interfaces.
@@ -1907,15 +1926,21 @@ is 0.
Some hardware can precisely cross timestamp the NIC clock with the system Some hardware can precisely cross timestamp the NIC clock with the system
clock. This option disables the use of the cross timestamping. clock. This option disables the use of the cross timestamping.
*rxfilter* _filter_::: *rxfilter* _filter_:::
This option selects the receive timestamping filter. Possible values are: This option selects the receive timestamping filter. The _filter_ can be one of
_all_, _ntp_, and _none_. The default value is _ntp_, which enables the following:
timestamping of NTP packets (_HWTSTAMP_FILTER_NTP_ALL_) if it is supported, or _all_::::
timestamping of all packets (_HWTSTAMP_FILTER_ALL_). Setting *rxfilter* to Enables timestamping of all received packets.
_all_ forces timestamping of all packets, which can be useful when the NIC _ntp_::::
supports both filters and NTP packets are received from or on a non-standard Enables timestamping of received NTP packets.
UDP port (e.g. specified by the *port* directive). Setting *rxfilter* to _none_ _none_::::
disables receive HW timestamping and allows transmit HW timestamping to be Disables timestamping of received packets.
enabled when the NIC supports only PTP-specific receive filters. :::
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: Examples of the directive are:

View File

@@ -2,7 +2,7 @@
// //
// Copyright (C) Richard P. Curnow 1997-2003 // Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Stephen Wadeley 2016 // 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 // This program is free software; you can redistribute it and/or modify
// it under the terms of version 2 of the GNU General Public License as // it under the terms of version 2 of the GNU General Public License as
@@ -216,7 +216,7 @@ An absolute bound on the computer's clock accuracy (assuming the stratum-1
computer is correct) is given by: 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*::: *Update interval*:::
This is the interval between the last two clock updates. This is the interval between the last two clock updates.

View File

@@ -1,7 +1,7 @@
// This file is part of chrony // This file is part of chrony
// //
// Copyright (C) Richard P. Curnow 1997-2003 // 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 // This program is free software; you can redistribute it and/or modify
// it under the terms of version 2 of the GNU General Public License as // it under the terms of version 2 of the GNU General Public License as

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 reliability the client should have at least three servers. The `iburst` option
speeds up the initial synchronisation. 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. 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, 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. that.
In order to keep the real-time clock (RTC) close to the true time, so the 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 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 system time is periodically copied to the RTC. It is supported on Linux and
macOS. 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)? === What is the real-time clock (RTC)?
This is the clock which keeps the time even when your computer is turned off. 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. more than few seconds per day.
There are two approaches how `chronyd` can work with it. One is to use the 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 `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 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 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. it on the next boot.
The other option is to use the `rtcfile` directive, which tells `chronyd` to The other option is to use the `rtcfile` directive, which tells `chronyd` to

View File

@@ -1,17 +1,35 @@
#!/bin/sh #!/bin/sh
# This is a NetworkManager dispatcher script for chronyd to set its NTP sources # 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 export LC_ALL=C
if [ "$2" = "up" ]; then # Check if there is a default route
/sbin/ip route list dev "$1" | grep -q '^default' &&
/usr/bin/chronyc online > /dev/null 2>&1 if /sbin/ip route list 2> /dev/null | grep -q '^default'; then
chronyc online > /dev/null 2>&1
exit 0
fi fi
if [ "$2" = "down" ]; then sources=$(chronyc -c -n sources 2> /dev/null)
/sbin/ip route list | grep -q '^default' ||
/usr/bin/chronyc offline > /dev/null 2>&1 [ $? -ne 0 ] && exit 0
fi
# 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 exit 0

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate. 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -39,6 +39,9 @@
/* Maximum number of samples per clock */ /* Maximum number of samples per clock */
#define MAX_SAMPLES 16 #define MAX_SAMPLES 16
/* Maximum acceptable frequency offset of the clock */
#define MAX_FREQ_OFFSET (2.0 / 3.0)
struct HCL_Instance_Record { struct HCL_Instance_Record {
/* HW and local reference timestamp */ /* HW and local reference timestamp */
struct timespec hw_ref; struct timespec hw_ref;
@@ -174,16 +177,17 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
/* Drop unneeded samples */ /* Drop unneeded samples */
clock->n_samples -= best_start; clock->n_samples -= best_start;
/* If the fit doesn't cross the error interval of the last sample, throw away /* If the fit doesn't cross the error interval of the last sample,
all previous samples and keep only the frequency estimate */ or the frequency is not sane, drop all samples and start again */
if (fabs(clock->offset) > err) { if (fabs(clock->offset) > err ||
DEBUG_LOG("HW clock reset offset=%e", clock->offset); fabs(clock->frequency - 1.0) > MAX_FREQ_OFFSET) {
clock->offset = 0.0; DEBUG_LOG("HW clock reset");
clock->n_samples = 1; 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", 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, raw_freq, err, clock->n_samples, clock->offset, clock->frequency - 1.0, raw_freq - 1.0, err,
UTI_DiffTimespecsToDouble(&clock->hw_ref, &clock->local_ref)); 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; return 0;
elapsed = UTI_DiffTimespecsToDouble(raw, &clock->hw_ref); 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); UTI_AddDoubleToTimespec(&clock->local_ref, offset, cooked);
/* Fow now, just return the error of the last sample */ /* Fow now, just return the error of the last sample */

View File

@@ -188,6 +188,9 @@ LOG_OpenFileLog(const char *log_file)
if (!f) if (!f)
LOG_FATAL("Could not open log file %s", log_file); LOG_FATAL("Could not open log file %s", log_file);
/* Enable line buffering */
setvbuf(f, NULL, _IOLBF, BUFSIZ);
file_log = f; file_log = f;
} }

9
main.c
View File

@@ -4,7 +4,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009 * Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2012-2016 * Copyright (C) Miroslav Lichvar 2012-2017
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -448,8 +448,13 @@ int main
sched_priority = parse_int_arg(optarg); sched_priority = parse_int_arg(optarg);
break; break;
case 'q': case 'q':
ref_mode = REF_ModeUpdateOnce;
nofork = 1;
client_only = 0;
system_log = 0;
break;
case 'Q': case 'Q':
ref_mode = opt == 'q' ? REF_ModeUpdateOnce : REF_ModePrintOnce; ref_mode = REF_ModePrintOnce;
nofork = 1; nofork = 1;
client_only = 1; client_only = 1;
clock_control = 0; clock_control = 0;

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate. chronyd/chronyc - Programs for keeping computer clocks accurate.
********************************************************************** **********************************************************************
* Copyright (C) Miroslav Lichvar 2014 * Copyright (C) Miroslav Lichvar 2014, 2017
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -54,6 +54,32 @@ Realloc(void *ptr, size_t size)
return r; 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 * char *
Strdup(const char *s) Strdup(const char *s)
{ {

View File

@@ -30,12 +30,14 @@
/* Wrappers checking for errors */ /* Wrappers checking for errors */
extern void *Malloc(size_t size); extern void *Malloc(size_t size);
extern void *Realloc(void *ptr, 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); extern char *Strdup(const char *s);
/* Convenient macros */ /* Convenient macros */
#define MallocNew(T) ((T *) Malloc(sizeof(T))) #define MallocNew(T) ((T *) Malloc(sizeof(T)))
#define MallocArray(T, n) ((T *) Malloc((n) * sizeof(T))) #define MallocArray(T, n) ((T *) Malloc2(n, sizeof(T)))
#define ReallocArray(T,n,x) ((T *) Realloc((void *)(x), (n)*sizeof(T))) #define ReallocArray(T, n, x) ((T *) Realloc2((void *)(x), n, sizeof(T)))
#define Free(x) free(x) #define Free(x) free(x)
#endif /* GOT_MEMORY_H */ #endif /* GOT_MEMORY_H */

View File

@@ -178,8 +178,10 @@ struct NCR_Instance_Record {
NTP_int64 local_ntp_tx; NTP_int64 local_ntp_tx;
NTP_Local_Timestamp local_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; 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 /* The instance record in the main source management module. This
performs the statistical analysis on the samples we generate */ 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 */ /* Start new timer for transmission */
inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, get_separation(inst->local_poll), inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, get_separation(inst->local_poll),
SAMPLING_RANDOMNESS, SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass, inst->mode == MODE_CLIENT ?
SCH_NtpClientClass : SCH_NtpPeerClass,
transmit_timeout, (void *)inst); 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), result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr),
SRC_NTP, params->sel_options, SRC_NTP, params->sel_options,
&result->remote_addr.ip_addr, &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->rx_timeout_id = 0;
result->tx_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_rx);
UTI_ZeroNtp64(&instance->local_ntp_tx); UTI_ZeroNtp64(&instance->local_ntp_tx);
zero_local_timestamp(&instance->local_rx); zero_local_timestamp(&instance->local_rx);
zero_local_timestamp(&instance->prev_local_tx); zero_local_timestamp(&instance->prev_local_tx);
instance->prev_local_poll = 0;
instance->prev_tx_count = 0;
} }
/* ================================================== */ /* ================================================== */
@@ -976,6 +983,9 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
UTI_TimespecToNtp64(&our_ref_time, &message.reference_ts, NULL); UTI_TimespecToNtp64(&our_ref_time, &message.reference_ts, NULL);
/* Don't reveal timestamps which are not necessary for the protocol */
if (my_mode != MODE_CLIENT || interleaved) {
/* Originate - this comes from the last packet the source sent us */ /* Originate - this comes from the last packet the source sent us */
message.originate_ts = interleaved ? *remote_ntp_rx : *remote_ntp_tx; message.originate_ts = interleaved ? *remote_ntp_rx : *remote_ntp_tx;
@@ -987,6 +997,10 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
the source like we have been running on our latest estimate of the source like we have been running on our latest estimate of
frequency all along */ frequency all along */
UTI_TimespecToNtp64(&local_receive, &message.receive_ts, &ts_fuzz); UTI_TimespecToNtp64(&local_receive, &message.receive_ts, &ts_fuzz);
} else {
UTI_ZeroNtp64(&message.originate_ts);
UTI_ZeroNtp64(&message.receive_ts);
}
do { do {
/* Prepare random bits which will be added to the transmit timestamp */ /* 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; NCR_Instance inst = (NCR_Instance) arg;
NTP_Local_Address local_addr; NTP_Local_Address local_addr;
int sent; int interleaved, sent;
inst->tx_timeout_id = 0; inst->tx_timeout_id = 0;
@@ -1110,18 +1124,31 @@ transmit_timeout(void *arg)
local_addr.if_index = INVALID_IF_INDEX; local_addr.if_index = INVALID_IF_INDEX;
local_addr.sock_fd = inst->local_addr.sock_fd; local_addr.sock_fd = inst->local_addr.sock_fd;
/* 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 /* 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 sending an NTP exchange to ensure both ends' ARP caches are
primed or whether we need to send two packets first to ensure a primed or whether we need to send two packets first to ensure a
server in the interleaved mode has a fresh timestamp for us. */ server in the interleaved mode has a fresh timestamp for us. */
if (inst->presend_minpoll <= inst->local_poll && !inst->presend_done && if (inst->presend_minpoll <= inst->local_poll && !inst->presend_done &&
!inst->burst_total_samples_to_go) { !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) { } else if (inst->presend_done > 0) {
inst->presend_done--; 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->version,
inst->auth_mode, inst->auth_key_id, inst->auth_mode, inst->auth_key_id,
&inst->remote_ntp_rx, &inst->remote_ntp_tx, &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 static int
receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr, receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length) 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)) { if (synced_packet && (!interleaved_packet || inst->valid_timestamps)) {
/* These are the timespec equivalents of the remote and local epochs */ /* These are the timespec equivalents of the remote and local epochs */
struct timespec remote_receive, remote_transmit, remote_request_receive; 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 */ /* Select remote and local timestamps for the new sample */
if (interleaved_packet) { if (interleaved_packet) {
@@ -1444,10 +1533,12 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
local_transmit = inst->local_tx; local_transmit = inst->local_tx;
} }
UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit); UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
UTI_Ntp64ToTimespec(&inst->remote_ntp_tx, &prev_remote_transmit);
local_receive = inst->local_rx; local_receive = inst->local_rx;
} else { } else {
UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive); UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit); UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
UTI_ZeroTimespec(&prev_remote_transmit);
remote_request_receive = remote_receive; remote_request_receive = remote_receive;
local_receive = *rx_ts; local_receive = *rx_ts;
local_transmit = inst->local_tx; 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)) + dispersion = MAX(precision, MAX(local_transmit.err, local_receive.err)) +
skew * fabs(local_interval); 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 */ /* Additional tests required to pass before accumulating the sample */
/* Test A requires that the minimum estimate of the peer delay is not /* Test A requires that the minimum estimate of the peer delay is not
larger than the configured maximum, in client mode that the server larger than the configured maximum, in both client modes that the server
processing time is sane, in the interleaved client mode that the processing time is sane, and in interleaved symmetric mode that the
timestamps are not too old, and in the interleaved symmetric mode measured delay and intervals between remote timestamps don't indicate
that the delay is not longer than half of the remote polling interval a missed response */
to detect missed packets */
testA = delay - dispersion <= inst->max_delay && precision <= inst->max_delay && testA = delay - dispersion <= inst->max_delay && precision <= inst->max_delay &&
!(inst->mode == MODE_CLIENT && !(inst->mode == MODE_CLIENT && response_time > MAX_SERVER_INTERVAL) &&
(response_time > MAX_SERVER_INTERVAL ||
(interleaved_packet && inst->tx_count > MAX_CLIENT_INTERLEAVED_TX + 1))) &&
!(inst->mode == MODE_ACTIVE && interleaved_packet && !(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 /* Test B requires in client mode that the ratio of the round trip delay
trip delay to the minimum one currently in the stats data register is to the minimum one currently in the stats data register is less than an
less than an administrator-defined value */ administrator-defined value */
testB = inst->max_delay_ratio <= 1.0 || testB = check_delay_ratio(inst, stats, &sample_time, delay);
!(inst->mode == MODE_CLIENT && !interleaved_packet &&
(delay - dispersion) / SST_MinRoundTripDelay(stats) > inst->max_delay_ratio);
/* Test C requires that the ratio of the increase in delay from the minimum /* 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 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 in the register is less than an administrator-defined value or the
difference between measured offset and predicted offset is larger than difference between measured offset and predicted offset is larger than
the increase in delay */ the increase in delay */
testC = SST_IsGoodSample(stats, -offset, delay, inst->max_delay_dev_ratio, testC = check_delay_dev_ratio(inst, stats, &sample_time, offset, delay);
LCL_GetMaxClockError(), &sample_time);
/* Test D requires that the remote peer is not synchronised to us to /* Test D requires that the remote peer is not synchronised to us to
prevent a synchronisation loop */ 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 ? inst->remote_stratum = message->stratum != NTP_INVALID_STRATUM ?
message->stratum : NTP_MAX_STRATUM; message->stratum : NTP_MAX_STRATUM;
inst->prev_local_poll = inst->local_poll;
inst->prev_tx_count = inst->tx_count;
inst->tx_count = 0; inst->tx_count = 0;
SRC_UpdateReachability(inst->source, synced_packet); SRC_UpdateReachability(inst->source, synced_packet);
if (good_packet) { if (good_packet) {

View File

@@ -154,17 +154,25 @@ add_interface(CNF_HwTsInterface *conf_iface)
ts_config.tx_type = HWTSTAMP_TX_ON; ts_config.tx_type = HWTSTAMP_TX_ON;
switch (conf_iface->rxfilter) { 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: case CNF_HWTS_RXFILTER_NONE:
ts_config.rx_filter = HWTSTAMP_FILTER_NONE; ts_config.rx_filter = HWTSTAMP_FILTER_NONE;
break; break;
case CNF_HWTS_RXFILTER_NTP:
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP #ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL)) { case CNF_HWTS_RXFILTER_NTP:
ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL; ts_config.rx_filter = HWTSTAMP_FILTER_NTP_ALL;
break; break;
}
#endif #endif
/* Fall through */
default: default:
ts_config.rx_filter = HWTSTAMP_FILTER_ALL; ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
break; break;
@@ -203,7 +211,8 @@ add_interface(CNF_HwTsInterface *conf_iface)
iface->clock = HCL_CreateInstance(UTI_Log2ToDouble(MAX(conf_iface->minpoll, MIN_PHC_POLL))); 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; 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; len -= ihl + 8, msg += ihl + 8;
#ifdef FEAT_IPV6 #ifdef FEAT_IPV6
} else if (len >= 48 && msg[0] >> 4 == 6) { } else if (len >= 48 && msg[0] >> 4 == 6) {
/* IPv6 extension headers are not supported */ int eh_len, next_header = msg[6];
if (msg[6] != 17)
return 0;
memcpy(&addr.in6.sin6_addr.s6_addr, msg + 24, 16); 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; addr.in6.sin6_family = AF_INET6;
len -= 48, msg += 48; len -= 8, msg += 8;
#endif #endif
} else { } else {
return 0; return 0;

View File

@@ -114,8 +114,10 @@ static const struct request_length request_lengths[] = {
client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */ client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
REQ_LENGTH_ENTRY(local, null), /* LOCAL2 */ REQ_LENGTH_ENTRY(local, null), /* LOCAL2 */
REQ_LENGTH_ENTRY(ntp_data, ntp_data), /* NTP_DATA */ REQ_LENGTH_ENTRY(ntp_data, ntp_data), /* NTP_DATA */
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SERVER2 */ { 0, 0 }, /* ADD_SERVER2 */
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_PEER2 */ { 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[] = { static const uint16_t reply_lengths[] = {

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Bryan Christianson 2015 * 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate. chronyd/chronyc - Programs for keeping computer clocks accurate.
********************************************************************** **********************************************************************
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016 * Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016-2017
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -260,7 +260,7 @@ RCL_AddRefclock(RefclockParameters *params)
filter_init(&inst->filter, params->filter_length, params->max_dispersion); filter_init(&inst->filter, params->filter_length, params->max_dispersion);
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_options, NULL, 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", DEBUG_LOG("refclock %s refid=%s poll=%d dpoll=%d filter=%d",
params->driver_name, UTI_RefidToString(inst->ref_id), params->driver_name, UTI_RefidToString(inst->ref_id),

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -156,6 +156,7 @@ handle_slew(struct timespec *raw,
double delta; double delta;
struct timespec now; struct timespec now;
if (!UTI_IsZeroTimespec(&our_ref_time))
UTI_AdjustTimespec(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset); UTI_AdjustTimespec(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset);
if (change_type == LCL_ChangeUnknownStep) { if (change_type == LCL_ChangeUnknownStep) {
@@ -225,7 +226,7 @@ REF_Initialise(void)
} }
logfileid = CNF_GetLogTracking() ? LOG_FileOpen("tracking", 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; : -1;
max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6; max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
@@ -267,6 +268,7 @@ REF_Initialise(void)
fb_drift_timeout_id = 0; fb_drift_timeout_id = 0;
} }
UTI_ZeroTimespec(&our_ref_time);
UTI_ZeroTimespec(&last_ref_update); UTI_ZeroTimespec(&last_ref_update);
last_ref_update_interval = 0.0; last_ref_update_interval = 0.0;
@@ -820,18 +822,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 static void
write_log(struct timespec *ref_time, char *ref, int stratum, NTP_Leap leap, write_log(struct timespec *now, int combined_sources, double freq,
double freq, double skew, double offset, int combined_sources, double offset, double offset_sd, double uncorrected_offset,
double offset_sd, double uncorrected_offset) double orig_root_distance)
{ {
const char leap_codes[4] = {'N', '+', '-', '?'}; const char leap_codes[4] = {'N', '+', '-', '?'};
if (logfileid != -1) { double root_dispersion, max_error;
LOG_FileWrite(logfileid, "%s %-15s %2d %10.3f %10.3f %10.3e %1c %2d %10.3e %10.3e", static double last_sys_offset = 0.0;
UTI_TimeToLogForm(ref_time->tv_sec), ref, stratum, freq, skew,
offset, leap_codes[leap], combined_sources, offset_sd, if (logfileid == -1)
uncorrected_offset); 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 +942,7 @@ REF_SetReference(int stratum,
double our_frequency; double our_frequency;
double abs_freq_ppm; double abs_freq_ppm;
double update_interval; double update_interval;
double elapsed; double elapsed, correction_rate, orig_root_distance;
double correction_rate;
double uncorrected_offset, accumulate_offset, step_offset; double uncorrected_offset, accumulate_offset, step_offset;
struct timespec now, raw_now; struct timespec now, raw_now;
NTP_int64 ref_fuzz; NTP_int64 ref_fuzz;
@@ -929,28 +955,10 @@ REF_SetReference(int stratum,
return; return;
} }
/* Guard against dividing by zero */ /* Guard against dividing by zero and NaN */
if (skew < MIN_SKEW) if (!(skew > MIN_SKEW))
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_ReadRawTime(&raw_now);
LCL_GetOffsetCorrection(&raw_now, &uncorrected_offset, NULL); LCL_GetOffsetCorrection(&raw_now, &uncorrected_offset, NULL);
UTI_AddDoubleToTimespec(&raw_now, uncorrected_offset, &now); UTI_AddDoubleToTimespec(&raw_now, uncorrected_offset, &now);
@@ -961,6 +969,8 @@ REF_SetReference(int stratum,
if (!is_offset_ok(our_offset)) if (!is_offset_ok(our_offset))
return; return;
orig_root_distance = our_root_delay / 2.0 + get_root_dispersion(&now);
are_we_synchronised = leap != LEAP_Unsynchronised ? 1 : 0; are_we_synchronised = leap != LEAP_Unsynchronised ? 1 : 0;
our_stratum = stratum + 1; our_stratum = stratum + 1;
our_ref_id = ref_id; our_ref_id = ref_id;
@@ -1071,16 +1081,8 @@ REF_SetReference(int stratum,
abs_freq_ppm = LCL_ReadAbsoluteFrequency(); abs_freq_ppm = LCL_ReadAbsoluteFrequency();
write_log(&now, write_log(&now, combined_sources, abs_freq_ppm, our_offset, offset_sd,
our_ref_ip.family != IPADDR_UNSPEC ? UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id), uncorrected_offset, orig_root_distance);
our_stratum,
our_leap_status,
abs_freq_ppm,
1.0e6*our_skew,
our_offset,
combined_sources,
offset_sd,
uncorrected_offset);
if (drift_file) { if (drift_file) {
/* Update drift file at most once per hour */ /* Update drift file at most once per hour */
@@ -1092,7 +1094,7 @@ REF_SetReference(int stratum,
} }
/* Update fallback drifts */ /* Update fallback drifts */
if (fb_drifts) { if (fb_drifts && are_we_synchronised) {
update_fb_drifts(abs_freq_ppm, update_interval); update_fb_drifts(abs_freq_ppm, update_interval);
schedule_fb_drift(&now); schedule_fb_drift(&now);
} }
@@ -1154,20 +1156,15 @@ REF_SetUnsynchronised(void)
} }
update_leap_status(LEAP_Unsynchronised, 0, 0); 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; are_we_synchronised = 0;
LCL_SetSyncStatus(0, 0.0, 0.0); LCL_SetSyncStatus(0, 0.0, 0.0);
write_log(&now, write_log(&now, 0, LCL_ReadAbsoluteFrequency(), 0.0, 0.0, uncorrected_offset,
"0.0.0.0", our_root_delay / 2.0 + get_root_dispersion(&now));
0,
our_leap_status,
LCL_ReadAbsoluteFrequency(),
1.0e6*our_skew,
0.0,
0,
0.0,
uncorrected_offset);
} }
/* ================================================== */ /* ================================================== */
@@ -1185,14 +1182,12 @@ REF_GetReferenceParams
double *root_dispersion double *root_dispersion
) )
{ {
double elapsed, dispersion; double dispersion;
assert(initialised); assert(initialised);
if (are_we_synchronised) { if (are_we_synchronised) {
elapsed = UTI_DiffTimespecsToDouble(local_time, &our_ref_time); dispersion = get_root_dispersion(local_time);
dispersion = our_root_dispersion +
(our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError()) * elapsed;
} else { } else {
dispersion = 0.0; dispersion = 0.0;
} }

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as

View File

@@ -34,7 +34,8 @@ typedef unsigned int SCH_TimeoutID;
typedef enum { typedef enum {
SCH_ReservedTimeoutValue = 0, SCH_ReservedTimeoutValue = 0,
SCH_NtpSamplingClass, SCH_NtpClientClass,
SCH_NtpPeerClass,
SCH_NtpBroadcastClass, SCH_NtpBroadcastClass,
SCH_NumberOfClasses /* needs to be last */ SCH_NumberOfClasses /* needs to be last */
} SCH_TimeoutClass; } SCH_TimeoutClass;

View File

@@ -246,6 +246,7 @@ handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
update_smoothing(cooked, doffset, dfreq); update_smoothing(cooked, doffset, dfreq);
} }
if (!UTI_IsZeroTimespec(&last_update))
UTI_AdjustTimespec(&last_update, cooked, &last_update, &delta, dfreq, doffset); UTI_AdjustTimespec(&last_update, cooked, &last_update, &delta, dfreq, doffset);
} }
@@ -264,6 +265,8 @@ void SMT_Initialise(void)
max_freq *= 1e-6; max_freq *= 1e-6;
max_wander *= 1e-6; max_wander *= 1e-6;
UTI_ZeroTimespec(&last_update);
LCL_AddParameterChangeHandler(handle_slew, NULL); 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 /* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */ 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; 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(); max_samples = CNF_GetMaxSamples();
result = MallocNew(struct SRC_Instance_Record); 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) { if (n_sources == max_n_sources) {
/* Reallocate memory */ /* Reallocate memory */

View File

@@ -59,7 +59,9 @@ typedef enum {
/* Function to create a new instance. This would be called by one of /* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */ 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. /* Function to get rid of a source when it is being unconfigured.
This may cause the current reference source to be reselected, if this 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) 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -82,6 +82,12 @@ struct SST_Stats_Record {
int min_samples; int min_samples;
int max_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 /* Number of samples currently stored. The samples are stored in circular
buffer. */ buffer. */
int n_samples; int n_samples;
@@ -197,13 +203,16 @@ SST_Finalise(void)
/* This function creates a new instance of the statistics handler */ /* This function creates a new instance of the statistics handler */
SST_Stats 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; SST_Stats inst;
inst = MallocNew(struct SST_Stats_Record); inst = MallocNew(struct SST_Stats_Record);
inst->min_samples = min_samples; inst->min_samples = min_samples;
inst->max_samples = max_samples; inst->max_samples = max_samples;
inst->fixed_min_delay = min_delay;
inst->fixed_asymmetry = asymmetry;
SST_SetRefid(inst, refid, addr); SST_SetRefid(inst, refid, addr);
SST_ResetInstance(inst); SST_ResetInstance(inst);
@@ -310,6 +319,9 @@ SST_AccumulateSample(SST_Stats inst, struct timespec *sample_time,
inst->root_dispersions[m] = root_dispersion; inst->root_dispersions[m] = root_dispersion;
inst->strata[m] = stratum; 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]) if (!inst->n_samples || inst->peer_delays[n] < inst->peer_delays[inst->min_delay_sample])
inst->min_delay_sample = n; 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 minimum network delay. This can significantly improve the accuracy and
stability of the estimated offset and frequency. */ 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 static void
correct_asymmetry(SST_Stats inst, double *times_back, double *offsets) 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; int i, n;
/* Don't try to estimate the asymmetry with reference clocks */ /* Check if the asymmetry was not specified to be zero */
if (!inst->ip_addr) if (inst->fixed_asymmetry == 0.0)
return; return;
min_delay = SST_MinRoundTripDelay(inst);
n = inst->runs_samples + inst->n_samples; n = inst->runs_samples + inst->n_samples;
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
delays[i] = inst->peer_delays[get_runsbuf_index(inst, i - inst->runs_samples)] - 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 (fabs(inst->fixed_asymmetry) <= MAX_ASYMMETRY) {
if (!RGR_MultipleRegress(times_back, delays, offsets, n, &asymmetry) || inst->asymmetry = inst->fixed_asymmetry;
asymmetry * inst->asymmetry_run < 0.0) { } else {
inst->asymmetry_run = 0; if (!estimate_asymmetry(times_back, offsets, delays, n,
inst->asymmetry = 0.0; &inst->asymmetry, &inst->asymmetry_run))
return; 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 */ /* Correct the offsets */
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
offsets[i] -= asymmetry * delays[i]; offsets[i] -= inst->asymmetry * delays[i];
inst->asymmetry = asymmetry;
} }
/* ================================================== */ /* ================================================== */
@@ -771,47 +801,33 @@ SST_PredictOffset(SST_Stats inst, struct timespec *when)
double double
SST_MinRoundTripDelay(SST_Stats inst) SST_MinRoundTripDelay(SST_Stats inst)
{ {
if (inst->fixed_min_delay > 0.0)
return inst->fixed_min_delay;
if (!inst->n_samples) if (!inst->n_samples)
return DBL_MAX; return DBL_MAX;
return inst->peer_delays[inst->min_delay_sample]; return inst->peer_delays[inst->min_delay_sample];
} }
/* ================================================== */ /* ================================================== */
int int
SST_IsGoodSample(SST_Stats inst, double offset, double delay, SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
double max_delay_dev_ratio, double clock_error, struct timespec *when) 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) if (inst->n_samples < 6)
return 1;
elapsed = UTI_DiffTimespecsToDouble(when, &inst->offset_time);
/* 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 0;
*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;
return 1;
} }
/* ================================================== */ /* ================================================== */

View File

@@ -38,7 +38,9 @@ extern void SST_Initialise(void);
extern void SST_Finalise(void); extern void SST_Finalise(void);
/* This function creates a new instance of the statistics handler */ /* 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. */ /* This function deletes an instance of the statistics handler. */
extern void SST_DeleteInstance(SST_Stats inst); 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 */ /* Find the minimum round trip delay in the register */
extern double SST_MinRoundTripDelay(SST_Stats inst); extern double SST_MinRoundTripDelay(SST_Stats inst);
/* This routine determines if a new sample is good enough that it should be /* Get data needed for testing NTP delay */
accumulated */ extern int SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
extern int SST_IsGoodSample(SST_Stats inst, double offset, double delay, double *last_sample_ago, double *predicted_offset,
double max_delay_dev_ratio, double clock_error, struct timespec *when); double *min_delay, double *skew, double *std_dev);
extern void SST_SaveToFile(SST_Stats inst, FILE *out); extern void SST_SaveToFile(SST_Stats inst, FILE *out);

View File

@@ -48,6 +48,8 @@ typedef struct {
double max_delay; double max_delay;
double max_delay_ratio; double max_delay_ratio;
double max_delay_dev_ratio; double max_delay_dev_ratio;
double min_delay;
double asymmetry;
double offset; double offset;
} SourceParameters; } SourceParameters;
@@ -63,6 +65,7 @@ typedef struct {
#define SRC_DEFAULT_MAXSOURCES 4 #define SRC_DEFAULT_MAXSOURCES 4
#define SRC_DEFAULT_MINSAMPLES (-1) #define SRC_DEFAULT_MINSAMPLES (-1)
#define SRC_DEFAULT_MAXSAMPLES (-1) #define SRC_DEFAULT_MAXSAMPLES (-1)
#define SRC_DEFAULT_ASYMMETRY 1.0
#define INACTIVE_AUTHKEY 0 #define INACTIVE_AUTHKEY 0
/* Flags for source selection */ /* Flags for source selection */

View File

@@ -4,7 +4,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009 * Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2016 * Copyright (C) Miroslav Lichvar 2009-2012, 2014-2017
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -517,7 +517,10 @@ SYS_Linux_EnableSystemCallFilter(int level)
const static unsigned long ioctls[] = { const static unsigned long ioctls[] = {
FIONREAD, TCGETS, FIONREAD, TCGETS,
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING) #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 #ifdef PTP_SYS_OFFSET_PRECISE
PTP_SYS_OFFSET_PRECISE, PTP_SYS_OFFSET_PRECISE,
#endif #endif
@@ -822,8 +825,9 @@ int
SYS_Linux_SetPHCExtTimestamping(int fd, int pin, int channel, SYS_Linux_SetPHCExtTimestamping(int fd, int pin, int channel,
int rising, int falling, int enable) int rising, int falling, int enable)
{ {
struct ptp_pin_desc pin_desc;
struct ptp_extts_request extts_req; struct ptp_extts_request extts_req;
#ifdef PTP_PIN_SETFUNC
struct ptp_pin_desc pin_desc;
memset(&pin_desc, 0, sizeof (pin_desc)); memset(&pin_desc, 0, sizeof (pin_desc));
pin_desc.index = pin; 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)); DEBUG_LOG("ioctl(%s) failed : %s", "PTP_PIN_SETFUNC", strerror(errno));
return 0; return 0;
} }
#else
DEBUG_LOG("Missing PTP_PIN_SETFUNC");
return 0;
#endif
memset(&extts_req, 0, sizeof (extts_req)); memset(&extts_req, 0, sizeof (extts_req));
extts_req.index = channel; extts_req.index = channel;

View File

@@ -4,7 +4,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2001 * Copyright (C) Richard P. Curnow 1997-2001
* Copyright (C) J. Hannken-Illjes 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as

View File

@@ -84,9 +84,18 @@ get_offset_correction(struct timespec *raw,
{ {
struct timeval remadj; struct timeval remadj;
double adjustment_remaining; 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) if (PRV_AdjustTime(NULL, &remadj) < 0)
LOG_FATAL("adjtime() failed"); LOG_FATAL("adjtime() failed");
#endif
adjustment_remaining = UTI_TimevalToDouble(&remadj); adjustment_remaining = UTI_TimevalToDouble(&remadj);

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as

View File

@@ -18,7 +18,7 @@ check_source_selection || test_fail
check_packet_interval || test_fail check_packet_interval || test_fail
check_sync || 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 run_test || test_fail
check_chronyd_exit || test_fail check_chronyd_exit || test_fail
check_packet_interval || 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)))" base_delay="(+ 1e-4 (* -1 (equal 0.1 from 2) (equal 0.1 to 1)))"
client_lpeer_options="xleave minpoll 5 maxpoll 5" client_lpeer_options="xleave minpoll 5 maxpoll 5"
client_rpeer_options="minpoll 5 maxpoll 5"
run_test || test_fail run_test || test_fail
check_chronyd_exit || 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; struct timespec start_hw_ts, start_local_ts, hw_ts, local_ts, ts;
HCL_Instance clock; HCL_Instance clock;
double freq, jitter, interval, d; double freq, jitter, interval, dj, sum;
int i, j; int i, j, count;
LCL_Initialise(); LCL_Initialise();
clock = HCL_CreateInstance(1.0); 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_hw_ts);
UTI_ZeroTimespec(&start_local_ts); UTI_ZeroTimespec(&start_local_ts);
UTI_AddDoubleToTimespec(&start_hw_ts, TST_GetRandomDouble(0.0, 1e9), &start_hw_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; clock->valid_coefs = 0;
for (j = 0; j < 100; j++) { 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); UTI_AddDoubleToTimespec(&start_local_ts, j * interval, &local_ts);
if (HCL_CookTime(clock, &hw_ts, &ts, NULL)) { if (HCL_CookTime(clock, &hw_ts, &ts, NULL)) {
d = UTI_DiffTimespecsToDouble(&ts, &local_ts); dj = fabs(UTI_DiffTimespecsToDouble(&ts, &local_ts) / jitter);
TEST_CHECK(fabs(d) <= 5.0 * 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)) if (HCL_NeedsNewSample(clock, &local_ts))
HCL_AccumulateSample(clock, &hw_ts, &local_ts, 2.0 * jitter); 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) if (!clock->valid_coefs)
continue; continue;
@@ -68,6 +74,8 @@ test_unit(void)
} }
} }
TEST_CHECK(sum / count < 0.4);
HCL_DestroyInstance(clock); HCL_DestroyInstance(clock);
LCL_Finalise(); LCL_Finalise();

View File

@@ -251,7 +251,8 @@ test_unit(void)
for (j = 0; j < 50; j++) { for (j = 0; j < 50; j++) {
DEBUG_LOG("iteration %d, %d", i, 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; authenticated = random() % 2;
valid = (!interleaved || (source.params.interleaved && has_updated)) && valid = (!interleaved || (source.params.interleaved && has_updated)) &&
(!source.params.authkey || authenticated); (!source.params.authkey || authenticated);

View File

@@ -53,7 +53,8 @@ test_unit(void)
DEBUG_LOG("added source %d options %d", j, sel_options); DEBUG_LOG("added source %d options %d", j, sel_options);
srcs[j] = SRC_CreateNewInstance(UTI_IPToRefid(&addr), SRC_NTP, sel_options, &addr, 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); SRC_UpdateReachability(srcs[j], 1);
samples = (i + j) % 5 + 3; samples = (i + j) % 5 + 3;

15
util.c
View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -610,13 +610,17 @@ UTI_SockaddrFamilyToString(int family)
char * char *
UTI_TimeToLogForm(time_t t) UTI_TimeToLogForm(time_t t)
{ {
struct tm stm; struct tm *stm;
char *result; char *result;
result = NEXT_BUFFER; result = NEXT_BUFFER;
stm = *gmtime(&t); stm = gmtime(&t);
strftime(result, BUFFER_LENGTH, "%Y-%m-%d %H:%M:%S", &stm);
if (stm)
strftime(result, BUFFER_LENGTH, "%Y-%m-%d %H:%M:%S", stm);
else
snprintf(result, BUFFER_LENGTH, "INVALID INVALID ");
return result; return result;
} }
@@ -641,6 +645,7 @@ UTI_GetNtp64Fuzz(NTP_int64 *ts, int precision)
int start, bits; int start, bits;
assert(precision >= -32 && precision <= 32); assert(precision >= -32 && precision <= 32);
assert(sizeof (*ts) == 8);
start = sizeof (*ts) - (precision + 32 + 7) / 8; start = sizeof (*ts) - (precision + 32 + 7) / 8;
ts->hi = ts->lo = 0; ts->hi = ts->lo = 0;
@@ -855,7 +860,7 @@ UTI_TimespecNetworkToHost(Timespec *src, struct timespec *dest)
#endif #endif
nsec = ntohl(src->tv_nsec); nsec = ntohl(src->tv_nsec);
dest->tv_nsec = CLAMP(0U, nsec, 999999999U); dest->tv_nsec = MIN(nsec, 999999999U);
} }
/* ================================================== */ /* ================================================== */