Compare commits

...

52 Commits

Author SHA1 Message Date
Miroslav Lichvar
5187c08c90 doc: update NEWS 2017-01-31 11:22:11 +01:00
Miroslav Lichvar
c8076ac10d makefile: fix distclean target to not print errors 2017-01-31 11:22:11 +01:00
Miroslav Lichvar
362d155558 examples: improve configuration examples 2017-01-31 11:22:11 +01:00
Miroslav Lichvar
7b7eb0a6e5 examples: improve systemd unit files
Add the PrivateTmp, ProtectHome, and ProtectSystem directives to better
secure the system from chronyd. It's taken from the Debian chrony
package.
2017-01-31 11:22:11 +01:00
Miroslav Lichvar
d96f49f67d test: add keys unit test 2017-01-31 11:22:11 +01:00
Miroslav Lichvar
43ba5d2126 doc: document rekey in chronyc man page
For some reason this useful command was never documented.
2017-01-31 11:22:11 +01:00
Miroslav Lichvar
48f7598fed client: add rekey to help text 2017-01-31 11:22:11 +01:00
Miroslav Lichvar
510b22e96b util: fix more coverity warnings
Coverity doesn't seem to like the new field in the IPAddr struct (used
as explicit padding of the structure) to be left uninitialized, even
though it's never used for anything and is cleared by memset() in
UTI_IPHostToNetwork() before leaving the process.
2017-01-31 11:22:10 +01:00
Miroslav Lichvar
0a0aff14d8 conf: add rawmeasurements log option
While the measurements log can be useful for debugging problems in NTP
configuration (e.g. authentication failures with symmetric keys), it
seems most users are interested only in valid measurements (e.g. for
producing graphs) and don't expect/handle entries where some of the RFC
5905 tests 1-7 failed. Modify the measurements log option to log only
valid measurements, and for debugging purposes add a new rawmeasurements
option.
2017-01-31 11:22:10 +01:00
Miroslav Lichvar
e225ac68bc test: update 110-chronyc 2017-01-27 11:54:12 +01:00
Miroslav Lichvar
58060c40a5 doc: improve FAQ 2017-01-27 11:45:50 +01:00
Miroslav Lichvar
2ac1b3d5c4 client: print tracking delay/dispersion in nanosecond resolution 2017-01-27 11:35:38 +01:00
Miroslav Lichvar
c174566982 ntp: check supported flags before enabling HW timestamping 2017-01-27 11:35:38 +01:00
Miroslav Lichvar
60fca19d40 ntp: log info message when HW timestamping is enabled 2017-01-27 10:55:28 +01:00
Miroslav Lichvar
8bcb15b02f doc: improve description of some server options 2017-01-27 10:55:28 +01:00
Miroslav Lichvar
65c2cebcd5 reference: report zero root dispersion with local reference
The server's precision is supposed to be included in client's
dispersion. Don't include it in the server's dispersion.
2017-01-27 10:55:28 +01:00
Miroslav Lichvar
2a51b45a43 test: fix memory leaks in unit tests 2017-01-27 10:55:28 +01:00
Miroslav Lichvar
5ac791665e doc: update NEWS 2017-01-24 15:03:24 +01:00
Miroslav Lichvar
a4e3f83611 update copyright years 2017-01-24 15:01:38 +01:00
Miroslav Lichvar
8a837f9c2b test: extend 119-smoothtime 2017-01-23 16:17:39 +01:00
Miroslav Lichvar
da2d33e9a8 ntp: fix time smoothing in interleaved mode
When the server's transmit timestamp was updated with a kernel/HW
timestamp, it didn't include the time smoothing offset. If the offset
was larger than one second, the update failed and clients using the
interleaved mode received less accurate timestamps. If the update
succeeded, the clients received timestamps that were not adjusted for
the time smoothing offset, which added an error of up to 0.5s/1s to
their measured offset/delay.

Fix the update to include the smoothing offset in the new timestamp.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
4b98dadae9 ntp: simplify UTI_Ntp64ToTimespec() callers
Since UTI_Ntp64ToTimespec() was modified to handle zero timestamps, some
of its callers don't need to do that anymore.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
86acea5c46 ntp: add interface index to NTP_Local_Address
This will allow us to get the interface index when sending responses to
clients.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
a60fc73e7b refclock_phc: add nocrossts option 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
50f99ec5f4 conf: add nocrossts option to hwtimestamp directive
This option disables the use of the PTP_SYS_OFFSET_PRECISE ioctl.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
31b6a14444 sys_linux: add support for PTP_SYS_OFFSET_PRECISE
This is for hardware that can precisely cross timestamp the PHC with the
system clock.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
9df4d36157 refclock_phc: use sys_linux code for reading PHC
This drops support for non-ioctl reading of PHC.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
b70f0b674f ntp: move PHC-specific code to sys_linux
This will allow sharing of the code with the PHC refclock driver.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
510784077f conf: add minpoll option to hwtimestamp directive 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
9800e397fb hwclock: make minimum sampling separation configurable 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
1436d9961f conf: add precision option to hwtimestamp directive 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
98f5d05925 ntp: include precision of PHC readings in their selection
Include a fixed non-zero precision (100 nanosecond) in the selection of
PHC readings.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
7a937c7652 conf: return hwtimestamp data in struct 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
b198d76676 ntp: include precision in maxdelay test 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
97d4203354 ntp: adapt sampling separation for short polling intervals 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
beaaaad162 ntp: allow sub-second polling intervals
Change the minimum minpoll to -4, but keep the minimum maxpoll at 0 in
order to not make it too easy to flood distant servers.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
4e78975909 ntp: use current poll when backing off on KoD RATE 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
99147ed8f2 ntp: rename maxdelay constants 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
dec0d3bfc2 ntp: reset ntpdata report on address change 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
cd84c99e70 examples: improve chronyd.service 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
d5c507975c doc: update README 2017-01-12 16:34:28 +01:00
Miroslav Lichvar
b4235abd36 update copyright years 2017-01-12 16:34:28 +01:00
Miroslav Lichvar
1966085a97 test: add ntp_core unit test 2017-01-12 16:34:28 +01:00
Miroslav Lichvar
e31e7af48f test: make 119-smoothtime more reliable 2017-01-12 16:34:28 +01:00
Miroslav Lichvar
adb9123fc3 test: extend util unit test 2017-01-12 16:34:28 +01:00
Miroslav Lichvar
b0f7efd59e util: handle zero in conversion of NTP timestamps
Handle zero NTP timestamp in UTI_Ntp64ToTimespec() as a special value to
make it symmetric with UTI_TimespecToNtp64(). This is needed since
commit d75f6830f1, in which a timestamp is
converted back and forth without checking for zero.

It also makes zero NTP timestamps more apparent in debug output.
2017-01-12 16:34:28 +01:00
Miroslav Lichvar
e28dfada8c rtc: check for backward RTC steps
When accumulating a new sample, check if the new RTC time is newer the
last sample time. If it is not, discard all previous samples, assuming
something has stepped the RTC, or it's a broken RTC/driver.
2017-01-12 16:34:28 +01:00
Miroslav Lichvar
ac0b28cce6 sourcestats: align sample time used for source report
This reduces leak of sample times (and receive timestamps which are
related to sample times), which could be useful in off-path attacks on
unauthenticated symmetric interleaved mode.
2017-01-12 16:34:28 +01:00
Miroslav Lichvar
48b16ae66c local: add assertion for precision 2017-01-12 16:34:28 +01:00
Miroslav Lichvar
061579ec28 ntp: don't send packets with RX equal to TX
Before sending an NTP packet, check whether the TX timestamp is not
equal to the RX timestamp. If it is, generate a new TX timestamp and try
again. This is extremely unlikely to happen in normal operation, but it
is needed for reliable detection of the interleaved mode.
2017-01-12 16:34:28 +01:00
Miroslav Lichvar
f2f834e7e7 ntp: limit maxdelay parameters 2017-01-12 16:34:27 +01:00
Miroslav Lichvar
a7802e9a76 fix some coverity warnings 2017-01-12 16:34:27 +01:00
46 changed files with 1113 additions and 448 deletions

View File

@@ -64,10 +64,10 @@ chronyc : $(CLI_OBJS)
$(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_CLI_LIBS)
distclean : clean
-rm -f .DS_Store
-rm -f Makefile config.h config.log
$(MAKE) -C doc distclean
$(MAKE) -C test/unit distclean
-rm -f .DS_Store
-rm -f Makefile config.h config.log
clean :
-rm -f *.o *.s chronyc chronyd core *~

15
NEWS
View File

@@ -1,3 +1,18 @@
New in version 3.1
==================
Enhancements
------------
* Add support for precise cross timestamping of PHC on Linux
* Add minpoll, precision, nocrossts options to hwtimestamp directive
* Add rawmeasurements option to log directive and modify measurements
option to log only valid measurements from synchronised sources
* Allow sub-second polling interval with NTP sources
Bug fixes
---------
* Fix time smoothing in interleaved mode
New in version 3.0
==================

5
README
View File

@@ -16,7 +16,7 @@ and systems that do not run continuosly, or run on a virtual machine.
Typical accuracy between two machines synchronised over the Internet is
within a few milliseconds; on a LAN, accuracy is typically in tens of
microseconds. With hardware timestamping or a hardware reference clock
microseconds. With hardware timestamping, or a hardware reference clock,
sub-microsecond accuracy may be possible.
Two programs are included in chrony, chronyd is a daemon that can be
@@ -203,6 +203,9 @@ Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
Frank Otto <sandwichmacher@web.de>
Handling arbitrary HZ values
Denny Page <dennypage@me.com>
Advice on support for hardware timestamping
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
Patch to add refresh command to chronyc

View File

@@ -50,8 +50,11 @@ typedef struct {
unsigned short port;
} NTP_Remote_Address;
#define INVALID_IF_INDEX -1
typedef struct {
IPAddr ip_addr;
int if_index;
int sock_fd;
} NTP_Local_Address;

View File

@@ -3,6 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Lonnie Abelbeck 2016
* Copyright (C) Miroslav Lichvar 2009-2016
*
* This program is free software; you can redistribute it and/or modify
@@ -1241,6 +1242,7 @@ give_help(void)
"Other daemon commands:\0\0"
"cyclelogs\0Close and re-open log files\0"
"dump\0Dump all measurements to save files\0"
"rekey\0Re-read keys from key file\0"
"\0\0"
"Client commands:\0\0"
"dns -n|+n\0Disable/enable resolving IP addresses to hostnames\0"
@@ -2214,8 +2216,8 @@ process_cmd_tracking(char *line)
"Frequency : %.3F\n"
"Residual freq : %+.3f ppm\n"
"Skew : %.3f ppm\n"
"Root delay : %.6f seconds\n"
"Root dispersion : %.6f seconds\n"
"Root delay : %.9f seconds\n"
"Root dispersion : %.9f seconds\n"
"Update interval : %.1f seconds\n"
"Leap status : %L\n",
(unsigned long)ref_id, name,
@@ -2723,7 +2725,8 @@ process_cmd_waitsync(char *line)
max_skew_ppm = 0.0;
interval = 10.0;
sscanf(line, "%d %lf %lf %lf", &max_tries, &max_correction, &max_skew_ppm, &interval);
if (sscanf(line, "%d %lf %lf %lf", &max_tries, &max_correction, &max_skew_ppm, &interval))
;
/* Don't allow shorter interval than 0.1 seconds */
if (interval < 0.1)
@@ -2831,7 +2834,8 @@ process_cmd_keygen(char *line)
snprintf(hash_name, sizeof (hash_name), "MD5");
#endif
sscanf(line, "%u %16s %d", &id, hash_name, &bits);
if (sscanf(line, "%u %16s %d", &id, hash_name, &bits))
;
length = CLAMP(10, (bits + 7) / 8, sizeof (key));
if (HSH_GetHashId(hash_name) < 0) {
@@ -3094,7 +3098,7 @@ static void
display_gpl(void)
{
printf("chrony version %s\n"
"Copyright (C) 1997-2003, 2007, 2009-2016 Richard P. Curnow and others\n"
"Copyright (C) 1997-2003, 2007, 2009-2017 Richard P. Curnow and others\n"
"chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n"
"you are welcome to redistribute it under certain conditions. See the\n"
"GNU General Public License version 2 for details.\n\n",

49
conf.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2016
* Copyright (C) Miroslav Lichvar 2009-2017
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -97,6 +97,7 @@ static double combine_limit = 3.0;
static int cmd_port = DEFAULT_CANDM_PORT;
static int raw_measurements = 0;
static int do_log_measurements = 0;
static int do_log_statistics = 0;
static int do_log_tracking = 0;
@@ -223,13 +224,7 @@ static char *leapsec_tz = NULL;
/* Name of the user to which will be dropped root privileges. */
static char *user;
typedef struct {
char *name;
double tx_comp;
double rx_comp;
} HwTs_Interface;
/* Array of HwTs_Interface */
/* Array of CNF_HwTsInterface */
static ARR_Instance hwts_interfaces;
typedef struct {
@@ -333,7 +328,7 @@ CNF_Initialise(int r)
{
restarted = r;
hwts_interfaces = ARR_CreateInstance(sizeof (HwTs_Interface));
hwts_interfaces = ARR_CreateInstance(sizeof (CNF_HwTsInterface));
init_sources = ARR_CreateInstance(sizeof (IPAddr));
ntp_sources = ARR_CreateInstance(sizeof (NTP_Source));
@@ -360,7 +355,7 @@ CNF_Finalise(void)
unsigned int i;
for (i = 0; i < ARR_GetSize(hwts_interfaces); i++)
Free(((HwTs_Interface *)ARR_GetElement(hwts_interfaces, i))->name);
Free(((CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, i))->name);
ARR_DestroyInstance(hwts_interfaces);
for (i = 0; i < ARR_GetSize(ntp_sources); i++)
@@ -820,7 +815,10 @@ parse_log(char *line)
log_name = line;
line = CPS_SplitWord(line);
if (*log_name) {
if (!strcmp(log_name, "measurements")) {
if (!strcmp(log_name, "rawmeasurements")) {
do_log_measurements = 1;
raw_measurements = 1;
} else if (!strcmp(log_name, "measurements")) {
do_log_measurements = 1;
} else if (!strcmp(log_name, "statistics")) {
do_log_statistics = 1;
@@ -1251,7 +1249,7 @@ parse_tempcomp(char *line)
static void
parse_hwtimestamp(char *line)
{
HwTs_Interface *iface;
CNF_HwTsInterface *iface;
char *p;
int n;
@@ -1265,18 +1263,30 @@ parse_hwtimestamp(char *line)
iface = ARR_GetNewElement(hwts_interfaces);
iface->name = Strdup(p);
iface->minpoll = 0;
iface->nocrossts = 0;
iface->precision = 100.0e-9;
iface->tx_comp = 0.0;
iface->rx_comp = 0.0;
for (p = line; *p; line += n, p = line) {
line = CPS_SplitWord(line);
if (!strcasecmp(p, "rxcomp")) {
if (!strcasecmp(p, "minpoll")) {
if (sscanf(line, "%d%n", &iface->minpoll, &n) != 1)
break;
} else if (!strcasecmp(p, "precision")) {
if (sscanf(line, "%lf%n", &iface->precision, &n) != 1)
break;
} else if (!strcasecmp(p, "rxcomp")) {
if (sscanf(line, "%lf%n", &iface->rx_comp, &n) != 1)
break;
} else if (!strcasecmp(p, "txcomp")) {
if (sscanf(line, "%lf%n", &iface->tx_comp, &n) != 1)
break;
} else if (!strcasecmp(p, "nocrossts")) {
n = 0;
iface->nocrossts = 1;
} else {
break;
}
@@ -1462,8 +1472,9 @@ CNF_GetDumpDir(void)
/* ================================================== */
int
CNF_GetLogMeasurements(void)
CNF_GetLogMeasurements(int *raw)
{
*raw = raw_measurements;
return do_log_measurements;
}
@@ -1968,17 +1979,11 @@ CNF_GetInitStepThreshold(void)
/* ================================================== */
int
CNF_GetHwTsInterface(unsigned int index, char **name, double *tx_comp, double *rx_comp)
CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface)
{
HwTs_Interface *iface;
if (index >= ARR_GetSize(hwts_interfaces))
return 0;
iface = ARR_GetElement(hwts_interfaces, index);
*name = iface->name;
*tx_comp = iface->tx_comp;
*rx_comp = iface->rx_comp;
*iface = (CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, index);
return 1;
}

13
conf.h
View File

@@ -52,7 +52,7 @@ extern char *CNF_GetDriftFile(void);
extern char *CNF_GetLogDir(void);
extern char *CNF_GetDumpDir(void);
extern int CNF_GetLogBanner(void);
extern int CNF_GetLogMeasurements(void);
extern int CNF_GetLogMeasurements(int *raw);
extern int CNF_GetLogStatistics(void);
extern int CNF_GetLogTracking(void);
extern int CNF_GetLogRtc(void);
@@ -119,6 +119,15 @@ extern char *CNF_GetHwclockFile(void);
extern int CNF_GetInitSources(void);
extern double CNF_GetInitStepThreshold(void);
extern int CNF_GetHwTsInterface(unsigned int index, char **name, double *tx_comp, double *rx_comp);
typedef struct {
char *name;
int minpoll;
int nocrossts;
double precision;
double tx_comp;
double rx_comp;
} CNF_HwTsInterface;
extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
#endif /* GOT_CONF_H */

5
configure vendored
View File

@@ -4,7 +4,8 @@
# chronyd/chronyc - Programs for keeping computer clocks accurate.
#
# Copyright (C) Richard P. Curnow 1997-2003
# Copyright (C) Miroslav Lichvar 2009, 2012-2015
# Copyright (C) Bryan Christianson 2016
# Copyright (C) Miroslav Lichvar 2009, 2012-2016
#
# =======================================================================
@@ -731,7 +732,7 @@ fi
if [ $feat_refclock = "1" ] && [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
grep '#define HAVE_CLOCK_GETTIME' config.h > /dev/null && \
test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
'ioctl(1, PTP_CLOCK_GETCAPS, 0);'
'ioctl(1, PTP_CLOCK_GETCAPS + PTP_SYS_OFFSET, 0);'
then
add_def FEAT_PHC
fi

View File

@@ -1,7 +1,8 @@
// This file is part of chrony
//
// Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Miroslav Lichvar 2009-2016
// Copyright (C) Stephen Wadeley 2016
// Copyright (C) Miroslav Lichvar 2009-2017
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of version 2 of the GNU General Public License as
@@ -67,11 +68,15 @@ options:
Although *chronyd* will trim the rate at which it samples the server during
normal operation, the user might want to constrain the minimum polling interval.
This is always defined as a power of 2, so *minpoll 5* would mean that the
polling interval cannot drop below 32 seconds. The default is 6 (64 seconds).
polling interval cannot drop below 32 seconds. The default is 6 (64 seconds),
the minimum is -4 (1/16th of a second), and the maximum is 24 (6 months). Note
that intervals shorter than 6 (64 seconds) should generally not be used with
public servers on the Internet, because it might be considered abuse.
*maxpoll* _poll_:::
In a similar way, the user might want to constrain the maximum polling interval.
Again this is specified as a power of 2, *maxpoll 9* indicates that the polling
interval must stay at or below 512 seconds. The default is 10 (1024 seconds).
interval must stay at or below 512 seconds. The default is 10 (1024 seconds),
the minimum is 0 (1 second), and the maximum is 24 (6 months).
*iburst*:::
If this option is set, the interval between the first four polls will be 2
seconds instead of _minpoll_. This is useful to quickly get the first update of
@@ -105,7 +110,7 @@ If the user knows that round trip delays above a certain level should cause the
measurement to be ignored, this level can be defined with the *maxdelay*
option. For example, *maxdelay 0.3* would indicate that measurements with a
round-trip delay of 0.3 seconds or more should be ignored. The default value is
3 seconds.
3 seconds and the maximum value is 1000 seconds.
*maxdelayratio* _ratio_:::
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
@@ -171,9 +176,12 @@ the interleaved mode requires the servers to keep some state for each client
and the state might be dropped when there are too many clients (e.g.
<<clientloglimit,*clientloglimit*>> is too small), or it might be overwritten
by other clients that have the same IP address (e.g. computers behind NAT or
someone sending requests with a spoofed source address). The *presend* option
can be used to shorten the interval in which the server has to keep the state
for this computer and be able to respond in the interleaved mode.
someone sending requests with a spoofed source address).
+
With longer polling intervals, it is recommended to combine the *xleave* option
with the *presend* option in order to shorten the interval in which the server
has to keep the state to be able to respond in the interleaved mode. The
shorter interval also improves accuracy of the measured offset and delay.
*polltarget* _target_:::
Target number of measurements to use for the regression algorithm which
*chronyd* will try to maintain by adjusting the polling interval between
@@ -397,9 +405,10 @@ refclock SOCK /var/run/chrony.ttyS0.sock
*PHC*:::
PTP hardware clock (PHC) driver. The parameter is the path to the device of
the PTP clock, which for example can be synchronised by *ptp4l* from
http://linuxptp.sourceforge.net[*linuxptp*]. PTP clocks are typically kept in
TAI instead of UTC, so the *offset* option should be used to compensate for the
current UTC-TAI offset. For example:
http://linuxptp.sourceforge.net[*linuxptp*]. String *:nocrossts* can be
appended to the path to disable use of precise cross timestamping. PTP clocks
are typically kept in TAI instead of UTC, so the *offset* option should be used
to compensate for the current UTC-TAI offset. For example:
+
----
refclock PHC /dev/ptp0 poll 3 dpoll -2 offset -36
@@ -1509,10 +1518,12 @@ The log files are written to the directory specified by the <<logdir,*logdir*>>
directive. A banner is periodically written to the files to indicate the
meanings of the columns.
+
*measurements*:::
*rawmeasurements*:::
This option logs the raw NTP measurements and related information to a file
called _measurements.log_. An example line (which actually appears as a single
line in the file) from the log file is shown below.
called _measurements.log_. An entry is made for each packet received from the
source. This can be useful when debugging a problem. An example line (which
actually appears as a single line in the file) from the log file is shown
below.
+
----
2016-11-09 05:40:50 203.0.113.15 N 2 111 111 1111 10 10 1.0 \
@@ -1554,6 +1565,12 @@ from the example line above):
. Source of the local receive timestamp
(_D_=daemon, _K_=kernel, _H_=hardware). [K]
+
*measurements*:::
This option is identical to the *rawmeasurements* option, except it logs only
valid measurements from synchronised sources, i.e. measurements which passed
the RFC 5905 tests 1 through 7. This can be useful for producing graphs of the
source's performance.
+
*statistics*:::
This option logs information about the regression processing to a file called
_statistics.log_. An example line (which actually appears as a single line in
@@ -1813,6 +1830,15 @@ on all available interfaces.
+
The *hwtimestamp* directive has the following options:
+
*minpoll* _poll_:::
This option specifies the minimum interval between readings of the NIC clock.
It's defined as a power of two. It should correspond to the minimum polling
interval of all NTP sources and the minimum expected polling interval of NTP
clients. The default value is 0 (1 second) and the minimum value is -6 (1/64th
of a second).
*precision* _precision_:::
This option specifies the assumed precision of reading of the NIC clock. The
default value is 100e-9 (100 nanoseconds).
*txcomp* _compensation_:::
This option specifies the difference in seconds between the actual transmission
time at the physical layer and the reported transmit timestamp. This value will
@@ -1822,6 +1848,9 @@ This option specifies the difference in seconds between the reported receive
timestamp and the actual reception time at the physical layer. This value will
be subtracted from receive timestamps obtained from the NIC. The default value
is 0.
*nocrossts*:::
Some hardware can precisely cross timestamp the NIC clock with the system
clock. This option disables the use of the cross timestamping.
::
+
Examples of the directive are:

View File

@@ -1,6 +1,7 @@
// This file is part of chrony
//
// Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Stephen Wadeley 2016
// Copyright (C) Miroslav Lichvar 2009-2016
//
// This program is free software; you can redistribute it and/or modify
@@ -129,15 +130,15 @@ performance. An example of the output is shown below.
----
Reference ID : CB00710F (foo.example.net)
Stratum : 3
Ref time (UTC) : Fri Feb 3 15:00:29 2012
System time : 0.000001501 seconds slow of NTP time
Last offset : -0.000001632 seconds
RMS offset : 0.000002360 seconds
Frequency : 331.898 ppm fast
Residual freq : 0.004 ppm
Skew : 0.154 ppm
Root delay : 0.373169 seconds
Root dispersion : 0.024780 seconds
Ref time (UTC) : Fri Jan 27 09:49:17 2017
System time : 0.000006523 seconds slow of NTP time
Last offset : -0.000006747 seconds
RMS offset : 0.000035822 seconds
Frequency : 3.225 ppm slow
Residual freq : -0.000 ppm
Skew : 0.129 ppm
Root delay : 0.013639022 seconds
Root dispersion : 0.001100737 seconds
Update interval : 64.2 seconds
Leap status : Normal
----
@@ -186,9 +187,6 @@ The '`frequency`' is the rate by which the system's clock would be wrong if
For example, a value of 1 ppm would mean that when the system's clock thinks it
has advanced 1 second, it has actually advanced by 1.000001 seconds relative to
true time.
+
As you can see in the example, the clock in the computer is not a very
good one; it would gain about 30 seconds per day if it was not corrected!
*Residual freq*:::
This shows the '`residual frequency`' for the currently selected reference
source. This reflects any difference between what the measurements from the
@@ -1132,6 +1130,10 @@ directory into which the dump files will be written. This can only be
done in the configuration file with the <<chrony.conf.adoc#dumpdir,*dumpdir*>>
directive.
[[rekey]]*rekey*::
The *rekey* command causes *chronyd* to re-read the key file specified in the
configuration file by the <<chrony.conf.adoc#keyfile,*keyfile*>> directive.
=== Client commands
[[dns]]*dns* _option_::

View File

@@ -79,7 +79,7 @@ rtcsync
You need to add an `allow` directive to the _chrony.conf_ file in order to open
the NTP port and allow `chronyd` to reply to client requests. `allow` with no
specified subnet allows all IPv4 and IPv6 addresses.
specified subnet allows access from all IPv4 and IPv6 addresses.
=== I have several computers on a LAN. Should be all clients of an external server?
@@ -97,7 +97,7 @@ _chrony.conf_ file. This configuration will be better because
No. Starting from version 1.25, `chronyd` will keep trying to resolve
the names specified by the `server`, `pool`, and `peer` directives in an
increasing interval until it succeeds. The `online` command can be issued from
`chronyc` to try to resolve them immediately.
`chronyc` to force `chronyd` to try to resolve the names immediately.
=== How can I make `chronyd` more secure?
@@ -161,7 +161,7 @@ The first three options set the minimum and maximum allowed polling interval,
and how should be the actual interval adjusted in the specified range. Their
default values are 6 (64 seconds) for `minpoll`, 10 (1024 seconds) for
`maxpoll` and 8 (samples) for `polltarget`. The default values should be used
for general servers on the Internet. With your own NTP servers or if have
for general servers on the Internet. With your own NTP servers, or if you have
permission to poll some servers more frequently, setting these options for
shorter polling intervals may significantly improve the accuracy of the system
clock.
@@ -195,15 +195,27 @@ server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
----
If your server supports the interleaved mode, the `xleave` option should be
added to the `server` directive in order to receive server's more accurate
hardware or kernel transmit timestamps. When combined with local hardware
timestamping, a sub-microsecond accuracy may be possible. An example could be
added to the `server` directive in order to allow the server to send the
client more accurate hardware or kernel transmit timestamps. When combined with
local hardware timestamping, sub-microsecond accuracy may be possible. An
example could be
----
server ntp.local minpoll 2 maxpoll 2 xleave
hwtimestamp eth0
----
=== Does `chronyd` have an ntpdate mode?
Yes. With the `-q` option `chronyd` will set the system clock once and exit.
With the `-Q` option it will print the measured offset without setting the
clock. If you don't want to use a configuration file, NTP servers can be
specified on the command line. For example:
----
# chronyd -q 'pool pool.ntp.org iburst'
----
=== What happened to the `commandkey` and `generatecommandkey` directives?
They were removed in version 2.2. Authentication is no longer supported in the
@@ -242,8 +254,17 @@ MS Name/IP address Stratum Poll Reach LastRx Last sample
=== Are NTP servers specified with the `offline` option?
Check that you're using ``chronyc``'s `online` and `offline` commands
appropriately. Again, check in _measurements.log_ to see if you're getting any
data back from the server.
appropriately. The `activity` command prints the number of sources that are
currently online and offline. For example:
----
200 OK
3 sources online
0 sources offline
0 sources doing burst (return to online)
0 sources doing burst (return to offline)
0 sources with unknown address
----
=== Is `chronyd` allowed to step the system clock?
@@ -396,15 +417,15 @@ option for all time sources in the _chrony.conf_ file.
=== What happens if the network connection is dropped without using ``chronyc``'s `offline` command first?
`chronyd` will keep trying to access the server(s) that it thinks are online.
When the network is connected again, it will take some time (on average half of
the maximum polling interval) before new measurements are made and the clock is
corrected. If the servers were set to offline and the `online` command was
issued when the network was connected, `chronyd` would make new measurements
immediately.
`chronyd` will keep trying to access the sources that it thinks are online, and
it will take longer before new measurements are actually made and the clock is
corrected when the network is connected again. If the sources were set to
offline, `chronyd` would make new measurements immediately after issuing the
`online` command.
The `auto_offline` option to the `server` entry in the _chrony.conf_ file may
be useful to switch the servers to the offline state automatically.
Unless the network connection lasts only few minutes (less than the maximum
polling interval), the delay is usually not a problem, and it may be acceptable
to keep all sources online all the time.
== Operating systems

View File

@@ -1,5 +1,6 @@
[Unit]
Description=Wait for chrony to synchronize system clock
Documentation=man:chronyc(1)
After=chronyd.service
Requires=chronyd.service
Before=time-sync.target

View File

@@ -4,8 +4,8 @@ pool pool.ntp.org iburst
# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift
# In first three updates step the system clock instead of slew
# if the adjustment is larger than 1 second.
# Allow the system clock to be stepped in the first three updates
# if its offset is larger than 1 second.
makestep 1.0 3
# Enable kernel synchronization of the real-time clock (RTC).

View File

@@ -5,17 +5,24 @@ pool pool.ntp.org iburst
# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift
# In first three updates step the system clock instead of slew
# if the adjustment is larger than 1 second.
# Allow the system clock to be stepped in the first three updates
# if its offset is larger than 1 second.
makestep 1.0 3
# Enable kernel synchronization of the real-time clock (RTC).
rtcsync
# Allow NTP client access from local network.
#allow 192.168/16
# Enable hardware timestamping on all interfaces that support it.
#hwtimestamp *
# Serve time even if not synchronized to any NTP server.
# Increase the minimum number of selectable sources required to adjust
# the system clock.
#minsources 2
# Allow NTP client access from local network.
#allow 192.168.0.0/16
# Serve time even if not synchronized to a time source.
#local stratum 10
# Specify file containing keys for NTP authentication.

View File

@@ -33,42 +33,30 @@
! pool pool.ntp.org iburst
# However, for dial-up use you probably want these instead. The word
# 'offline' means that the server is not visible at boot time. Use
# chronyc's 'online' command to tell chronyd that these servers have
# become visible after you go on-line.
! server foo.example.net offline
! server bar.example.net offline
! server baz.example.net offline
! pool pool.ntp.org offline
# You may want to specify NTP 'peers' instead. If you run a network
# with a lot of computers and want several computers running chrony to
# have the 'front-line' interface to the public NTP servers, you can
# 'peer' these machines together to increase robustness.
! peer foo.example.net
# There are other options to the 'server' and 'peer' directives that you
# might want to use. For example, you can ignore measurements whose
# round-trip-time is too large (indicating that the measurement is
# probably useless, because you don't know which way the measurement
# message got held up.) Consult the full documentation for details.
#######################################################################
### AVOIDING POTENTIALLY BOGUS CHANGES TO YOUR CLOCK
#
# To avoid changes being made to your computer's gain/loss compensation
# when the measurement history is too erratic, you might want to enable
# one of the following lines. The first seems good for dial-up (or
# other high-latency connections like slow leased lines), the second
# seems OK for a LAN environment.
# one of the following lines. The first seems good with servers on the
# Internet, the second seems OK for a LAN environment.
! maxupdateskew 100
! maxupdateskew 5
# If you want to increase the minimum number of selectable sources
# required to update the system clock in order to make the
# synchronisation more reliable, uncomment (and edit) the following
# line.
! minsources 2
# If your computer has a good stable clock (e.g. it is not a virtual
# machine), you might also want to reduce the maximum assumed drift
# (frequency error) of the clock (the value is specified in ppm).
! maxdrift 100
#######################################################################
### FILENAMES ETC
# Chrony likes to keep information about your computer's clock in files.
@@ -181,13 +169,12 @@ driftfile /var/lib/chrony/drift
# machine accesses it. The information can be accessed by the 'clients'
# command of chronyc. You can disable this facility by uncommenting the
# following line. This will save a bit of memory if you have many
# clients.
# clients and it will also disable support for the interleaved mode.
! noclientlog
# The clientlog size is limited to 512KB by default. If you have many
# clients, especially in many different subnets, you might want to
# increase the limit.
# clients, you might want to increase the limit.
! clientloglimit 4194304
@@ -196,7 +183,7 @@ driftfile /var/lib/chrony/drift
# clients that are sending requests too frequently, uncomment and edit
# the following line.
! limitrate interval 3 burst 8
! ratelimit interval 3 burst 8
#######################################################################
### REPORTING BIG CLOCK CHANGES
@@ -243,7 +230,17 @@ driftfile /var/lib/chrony/drift
# Rate limiting can be enabled also for command packets. (Note,
# commands from localhost are never limited.)
! cmdratelimit interval 1 burst 16
! cmdratelimit interval -4 burst 16
#######################################################################
### HARDWARE TIMESTAMPING
# On Linux, if the network interface controller and its driver support
# hardware timestamping, it can significantly improve the accuracy of
# synchronisation. It can be enabled on specified interfaces only, or it
# can be enabled on all interfaces that support it.
! hwtimestamp eth0
! hwtimestamp *
#######################################################################
### REAL TIME CLOCK
@@ -274,6 +271,12 @@ driftfile /var/lib/chrony/drift
! rtcdevice /dev/misc/rtc
# Alternatively, if not using the -s option, this directive can be used
# to enable a mode in which the RTC is periodically set to the system
# time, with no tracking of its drift.
! rtcsync
#######################################################################
### REAL TIME SCHEDULER
# This directive tells chronyd to use the real-time FIFO scheduler with the

View File

@@ -1,13 +1,18 @@
[Unit]
Description=NTP client/server
Documentation=man:chronyd(8) man:chrony.conf(5)
After=ntpdate.service sntp.service ntpd.service
Conflicts=ntpd.service systemd-timesyncd.service
ConditionCapability=CAP_SYS_TIME
[Service]
Type=forking
PIDFile=/var/run/chronyd.pid
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd $OPTIONS
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=full
[Install]
WantedBy=multi-user.target

View File

@@ -39,9 +39,6 @@
/* Maximum number of samples per clock */
#define MAX_SAMPLES 16
/* Minimum interval between samples (in seconds) */
#define MIN_SAMPLE_SEPARATION 1.0
struct HCL_Instance_Record {
/* HW and local reference timestamp */
struct timespec hw_ref;
@@ -58,6 +55,9 @@ struct HCL_Instance_Record {
/* Maximum error of the last sample */
double last_err;
/* Minimum interval between samples */
double min_separation;
/* Flag indicating the offset and frequency values are valid */
int valid_coefs;
@@ -86,7 +86,7 @@ handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
/* ================================================== */
HCL_Instance
HCL_CreateInstance(void)
HCL_CreateInstance(double min_separation)
{
HCL_Instance clock;
@@ -95,6 +95,7 @@ HCL_CreateInstance(void)
clock->y_data[MAX_SAMPLES - 1] = 0.0;
clock->n_samples = 0;
clock->valid_coefs = 0;
clock->min_separation = min_separation;
LCL_AddParameterChangeHandler(handle_slew, clock);
@@ -115,7 +116,7 @@ int
HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now)
{
if (!clock->n_samples ||
fabs(UTI_DiffTimespecsToDouble(now, &clock->local_ref)) >= MIN_SAMPLE_SEPARATION)
fabs(UTI_DiffTimespecsToDouble(now, &clock->local_ref)) >= clock->min_separation)
return 1;
return 0;
@@ -140,7 +141,7 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
hw_delta = UTI_DiffTimespecsToDouble(hw_ts, &clock->hw_ref);
local_delta = UTI_DiffTimespecsToDouble(local_ts, &clock->local_ref) / local_freq;
if (hw_delta <= 0.0 || local_delta < MIN_SAMPLE_SEPARATION / 2.0) {
if (hw_delta <= 0.0 || local_delta < clock->min_separation / 2.0) {
clock->n_samples = 0;
DEBUG_LOG(LOGF_HwClocks, "HW clock reset interval=%f", local_delta);
}

View File

@@ -29,7 +29,7 @@
typedef struct HCL_Instance_Record *HCL_Instance;
/* Create a new HW clock instance */
extern HCL_Instance HCL_CreateInstance(void);
extern HCL_Instance HCL_CreateInstance(double min_separation);
/* Destroy a HW clock instance */
extern void HCL_DestroyInstance(HCL_Instance clock);

View File

@@ -144,6 +144,8 @@ calculate_sys_precision(void)
best *= 2;
}
assert(precision_log >= -30);
DEBUG_LOG(LOGF_Local, "Clock precision %.9f (%d)", precision_quantum, precision_log);
}

5
main.c
View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2012-2015
* Copyright (C) Miroslav Lichvar 2012-2016
*
* 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
@@ -325,7 +325,8 @@ go_daemon(void)
if (r) {
if (r > 0) {
/* Print the error message from the child */
fprintf(stderr, "%.1024s\n", message);
message[sizeof (message) - 1] = '\0';
fprintf(stderr, "%s\n", message);
}
exit(1);
} else

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2016
* Copyright (C) Miroslav Lichvar 2009-2017
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -49,6 +49,7 @@
/* ================================================== */
static LOG_FileID logfileid;
static int log_raw_measurements;
/* ================================================== */
/* Enumeration used for remembering the operating mode of one of the
@@ -205,7 +206,8 @@ static ARR_Instance broadcasts;
/* Spacing required between samples for any two servers/peers (to
minimise risk of network collisions) (in seconds) */
#define SAMPLING_SEPARATION 0.2
#define MIN_SAMPLING_SEPARATION 0.02
#define MAX_SAMPLING_SEPARATION 0.2
/* Randomness added to spacing between samples for one server/peer */
#define SAMPLING_RANDOMNESS 0.02
@@ -243,8 +245,14 @@ static ARR_Instance broadcasts;
/* Maximum acceptable delay in transmission for timestamp correction */
#define MAX_TX_DELAY 1.0
/* Maximum allowed values of maxdelay parameters */
#define MAX_MAXDELAY 1.0e3
#define MAX_MAXDELAYRATIO 1.0e6
#define MAX_MAXDELAYDEVRATIO 1.0e6
/* Minimum and maximum allowed poll interval */
#define MIN_POLL 0
#define MIN_MINPOLL -4
#define MIN_MAXPOLL 0
#define MAX_POLL 24
/* Kiss-o'-Death codes */
@@ -273,6 +281,7 @@ static const char tss_chars[3] = {'D', 'K', 'H'};
static void transmit_timeout(void *arg);
static double get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx);
static double get_separation(int poll);
/* ================================================== */
@@ -345,7 +354,7 @@ NCR_Initialise(void)
do_size_checks();
do_time_checks();
logfileid = CNF_GetLogMeasurements() ? LOG_FileOpen("measurements",
logfileid = CNF_GetLogMeasurements(&log_raw_measurements) ? LOG_FileOpen("measurements",
" Date (UTC) Time IP Address L St 123 567 ABCD LP RP Score Offset Peer del. Peer disp. Root del. Root disp. Refid MTxRx")
: -1;
@@ -393,7 +402,7 @@ restart_timeout(NCR_Instance inst, double delay)
SCH_RemoveTimeout(inst->tx_timeout_id);
/* Start new timer for transmission */
inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, SAMPLING_SEPARATION,
inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, get_separation(inst->local_poll),
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *)inst);
@@ -474,6 +483,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
result->remote_addr = *remote_addr;
result->local_addr.ip_addr.family = IPADDR_UNSPEC;
result->local_addr.if_index = INVALID_IF_INDEX;
switch (type) {
case NTP_SERVER:
@@ -492,12 +502,12 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
result->interleaved = params->interleaved;
result->minpoll = params->minpoll;
if (result->minpoll < MIN_POLL)
if (result->minpoll < MIN_MINPOLL)
result->minpoll = SRC_DEFAULT_MINPOLL;
else if (result->minpoll > MAX_POLL)
result->minpoll = MAX_POLL;
result->maxpoll = params->maxpoll;
if (result->maxpoll < MIN_POLL)
if (result->maxpoll < MIN_MAXPOLL)
result->maxpoll = SRC_DEFAULT_MAXPOLL;
else if (result->maxpoll > MAX_POLL)
result->maxpoll = MAX_POLL;
@@ -513,9 +523,9 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
if (result->presend_minpoll <= MAX_POLL && result->mode != MODE_CLIENT)
result->presend_minpoll = MAX_POLL + 1;
result->max_delay = params->max_delay;
result->max_delay_ratio = params->max_delay_ratio;
result->max_delay_dev_ratio = params->max_delay_dev_ratio;
result->max_delay = CLAMP(0.0, params->max_delay, MAX_MAXDELAY);
result->max_delay_ratio = CLAMP(0.0, params->max_delay_ratio, MAX_MAXDELAYRATIO);
result->max_delay_dev_ratio = CLAMP(0.0, params->max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
result->offset_correction = params->offset;
result->auto_offline = params->auto_offline;
result->poll_target = params->poll_target;
@@ -648,6 +658,7 @@ NCR_ResetPoll(NCR_Instance instance)
void
NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr)
{
memset(&inst->report, 0, sizeof (inst->report));
NCR_ResetInstance(inst);
inst->remote_addr = *remote_addr;
@@ -656,6 +667,7 @@ NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr)
else {
NIO_CloseServerSocket(inst->local_addr.sock_fd);
inst->local_addr.ip_addr.family = IPADDR_UNSPEC;
inst->local_addr.if_index = INVALID_IF_INDEX;
inst->local_addr.sock_fd = NIO_OpenServerSocket(remote_addr);
}
@@ -759,7 +771,7 @@ get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
approx the poll interval away */
poll_to_use = inst->local_poll;
delay_time = (double) (1UL<<poll_to_use);
delay_time = UTI_Log2ToDouble(poll_to_use);
if (inst->presend_done)
delay_time = WARM_UP_DELAY;
@@ -777,7 +789,7 @@ get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
if (poll_to_use < inst->minpoll)
poll_to_use = inst->minpoll;
delay_time = (double) (1UL<<poll_to_use);
delay_time = UTI_Log2ToDouble(poll_to_use);
/* If the remote stratum is higher than ours, try to lock on the
peer's polling to minimize our response time by slightly extending
@@ -816,6 +828,21 @@ get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
return delay_time;
}
/* ================================================== */
/* Calculate sampling separation for given polling interval */
static double
get_separation(int poll)
{
double separation;
/* Allow up to 8 sources using the same short interval to not be limited
by the separation */
separation = UTI_Log2ToDouble(poll - 3);
return CLAMP(MIN_SAMPLING_SEPARATION, separation, MAX_SAMPLING_SEPARATION);
}
/* ================================================== */
/* Timeout handler for closing the client socket when no acceptable
reply can be received from the server */
@@ -951,57 +978,63 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
frequency all along */
UTI_TimespecToNtp64(&local_receive, &message.receive_ts, &ts_fuzz);
/* Prepare random bits which will be added to the transmit timestamp. */
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
do {
/* Prepare random bits which will be added to the transmit timestamp */
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
/* Transmit - this our local time right now! Also, we might need to
store this for our own use later, next time we receive a message
from the source we're sending to now. */
LCL_ReadCookedTime(&local_transmit, &local_transmit_err);
/* Transmit - this our local time right now! Also, we might need to
store this for our own use later, next time we receive a message
from the source we're sending to now. */
LCL_ReadCookedTime(&local_transmit, &local_transmit_err);
if (smooth_time)
UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
if (smooth_time)
UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
length = NTP_NORMAL_PACKET_LENGTH;
length = NTP_NORMAL_PACKET_LENGTH;
/* Authenticate the packet if needed */
/* Authenticate the packet */
if (auth_mode == AUTH_SYMMETRIC || auth_mode == AUTH_MSSNTP) {
/* Pre-compensate the transmit time by approx. how long it will
take to generate the authentication data. */
local_transmit.tv_nsec += auth_mode == AUTH_SYMMETRIC ?
KEY_GetAuthDelay(key_id) : NSD_GetAuthDelay(key_id);
UTI_NormaliseTimespec(&local_transmit);
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
&message.transmit_ts, &ts_fuzz);
if (auth_mode == AUTH_SYMMETRIC || auth_mode == AUTH_MSSNTP) {
/* Pre-compensate the transmit time by approximately how long it will
take to generate the authentication data */
local_transmit.tv_nsec += auth_mode == AUTH_SYMMETRIC ?
KEY_GetAuthDelay(key_id) : NSD_GetAuthDelay(key_id);
UTI_NormaliseTimespec(&local_transmit);
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
&message.transmit_ts, &ts_fuzz);
if (auth_mode == AUTH_SYMMETRIC) {
auth_len = KEY_GenerateAuth(key_id, (unsigned char *) &message,
offsetof(NTP_Packet, auth_keyid),
(unsigned char *)&message.auth_data,
sizeof (message.auth_data));
if (!auth_len) {
DEBUG_LOG(LOGF_NtpCore, "Could not generate auth data with key %"PRIu32, key_id);
return 0;
if (auth_mode == AUTH_SYMMETRIC) {
auth_len = KEY_GenerateAuth(key_id, (unsigned char *) &message,
offsetof(NTP_Packet, auth_keyid),
(unsigned char *)&message.auth_data,
sizeof (message.auth_data));
if (!auth_len) {
DEBUG_LOG(LOGF_NtpCore, "Could not generate auth data with key %"PRIu32, key_id);
return 0;
}
message.auth_keyid = htonl(key_id);
mac_len = sizeof (message.auth_keyid) + auth_len;
/* Truncate MACs in NTPv4 packets to allow deterministic parsing
of extension fields (RFC 7822) */
if (version == 4 && mac_len > NTP_MAX_V4_MAC_LENGTH)
mac_len = NTP_MAX_V4_MAC_LENGTH;
length += mac_len;
} else if (auth_mode == AUTH_MSSNTP) {
/* MS-SNTP packets are signed (asynchronously) by ntp_signd */
return NSD_SignAndSendPacket(key_id, &message, where_to, from, length);
}
message.auth_keyid = htonl(key_id);
mac_len = sizeof (message.auth_keyid) + auth_len;
/* Truncate MACs in NTPv4 packets to allow deterministic parsing
of extension fields (RFC 7822) */
if (version == 4 && mac_len > NTP_MAX_V4_MAC_LENGTH)
mac_len = NTP_MAX_V4_MAC_LENGTH;
length += mac_len;
} else if (auth_mode == AUTH_MSSNTP) {
/* MS-SNTP packets are signed (asynchronously) by ntp_signd */
return NSD_SignAndSendPacket(key_id, &message, where_to, from, length);
} else {
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
&message.transmit_ts, &ts_fuzz);
}
} else {
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
&message.transmit_ts, &ts_fuzz);
}
/* Avoid sending messages with non-zero transmit timestamp equal to the
receive timestamp to allow reliable detection of the interleaved mode */
} while (!UTI_CompareNtp64(&message.transmit_ts, &message.receive_ts) &&
!UTI_IsZeroNtp64(&message.transmit_ts));
ret = NIO_SendPacket(&message, where_to, from, length, local_tx != NULL);
@@ -1064,6 +1097,7 @@ transmit_timeout(void *arg)
/* Don't require the packet to be sent from the same address as before */
local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.if_index = INVALID_IF_INDEX;
local_addr.sock_fd = inst->local_addr.sock_fd;
/* Check whether we need to 'warm up' the link to the other end by
@@ -1445,7 +1479,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
processing time is sane, and in the interleaved symmetric mode that
the delay is not longer than half of the remote polling interval to
detect missed packets */
testA = delay - dispersion <= inst->max_delay &&
testA = delay - dispersion <= inst->max_delay && precision <= inst->max_delay &&
!(inst->mode == MODE_CLIENT && server_interval > MAX_SERVER_INTERVAL) &&
!(inst->mode == MODE_ACTIVE && interleaved_packet &&
delay > UTI_Log2ToDouble(message->poll - 1));
@@ -1597,8 +1631,9 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
server and the socket can be closed */
close_client_socket(inst);
/* Update the local address */
/* Update the local address and interface */
inst->local_addr.ip_addr = local_addr->ip_addr;
inst->local_addr.if_index = local_addr->if_index;
/* And now, requeue the timer */
if (inst->opmode != MD_OFFLINE) {
@@ -1610,7 +1645,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
UTI_IPToString(&inst->remote_addr.ip_addr));
/* Back off for a while and stop ongoing burst */
delay_time += 4 * (1UL << inst->minpoll);
delay_time += 4 * UTI_Log2ToDouble(inst->local_poll);
if (inst->opmode == MD_BURST_WAS_OFFLINE || inst->opmode == MD_BURST_WAS_ONLINE) {
inst->burst_good_samples_to_go = 0;
@@ -1653,7 +1688,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
}
/* Do measurement logging */
if (logfileid != -1) {
if (logfileid != -1 && (log_raw_measurements || synced_packet)) {
LOG_FileWrite(logfileid, "%s %-15s %1c %2d %1d%1d%1d %1d%1d%1d %1d%1d%1d%d %2d %2d %4.2f %10.3e %10.3e %10.3e %10.3e %10.3e %08"PRIX32" %1d%1c %1c %1c",
UTI_TimeToLogForm(sample_time.tv_sec),
UTI_IPToString(&inst->remote_addr.ip_addr),
@@ -1909,10 +1944,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
!UTI_CompareNtp64(&message->originate_ts, local_ntp_rx);
if (interleaved) {
if (!UTI_IsZeroNtp64(local_ntp_tx))
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
else
interleaved = 0;
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
tx_ts = &local_tx;
} else {
UTI_ZeroNtp64(local_ntp_tx);
@@ -2005,10 +2037,10 @@ NCR_ProcessTxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
if (log_index < 0)
return;
CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
if (SMT_IsEnabled() && NTP_LVM_TO_MODE(message->lvm) == MODE_SERVER)
UTI_AddDoubleToTimespec(&tx_ts->ts, SMT_GetOffset(&tx_ts->ts), &tx_ts->ts);
if (UTI_IsZeroNtp64(local_ntp_tx))
return;
CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
update_tx_timestamp(&local_tx, tx_ts, local_ntp_rx, NULL, message);
@@ -2080,7 +2112,7 @@ NCR_TakeSourceOffline(NCR_Instance inst)
void
NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
{
if (new_minpoll < MIN_POLL || new_minpoll > MAX_POLL)
if (new_minpoll < MIN_MINPOLL || new_minpoll > MAX_POLL)
return;
inst->minpoll = new_minpoll;
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new minpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_minpoll);
@@ -2093,7 +2125,7 @@ NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
void
NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll)
{
if (new_maxpoll < MIN_POLL || new_maxpoll > MAX_POLL)
if (new_maxpoll < MIN_MAXPOLL || new_maxpoll > MAX_POLL)
return;
inst->maxpoll = new_maxpoll;
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new maxpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_maxpoll);
@@ -2106,9 +2138,9 @@ NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll)
void
NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay)
{
inst->max_delay = new_max_delay;
inst->max_delay = CLAMP(0.0, new_max_delay, MAX_MAXDELAY);
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay %f",
UTI_IPToString(&inst->remote_addr.ip_addr), new_max_delay);
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay);
}
/* ================================================== */
@@ -2116,9 +2148,9 @@ NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay)
void
NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio)
{
inst->max_delay_ratio = new_max_delay_ratio;
inst->max_delay_ratio = CLAMP(0.0, new_max_delay_ratio, MAX_MAXDELAYRATIO);
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay ratio %f",
UTI_IPToString(&inst->remote_addr.ip_addr), new_max_delay_ratio);
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_ratio);
}
/* ================================================== */
@@ -2126,9 +2158,9 @@ NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio)
void
NCR_ModifyMaxdelaydevratio(NCR_Instance inst, double new_max_delay_dev_ratio)
{
inst->max_delay_dev_ratio = new_max_delay_dev_ratio;
inst->max_delay_dev_ratio = CLAMP(0.0, new_max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay dev ratio %f",
UTI_IPToString(&inst->remote_addr.ip_addr), new_max_delay_dev_ratio);
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_dev_ratio);
}
/* ================================================== */
@@ -2332,20 +2364,21 @@ broadcast_timeout(void *arg)
BroadcastDestination *destination;
NTP_int64 orig_ts;
NTP_Local_Timestamp recv_ts;
int poll;
destination = ARR_GetElement(broadcasts, (long)arg);
poll = log(destination->interval) / log(2.0) + 0.5;
UTI_ZeroNtp64(&orig_ts);
UTI_ZeroTimespec(&recv_ts.ts);
recv_ts.source = NTP_TS_DAEMON;
recv_ts.err = 0.0;
transmit_packet(MODE_BROADCAST, 0, log(destination->interval) / log(2.0) + 0.5,
NTP_VERSION, 0, 0, &orig_ts, &orig_ts, &recv_ts, NULL, NULL, NULL,
&destination->addr, &destination->local_addr);
transmit_packet(MODE_BROADCAST, 0, poll, NTP_VERSION, 0, 0, &orig_ts, &orig_ts, &recv_ts,
NULL, NULL, NULL, &destination->addr, &destination->local_addr);
/* Requeue timeout. We don't care if interval drifts gradually. */
SCH_AddTimeoutInClass(destination->interval, SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
SCH_AddTimeoutInClass(destination->interval, get_separation(poll), SAMPLING_RANDOMNESS,
SCH_NtpBroadcastClass, broadcast_timeout, arg);
}
@@ -2361,10 +2394,11 @@ NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval)
destination->addr.ip_addr = *addr;
destination->addr.port = port;
destination->local_addr.ip_addr.family = IPADDR_UNSPEC;
destination->local_addr.if_index = INVALID_IF_INDEX;
destination->local_addr.sock_fd = NIO_OpenServerSocket(&destination->addr);
destination->interval = CLAMP(1 << MIN_POLL, interval, 1 << MAX_POLL);
destination->interval = CLAMP(1, interval, 1 << MAX_POLL);
SCH_AddTimeoutInClass(destination->interval, SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
SCH_AddTimeoutInClass(destination->interval, MAX_SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
SCH_NtpBroadcastClass, broadcast_timeout,
(void *)(long)(ARR_GetSize(broadcasts) - 1));
}

View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Timo Teras 2009
* Copyright (C) Miroslav Lichvar 2009, 2013-2015
* Copyright (C) Miroslav Lichvar 2009, 2013-2016
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -365,9 +365,8 @@ NIO_Initialise(int family)
NIO_Linux_Initialise();
#else
if (1) {
double tx_comp, rx_comp;
char *name;
if (CNF_GetHwTsInterface(0, &name, &tx_comp, &rx_comp))
CNF_HwTsInterface *conf_iface;
if (CNF_GetHwTsInterface(0, &conf_iface))
LOG_FATAL(LOGF_NtpIO, "HW timestamping not supported");
}
#endif
@@ -579,7 +578,6 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
NTP_Local_Timestamp local_ts;
struct timespec sched_ts;
struct cmsghdr *cmsg;
int if_index;
SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL);
local_ts.source = NTP_TS_DAEMON;
@@ -599,8 +597,8 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
}
local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.if_index = INVALID_IF_INDEX;
local_addr.sock_fd = sock_fd;
if_index = -1;
if (hdr->msg_flags & MSG_TRUNC) {
DEBUG_LOG(LOGF_NtpIO, "Received truncated message from %s:%d",
@@ -621,7 +619,7 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
local_addr.ip_addr.addr.in4 = ntohl(ipi.ipi_addr.s_addr);
local_addr.ip_addr.family = IPADDR_INET4;
if_index = ipi.ipi_ifindex;
local_addr.if_index = ipi.ipi_ifindex;
}
#endif
@@ -633,7 +631,7 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
memcpy(&local_addr.ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr,
sizeof (local_addr.ip_addr.addr.in6));
local_addr.ip_addr.family = IPADDR_INET6;
if_index = ipi.ipi6_ifindex;
local_addr.if_index = ipi.ipi6_ifindex;
}
#endif
@@ -661,14 +659,13 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
}
#ifdef HAVE_LINUX_TIMESTAMPING
if (NIO_Linux_ProcessMessage(&remote_addr, &local_addr, &local_ts,
hdr, length, sock_fd, if_index))
if (NIO_Linux_ProcessMessage(&remote_addr, &local_addr, &local_ts, hdr, length))
return;
#endif
DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd=%d if=%d tss=%d delay=%.9f",
length, UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd, if_index,
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd, local_addr.if_index,
local_ts.source, UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts));
/* Just ignore the packet if it's not of a recognized length */

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2016
* Copyright (C) Miroslav Lichvar 2016-2017
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -61,11 +61,15 @@ struct Interface {
char name[IF_NAMESIZE];
int if_index;
int phc_fd;
int phc_mode;
int phc_nocrossts;
/* Link speed in mbit/s */
int link_speed;
/* Start of UDP data at layer 2 for IPv4 and IPv6 */
int l2_udp4_ntp_start;
int l2_udp6_ntp_start;
/* Precision of PHC readings */
double precision;
/* Compensation of errors in TX and RX timestamping */
double tx_comp;
double rx_comp;
@@ -75,6 +79,9 @@ struct Interface {
/* Number of PHC readings per HW clock sample */
#define PHC_READINGS 10
/* Minimum interval between PHC readings */
#define MIN_PHC_POLL -6
/* Maximum acceptable offset between HW and daemon/kernel timestamp */
#define MAX_TS_DELAY 1.0
@@ -91,19 +98,18 @@ static int permanent_ts_options;
/* ================================================== */
static int
add_interface(const char *name, double tx_comp, double rx_comp)
add_interface(CNF_HwTsInterface *conf_iface)
{
struct ethtool_ts_info ts_info;
struct hwtstamp_config ts_config;
struct ifreq req;
int sock_fd, if_index, phc_index, phc_fd;
int sock_fd, if_index, phc_fd, req_hwts_flags;
unsigned int i;
struct Interface *iface;
char phc_path[64];
/* Check if the interface was not already added */
for (i = 0; i < ARR_GetSize(interfaces); i++) {
if (!strcmp(name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
if (!strcmp(conf_iface->name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
return 1;
}
@@ -114,7 +120,8 @@ add_interface(const char *name, double tx_comp, double rx_comp)
memset(&req, 0, sizeof (req));
memset(&ts_info, 0, sizeof (ts_info));
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", name) >= sizeof (req.ifr_name)) {
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", conf_iface->name) >=
sizeof (req.ifr_name)) {
close(sock_fd);
return 0;
}
@@ -136,6 +143,14 @@ add_interface(const char *name, double tx_comp, double rx_comp)
return 0;
}
req_hwts_flags = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
if ((ts_info.so_timestamping & req_hwts_flags) != req_hwts_flags) {
DEBUG_LOG(LOGF_NtpIOLinux, "HW timestamping not supported on %s", req.ifr_name);
close(sock_fd);
return 0;
}
ts_config.flags = 0;
ts_config.tx_type = HWTSTAMP_TX_ON;
ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
@@ -148,36 +163,31 @@ add_interface(const char *name, double tx_comp, double rx_comp)
}
close(sock_fd);
phc_index = ts_info.phc_index;
if (snprintf(phc_path, sizeof (phc_path), "/dev/ptp%d", phc_index) >= sizeof (phc_path))
phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index);
if (phc_fd < 0)
return 0;
phc_fd = open(phc_path, O_RDONLY);
if (phc_fd < 0) {
LOG(LOGS_ERR, LOGF_NtpIOLinux, "Could not open %s : %s", phc_path, strerror(errno));
return 0;
}
UTI_FdSetCloexec(phc_fd);
iface = ARR_GetNewElement(interfaces);
snprintf(iface->name, sizeof (iface->name), "%s", name);
snprintf(iface->name, sizeof (iface->name), "%s", conf_iface->name);
iface->if_index = if_index;
iface->phc_fd = phc_fd;
iface->phc_mode = 0;
iface->phc_nocrossts = conf_iface->nocrossts;
/* Start with 1 gbit and no VLANs or IPv4/IPv6 options */
iface->link_speed = 1000;
iface->l2_udp4_ntp_start = 42;
iface->l2_udp6_ntp_start = 62;
iface->tx_comp = tx_comp;
iface->rx_comp = rx_comp;
iface->precision = conf_iface->precision;
iface->tx_comp = conf_iface->tx_comp;
iface->rx_comp = conf_iface->rx_comp;
iface->clock = HCL_CreateInstance();
iface->clock = HCL_CreateInstance(UTI_Log2ToDouble(MAX(conf_iface->minpoll, MIN_PHC_POLL)));
DEBUG_LOG(LOGF_NtpIOLinux, "Enabled HW timestamping on %s", name);
LOG(LOGS_INFO, LOGF_NtpIOLinux, "Enabled HW timestamping on %s", iface->name);
return 1;
}
@@ -185,18 +195,22 @@ add_interface(const char *name, double tx_comp, double rx_comp)
/* ================================================== */
static int
add_all_interfaces(double tx_comp, double rx_comp)
add_all_interfaces(CNF_HwTsInterface *conf_iface_all)
{
CNF_HwTsInterface conf_iface;
struct ifaddrs *ifaddr, *ifa;
int r;
conf_iface = *conf_iface_all;
if (getifaddrs(&ifaddr)) {
DEBUG_LOG(LOGF_NtpIOLinux, "getifaddrs() failed : %s", strerror(errno));
return 0;
}
for (r = 0, ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
if (add_interface(ifa->ifa_name, tx_comp, rx_comp))
conf_iface.name = ifa->ifa_name;
if (add_interface(&conf_iface))
r = 1;
}
@@ -242,8 +256,7 @@ update_interface_speed(struct Interface *iface)
void
NIO_Linux_Initialise(void)
{
double tx_comp, rx_comp;
char *name;
CNF_HwTsInterface *conf_iface;
unsigned int i;
int hwts;
@@ -252,18 +265,18 @@ NIO_Linux_Initialise(void)
/* Enable HW timestamping on specified interfaces. If "*" was specified, try
all interfaces. If no interface was specified, enable SW timestamping. */
for (i = hwts = 0; CNF_GetHwTsInterface(i, &name, &tx_comp, &rx_comp); i++) {
if (!strcmp("*", name))
for (i = hwts = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
if (!strcmp("*", conf_iface->name))
continue;
if (!add_interface(name, tx_comp, rx_comp))
LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", name);
if (!add_interface(conf_iface))
LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", conf_iface->name);
hwts = 1;
}
for (i = 0; CNF_GetHwTsInterface(i, &name, &tx_comp, &rx_comp); i++) {
if (strcmp("*", name))
for (i = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
if (strcmp("*", conf_iface->name))
continue;
if (add_all_interfaces(tx_comp, rx_comp))
if (add_all_interfaces(conf_iface))
hwts = 1;
break;
}
@@ -337,68 +350,6 @@ NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
/* ================================================== */
static int
get_phc_sample(int phc_fd, struct timespec *phc_ts, struct timespec *local_ts, double *p_delay)
{
struct ptp_sys_offset sys_off;
struct timespec ts1, ts2, ts3, phc_tss[PHC_READINGS], sys_tss[PHC_READINGS];
double min_delay = 0.0, delays[PHC_READINGS], phc_sum, local_sum, local_prec;
int i, n;
/* Silence valgrind */
memset(&sys_off, 0, sizeof (sys_off));
sys_off.n_samples = PHC_READINGS;
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
return 0;
}
for (i = 0; i < PHC_READINGS; i++) {
ts1.tv_sec = sys_off.ts[i * 2].sec;
ts1.tv_nsec = sys_off.ts[i * 2].nsec;
ts2.tv_sec = sys_off.ts[i * 2 + 1].sec;
ts2.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
ts3.tv_sec = sys_off.ts[i * 2 + 2].sec;
ts3.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
sys_tss[i] = ts1;
phc_tss[i] = ts2;
delays[i] = UTI_DiffTimespecsToDouble(&ts3, &ts1);
if (delays[i] <= 0.0)
/* Step in the middle of a PHC reading? */
return 0;
if (!i || delays[i] < min_delay)
min_delay = delays[i];
}
local_prec = LCL_GetSysPrecisionAsQuantum();
/* Combine best readings */
for (i = n = 0, phc_sum = local_sum = 0.0; i < PHC_READINGS; i++) {
if (delays[i] > min_delay + local_prec)
continue;
phc_sum += UTI_DiffTimespecsToDouble(&phc_tss[i], &phc_tss[0]);
local_sum += UTI_DiffTimespecsToDouble(&sys_tss[i], &sys_tss[0]) + delays[i] / 2.0;
n++;
}
assert(n);
UTI_AddDoubleToTimespec(&phc_tss[0], phc_sum / n, phc_ts);
UTI_AddDoubleToTimespec(&sys_tss[0], local_sum / n, &ts1);
LCL_CookTime(&ts1, local_ts, NULL);
*p_delay = min_delay;
return 1;
}
/* ================================================== */
static struct Interface *
get_interface(int if_index)
{
@@ -422,16 +373,17 @@ static void
process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family)
{
struct timespec sample_phc_ts, sample_local_ts, ts;
double sample_delay, rx_correction, ts_delay, err;
struct timespec sample_phc_ts, sample_sys_ts, sample_local_ts, ts;
double rx_correction, ts_delay, err;
int l2_length;
if (HCL_NeedsNewSample(iface->clock, &local_ts->ts)) {
if (!get_phc_sample(iface->phc_fd, &sample_phc_ts, &sample_local_ts, &sample_delay))
if (!SYS_Linux_GetPHCSample(iface->phc_fd, iface->phc_nocrossts, iface->precision,
&iface->phc_mode, &sample_phc_ts, &sample_sys_ts, &err))
return;
HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts,
sample_delay / 2.0);
LCL_CookTime(&sample_sys_ts, &sample_local_ts, NULL);
HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts, err);
update_interface_speed(iface);
}
@@ -536,8 +488,7 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
int
NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
NTP_Local_Timestamp *local_ts, struct msghdr *hdr,
int length, int sock_fd, int if_index)
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length)
{
struct Interface *iface;
struct cmsghdr *cmsg;
@@ -556,12 +507,13 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
LCL_CookTime(&ts3.ts[0], &local_ts->ts, &local_ts->err);
local_ts->source = NTP_TS_KERNEL;
} else if (!UTI_IsZeroTimespec(&ts3.ts[2])) {
iface = get_interface(if_index);
iface = get_interface(local_addr->if_index);
if (iface) {
process_hw_timestamp(iface, &ts3.ts[2], local_ts, !is_tx ? length : 0,
remote_addr->ip_addr.family);
} else {
DEBUG_LOG(LOGF_NtpIOLinux, "HW clock not found for interface %d", if_index);
DEBUG_LOG(LOGF_NtpIOLinux, "HW clock not found for interface %d",
local_addr->if_index);
}
}
}
@@ -593,7 +545,7 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
DEBUG_LOG(LOGF_NtpIOLinux, "Received %d (%d) bytes from error queue for %s:%d fd=%d if=%d tss=%d",
l2_length, length, UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
sock_fd, if_index, local_ts->source);
local_addr->sock_fd, local_addr->if_index, local_ts->source);
/* Update assumed position of UDP data at layer 2 for next received packet */
if (iface && length) {

View File

@@ -31,7 +31,6 @@ extern void NIO_Linux_Finalise(void);
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
extern int NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length,
int sock_fd, int if_index);
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length);
extern int NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd);

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -505,6 +505,12 @@ RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second)
return 1;
}
double
RCL_GetPrecision(RCL_Instance instance)
{
return instance->precision;
}
static int
valid_sample_time(RCL_Instance instance, struct timespec *raw, struct timespec *cooked)
{

View File

@@ -71,5 +71,6 @@ extern char *RCL_GetDriverParameter(RCL_Instance instance);
extern char *RCL_GetDriverOption(RCL_Instance instance, char *name);
extern int RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap);
extern int RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second);
extern double RCL_GetPrecision(RCL_Instance instance);
#endif

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2013
* Copyright (C) Miroslav Lichvar 2013, 2017
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -33,144 +33,67 @@
#include "sysincl.h"
#include <linux/ptp_clock.h>
#include "refclock.h"
#include "logging.h"
#include "memory.h"
#include "util.h"
#include "sys_linux.h"
/* From linux/include/linux/posix-timers.h */
#define CPUCLOCK_MAX 3
#define CLOCKFD CPUCLOCK_MAX
#define CLOCKFD_MASK (CPUCLOCK_PERTHREAD_MASK|CPUCLOCK_CLOCK_MASK)
#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
#define NUM_READINGS 10
static int no_sys_offset_ioctl = 0;
struct phc_reading {
struct timespec sys_ts1;
struct timespec phc_ts;;
struct timespec sys_ts2;
struct phc_instance {
int fd;
int mode;
int nocrossts;
};
static int read_phc_ioctl(struct phc_reading *readings, int phc_fd, int n)
{
#if defined(PTP_SYS_OFFSET) && NUM_READINGS <= PTP_MAX_SAMPLES
struct ptp_sys_offset sys_off;
int i;
/* Silence valgrind */
memset(&sys_off, 0, sizeof (sys_off));
sys_off.n_samples = n;
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
LOG(LOGS_ERR, LOGF_Refclock, "ioctl(PTP_SYS_OFFSET) failed : %s", strerror(errno));
return 0;
}
for (i = 0; i < n; i++) {
readings[i].sys_ts1.tv_sec = sys_off.ts[i * 2].sec;
readings[i].sys_ts1.tv_nsec = sys_off.ts[i * 2].nsec;
readings[i].phc_ts.tv_sec = sys_off.ts[i * 2 + 1].sec;
readings[i].phc_ts.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
readings[i].sys_ts2.tv_sec = sys_off.ts[i * 2 + 2].sec;
readings[i].sys_ts2.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
}
return 1;
#else
/* Not available */
return 0;
#endif
}
static int read_phc_user(struct phc_reading *readings, int phc_fd, int n)
{
clockid_t phc_id;
int i;
phc_id = FD_TO_CLOCKID(phc_fd);
for (i = 0; i < n; i++) {
if (clock_gettime(CLOCK_REALTIME, &readings[i].sys_ts1) ||
clock_gettime(phc_id, &readings[i].phc_ts) ||
clock_gettime(CLOCK_REALTIME, &readings[i].sys_ts2)) {
LOG(LOGS_ERR, LOGF_Refclock, "clock_gettime() failed : %s", strerror(errno));
return 0;
}
}
return 1;
}
static int phc_initialise(RCL_Instance instance)
{
struct ptp_clock_caps caps;
struct phc_instance *phc;
int phc_fd;
char *path;
path = RCL_GetDriverParameter(instance);
phc_fd = open(path, O_RDONLY);
phc_fd = SYS_Linux_OpenPHC(path, 0);
if (phc_fd < 0) {
LOG_FATAL(LOGF_Refclock, "open() failed on %s", path);
LOG_FATAL(LOGF_Refclock, "Could not open PHC");
return 0;
}
/* Make sure it is a PHC */
if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) {
LOG_FATAL(LOGF_Refclock, "ioctl(PTP_CLOCK_GETCAPS) failed : %s", strerror(errno));
return 0;
}
phc = MallocNew(struct phc_instance);
phc->fd = phc_fd;
phc->mode = 0;
phc->nocrossts = RCL_GetDriverOption(instance, "nocrossts") ? 1 : 0;
UTI_FdSetCloexec(phc_fd);
RCL_SetDriverData(instance, (void *)(long)phc_fd);
RCL_SetDriverData(instance, phc);
return 1;
}
static void phc_finalise(RCL_Instance instance)
{
close((long)RCL_GetDriverData(instance));
struct phc_instance *phc;
phc = (struct phc_instance *)RCL_GetDriverData(instance);
close(phc->fd);
Free(phc);
}
static int phc_poll(RCL_Instance instance)
{
struct phc_reading readings[NUM_READINGS];
double offset = 0.0, delay, best_delay = 0.0;
int i, phc_fd, best;
phc_fd = (long)RCL_GetDriverData(instance);
struct phc_instance *phc;
struct timespec phc_ts, sys_ts;
double offset, err;
if (!no_sys_offset_ioctl) {
if (!read_phc_ioctl(readings, phc_fd, NUM_READINGS)) {
no_sys_offset_ioctl = 1;
return 0;
}
} else {
if (!read_phc_user(readings, phc_fd, NUM_READINGS))
return 0;
}
phc = (struct phc_instance *)RCL_GetDriverData(instance);
/* Find the fastest reading */
for (i = 0; i < NUM_READINGS; i++) {
delay = UTI_DiffTimespecsToDouble(&readings[i].sys_ts2, &readings[i].sys_ts1);
if (!SYS_Linux_GetPHCSample(phc->fd, phc->nocrossts, RCL_GetPrecision(instance),
&phc->mode, &phc_ts, &sys_ts, &err))
return 0;
if (!i || best_delay > delay) {
best = i;
best_delay = delay;
}
}
offset = UTI_DiffTimespecsToDouble(&phc_ts, &sys_ts);
offset = UTI_DiffTimespecsToDouble(&readings[best].phc_ts, &readings[best].sys_ts2) +
best_delay / 2.0;
DEBUG_LOG(LOGF_Refclock, "PHC offset: %+.9f err: %.9f", offset, err);
DEBUG_LOG(LOGF_Refclock, "PHC offset: %+.9f delay: %.9f", offset, best_delay);
return RCL_AddSample(instance, &readings[best].sys_ts2, offset, LEAP_Normal);
return RCL_AddSample(instance, &sys_ts, offset, LEAP_Normal);
}
RefclockDriver RCL_PHC_driver = {

View File

@@ -1214,7 +1214,7 @@ REF_GetReferenceParams
*leap_status = LEAP_Normal;
*root_delay = 0.0;
*root_dispersion = LCL_GetSysPrecisionAsQuantum();
*root_dispersion = 0.0;
} else {

View File

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

View File

@@ -187,6 +187,11 @@ accumulate_sample(time_t rtc, struct timespec *sys)
discard_samples(NEW_FIRST_WHEN_FULL);
}
/* Discard all samples if the RTC was stepped back (not our trim) */
if (n_samples > 0 && rtc_sec[n_samples - 1] - rtc >= rtc_trim[n_samples - 1]) {
DEBUG_LOG(LOGF_RtcLinux, "RTC samples discarded");
n_samples = 0;
}
/* Always use most recent sample as reference */
/* use sample only if n_sample is not negative*/

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011, 2013-2015
* Copyright (C) Miroslav Lichvar 2011, 2013-2016
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011-2014
* Copyright (C) Miroslav Lichvar 2011-2014, 2016
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -928,7 +928,7 @@ void
SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timespec *now)
{
int i, j;
struct timespec ago;
struct timespec last_sample_time;
if (inst->n_samples > 0) {
i = get_runsbuf_index(inst, inst->n_samples - 1);
@@ -938,8 +938,10 @@ SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timespec *no
report->latest_meas_err = 0.5*inst->root_delays[j] + inst->root_dispersions[j];
report->stratum = inst->strata[j];
UTI_DiffTimespecs(&ago, now, &inst->sample_times[i]);
report->latest_meas_ago = ago.tv_sec;
/* Align the sample time to reduce the leak of the receive timestamp */
last_sample_time = inst->sample_times[i];
last_sample_time.tv_nsec = 0;
report->latest_meas_ago = UTI_DiffTimespecsToDouble(now, &last_sample_time);
} else {
report->latest_meas_ago = (uint32_t)-1;
report->orig_latest_meas = 0;

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2014-2015
* Copyright (C) Miroslav Lichvar 2014-2016
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as

View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2015
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2016
*
* 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
@@ -47,13 +47,14 @@
#include <sys/capability.h>
#endif
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
#include <linux/ptp_clock.h>
#endif
#ifdef FEAT_SCFILTER
#include <sys/prctl.h>
#include <seccomp.h>
#include <termios.h>
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
#include <linux/ptp_clock.h>
#endif
#ifdef FEAT_PPS
#include <linux/pps.h>
#endif
@@ -68,6 +69,7 @@
#include "sys_linux.h"
#include "sys_timex.h"
#include "conf.h"
#include "local.h"
#include "logging.h"
#include "privops.h"
#include "util.h"
@@ -515,6 +517,9 @@ SYS_Linux_EnableSystemCallFilter(int level)
FIONREAD, TCGETS,
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
PTP_SYS_OFFSET,
#ifdef PTP_SYS_OFFSET_PRECISE
PTP_SYS_OFFSET_PRECISE,
#endif
#endif
#ifdef FEAT_PPS
PPS_FETCH,
@@ -661,3 +666,151 @@ SYS_Linux_CheckKernelVersion(int req_major, int req_minor)
return kernelvercmp(req_major, req_minor, 0, major, minor, patch) <= 0;
}
/* ================================================== */
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
#define PHC_READINGS 10
static int
get_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
struct timespec *sys_ts, double *err)
{
struct ptp_sys_offset sys_off;
struct timespec ts1, ts2, ts3, phc_tss[PHC_READINGS], sys_tss[PHC_READINGS];
double min_delay = 0.0, delays[PHC_READINGS], phc_sum, sys_sum, sys_prec;
int i, n;
/* Silence valgrind */
memset(&sys_off, 0, sizeof (sys_off));
sys_off.n_samples = PHC_READINGS;
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
DEBUG_LOG(LOGF_SysLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
return 0;
}
for (i = 0; i < PHC_READINGS; i++) {
ts1.tv_sec = sys_off.ts[i * 2].sec;
ts1.tv_nsec = sys_off.ts[i * 2].nsec;
ts2.tv_sec = sys_off.ts[i * 2 + 1].sec;
ts2.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
ts3.tv_sec = sys_off.ts[i * 2 + 2].sec;
ts3.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
sys_tss[i] = ts1;
phc_tss[i] = ts2;
delays[i] = UTI_DiffTimespecsToDouble(&ts3, &ts1);
if (delays[i] <= 0.0)
/* Step in the middle of a PHC reading? */
return 0;
if (!i || delays[i] < min_delay)
min_delay = delays[i];
}
sys_prec = LCL_GetSysPrecisionAsQuantum();
/* Combine best readings */
for (i = n = 0, phc_sum = sys_sum = 0.0; i < PHC_READINGS; i++) {
if (delays[i] > min_delay + MAX(sys_prec, precision))
continue;
phc_sum += UTI_DiffTimespecsToDouble(&phc_tss[i], &phc_tss[0]);
sys_sum += UTI_DiffTimespecsToDouble(&sys_tss[i], &sys_tss[0]) + delays[i] / 2.0;
n++;
}
assert(n);
UTI_AddDoubleToTimespec(&phc_tss[0], phc_sum / n, phc_ts);
UTI_AddDoubleToTimespec(&sys_tss[0], sys_sum / n, sys_ts);
*err = MAX(min_delay / 2.0, precision);
return 1;
}
/* ================================================== */
static int
get_precise_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
struct timespec *sys_ts, double *err)
{
#ifdef PTP_SYS_OFFSET_PRECISE
struct ptp_sys_offset_precise sys_off;
/* Silence valgrind */
memset(&sys_off, 0, sizeof (sys_off));
if (ioctl(phc_fd, PTP_SYS_OFFSET_PRECISE, &sys_off)) {
DEBUG_LOG(LOGF_SysLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET_PRECISE",
strerror(errno));
return 0;
}
phc_ts->tv_sec = sys_off.device.sec;
phc_ts->tv_nsec = sys_off.device.nsec;
sys_ts->tv_sec = sys_off.sys_realtime.sec;
sys_ts->tv_nsec = sys_off.sys_realtime.nsec;
*err = MAX(LCL_GetSysPrecisionAsQuantum(), precision);
return 1;
#else
return 0;
#endif
}
/* ================================================== */
int
SYS_Linux_OpenPHC(const char *path, int phc_index)
{
struct ptp_clock_caps caps;
char phc_path[64];
int phc_fd;
if (!path) {
if (snprintf(phc_path, sizeof (phc_path), "/dev/ptp%d", phc_index) >= sizeof (phc_path))
return -1;
path = phc_path;
}
phc_fd = open(path, O_RDONLY);
if (phc_fd < 0) {
LOG(LOGS_ERR, LOGF_SysLinux, "Could not open %s : %s", path, strerror(errno));
return -1;
}
/* Make sure it is a PHC */
if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) {
LOG(LOGS_ERR, LOGF_SysLinux, "ioctl(%s) failed : %s", "PTP_CLOCK_GETCAPS", strerror(errno));
close(phc_fd);
return -1;
}
UTI_FdSetCloexec(phc_fd);
return phc_fd;
}
/* ================================================== */
int
SYS_Linux_GetPHCSample(int fd, int nocrossts, double precision, int *reading_mode,
struct timespec *phc_ts, struct timespec *sys_ts, double *err)
{
if ((*reading_mode == 2 || !*reading_mode) && !nocrossts &&
get_precise_phc_sample(fd, precision, phc_ts, sys_ts, err)) {
*reading_mode = 2;
return 1;
} else if ((*reading_mode == 1 || !*reading_mode) &&
get_phc_sample(fd, precision, phc_ts, sys_ts, err)) {
*reading_mode = 1;
return 1;
}
return 0;
}
#endif

View File

@@ -41,4 +41,9 @@ extern void SYS_Linux_SetScheduler(int SchedPriority);
extern int SYS_Linux_CheckKernelVersion(int req_major, int req_minor);
extern int SYS_Linux_OpenPHC(const char *path, int phc_index);
extern int SYS_Linux_GetPHCSample(int fd, int nocrossts, double precision, int *reading_mode,
struct timespec *phc_ts, struct timespec *sys_ts, double *err);
#endif /* GOT_SYS_LINUX_H */

View File

@@ -158,7 +158,8 @@ set_sync_status(int synchronised, double est_error, double max_error)
txc.esterror = est_error * 1.0e6;
txc.maxerror = max_error * 1.0e6;
SYS_Timex_Adjust(&txc, 1);
if (SYS_Timex_Adjust(&txc, 1) < 0)
;
}
/* ================================================== */

View File

@@ -20,8 +20,8 @@ RMS offset : 0\.000...... seconds
Frequency : (99|100)\.... ppm fast
Residual freq : [+-][0-9]\.... ppm
Skew : [0-9]\.... ppm
Root delay : 0\.000... seconds
Root dispersion : 0\.000... seconds
Root delay : 0\.000...... seconds
Root dispersion : 0\.000...... seconds
Update interval : [0-9]+\.. seconds
Leap status : Normal
210 Number of sources = 1

View File

@@ -25,13 +25,21 @@ time_offset=-10
client_server_options="minpoll 6 maxpoll 6"
client_conf="corrtimeratio 100"
min_sync_time=8000
max_sync_time=8500
max_sync_time=9000
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_sync || test_fail
client_server_options="minpoll 6 maxpoll 6 xleave maxdelay 1e-1"
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_sync || test_fail
client_server_options="minpoll 6 maxpoll 6"
min_sync_time=$default_min_sync_time
max_sync_time=$default_max_sync_time
time_max_limit=11

View File

@@ -31,7 +31,7 @@ test_unit(void)
LCL_Initialise();
clock = HCL_CreateInstance();
clock = HCL_CreateInstance(1.0);
for (i = 0; i < 2000; i++) {
UTI_ZeroTimespec(&start_hw_ts);
@@ -43,7 +43,7 @@ test_unit(void)
freq = TST_GetRandomDouble(0.9, 1.1);
jitter = TST_GetRandomDouble(10.0e-9, 1000.0e-9);
interval = TST_GetRandomDouble(MIN_SAMPLE_SEPARATION / 10, MIN_SAMPLE_SEPARATION * 10.0);
interval = TST_GetRandomDouble(0.1, 10.0);
clock->n_samples = 0;
clock->valid_coefs = 0;
@@ -68,5 +68,7 @@ test_unit(void)
}
}
HCL_DestroyInstance(clock);
LCL_Finalise();
}

147
test/unit/keys.c Normal file
View File

@@ -0,0 +1,147 @@
/*
**********************************************************************
* Copyright (C) Miroslav Lichvar 2017
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
*/
#include <keys.c>
#include "test.h"
#define KEYS 100
#define KEYFILE "keys.test-keys"
static
uint32_t write_random_key(FILE *f)
{
const char *hash_name;
char key[128];
uint32_t id;
int i, length;
length = random() % sizeof (key) + 1;
length = MAX(length, 4);
UTI_GetRandomBytes(&id, sizeof (id));
UTI_GetRandomBytes(key, length);
switch (random() % 6) {
#ifdef FEAT_SECHASH
case 0:
hash_name = "SHA1";
break;
case 1:
hash_name = "SHA256";
break;
case 2:
hash_name = "SHA384";
break;
case 3:
hash_name = "SHA512";
break;
#endif
case 4:
hash_name = "MD5";
break;
default:
hash_name = "";
}
fprintf(f, "%u %s %s", id, hash_name, random() % 2 ? "HEX:" : "");
for (i = 0; i < length; i++)
fprintf(f, "%02hhX", key[i]);
fprintf(f, "\n");
return id;
}
static void
generate_key_file(const char *name, uint32_t *keys)
{
FILE *f;
int i;
f = fopen(name, "w");
TEST_CHECK(f);
for (i = 0; i < KEYS; i++)
keys[i] = write_random_key(f);
fclose(f);
}
void
test_unit(void)
{
int i, j, data_len, auth_len;
uint32_t keys[KEYS], key;
unsigned char data[100], auth[MAX_HASH_LENGTH];
char conf[][100] = {
"keyfile "KEYFILE
};
CNF_Initialise(0);
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
CNF_ParseLine(NULL, i + 1, conf[i]);
generate_key_file(KEYFILE, keys);
KEY_Initialise();
for (i = 0; i < 100; i++) {
DEBUG_LOG(0, "iteration %d", i);
if (i) {
generate_key_file(KEYFILE, keys);
KEY_Reload();
}
UTI_GetRandomBytes(data, sizeof (data));
for (j = 0; j < KEYS; j++) {
TEST_CHECK(KEY_KeyKnown(keys[j]));
TEST_CHECK(KEY_GetAuthDelay(keys[j]) >= 0);
TEST_CHECK(KEY_GetAuthLength(keys[j]) >= 16);
data_len = random() % (sizeof (data) + 1);
auth_len = KEY_GenerateAuth(keys[j], data, data_len, auth, sizeof (auth));
TEST_CHECK(auth_len >= 16);
TEST_CHECK(KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
if (j > 0 && keys[j - 1] != keys[j])
TEST_CHECK(!KEY_CheckAuth(keys[j - 1], data, data_len, auth, auth_len, auth_len));
auth_len = random() % auth_len + 1;
if (auth_len < MAX_HASH_LENGTH)
auth[auth_len]++;
TEST_CHECK(KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
auth[auth_len - 1]++;
TEST_CHECK(!KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
}
for (j = 0; j < 1000; j++) {
UTI_GetRandomBytes(&key, sizeof (key));
if (KEY_KeyKnown(key))
continue;
TEST_CHECK(!KEY_GenerateAuth(j, data, data_len, auth, sizeof (auth)));
TEST_CHECK(!KEY_CheckAuth(j, data, data_len, auth, auth_len, auth_len));
}
}
unlink(KEYFILE);
KEY_Finalise();
CNF_Finalise();
HSH_Finalise();
}

299
test/unit/ntp_core.c Normal file
View File

@@ -0,0 +1,299 @@
/*
**********************************************************************
* Copyright (C) Miroslav Lichvar 2017
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
*/
#include <config.h>
#include <sysincl.h>
#include <cmdparse.h>
#include <conf.h>
#include <keys.h>
#include <ntp_io.h>
#include <sched.h>
#include <local.h>
#include "test.h"
static struct timespec current_time;
static NTP_Receive_Buffer req_buffer, res_buffer;
static int req_length, res_length;
#define NIO_OpenServerSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 100 : 0)
#define NIO_CloseServerSocket(fd) assert(fd == 100)
#define NIO_OpenClientSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 101 : 0)
#define NIO_CloseClientSocket(fd) assert(fd == 101)
#define NIO_SendPacket(msg, to, from, len, process_tx) (memcpy(&req_buffer, msg, len), req_length = len, 1)
#define SCH_AddTimeoutByDelay(delay, handler, arg) (1 ? 102 : (handler(arg), 1))
#define SCH_AddTimeoutInClass(delay, separation, randomness, class, handler, arg) \
add_timeout_in_class(delay, separation, randomness, class, handler, arg)
#define SCH_RemoveTimeout(id) assert(!id || id == 102)
#define LCL_ReadRawTime(ts) (*ts = current_time)
#define LCL_ReadCookedTime(ts, err) do {double *p = err; *ts = current_time; if (p) *p = 0.0;} while (0)
#define SRC_UpdateReachability(inst, reach)
#define SRC_ResetReachability(inst)
static SCH_TimeoutID
add_timeout_in_class(double min_delay, double separation, double randomness,
SCH_TimeoutClass class, SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg)
{
return 102;
}
#include <ntp_core.c>
static NCR_Instance inst;
static void
advance_time(double x)
{
UTI_AddDoubleToTimespec(&current_time, x, &current_time);
}
static void
send_request(void)
{
NTP_Local_Address local_addr;
NTP_Local_Timestamp local_ts;
uint32_t prev_tx_count;
prev_tx_count = inst->report.total_tx_count;
transmit_timeout(inst);
TEST_CHECK(!inst->valid_rx);
TEST_CHECK(!inst->updated_timestamps);
TEST_CHECK(prev_tx_count + 1 == inst->report.total_tx_count);
advance_time(1e-4);
local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.if_index = INVALID_IF_INDEX;
local_addr.sock_fd = 101;
local_ts.ts = current_time;
local_ts.err = 0.0;
local_ts.source = NTP_TS_DAEMON;
NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer.ntp_pkt, req_length);
}
static void
send_response(int interleaved, int authenticated, int allow_update, int valid_ts, int valid_auth)
{
NTP_Packet *req, *res;
req = &req_buffer.ntp_pkt;
res = &res_buffer.ntp_pkt;
TEST_CHECK(req_length >= NTP_NORMAL_PACKET_LENGTH);
res->lvm = NTP_LVM(LEAP_Normal, NTP_LVM_TO_VERSION(req->lvm),
NTP_LVM_TO_MODE(req->lvm) == MODE_CLIENT ? MODE_SERVER : MODE_ACTIVE);
res->stratum = 1;
res->poll = req->poll;
res->precision = -20;
res->root_delay = UTI_DoubleToNtp32(0.1);
res->root_dispersion = UTI_DoubleToNtp32(0.1);
res->reference_id = 0;
UTI_ZeroNtp64(&res->reference_ts);
res->originate_ts = interleaved ? req->receive_ts : req->transmit_ts;
advance_time(TST_GetRandomDouble(1e-4, 1e-2));
UTI_TimespecToNtp64(&current_time, &res->receive_ts, NULL);
advance_time(TST_GetRandomDouble(-1e-4, 1e-3));
UTI_TimespecToNtp64(&current_time, &res->transmit_ts, NULL);
advance_time(TST_GetRandomDouble(1e-4, 1e-2));
if (!valid_ts) {
switch (random() % (allow_update ? 4 : 5)) {
case 0:
res->originate_ts.hi = random();
break;
case 1:
res->originate_ts.lo = random();
break;
case 2:
UTI_ZeroNtp64(&res->originate_ts);
break;
case 3:
UTI_ZeroNtp64(&res->receive_ts);
break;
case 4:
UTI_ZeroNtp64(&res->transmit_ts);
break;
default:
assert(0);
}
}
if (authenticated) {
res->auth_keyid = req->auth_keyid;
KEY_GenerateAuth(ntohl(res->auth_keyid), (unsigned char *)res, NTP_NORMAL_PACKET_LENGTH,
res->auth_data, 16);
res_length = NTP_NORMAL_PACKET_LENGTH + 4 + 16;
} else {
res_length = NTP_NORMAL_PACKET_LENGTH;
}
if (!valid_auth) {
switch (random() % 3) {
case 0:
res->auth_keyid++;
break;
case 1:
res->auth_data[random() % 16]++;
break;
case 2:
res_length = NTP_NORMAL_PACKET_LENGTH;
break;
default:
assert(0);
}
}
}
static void
process_response(int valid, int updated)
{
NTP_Local_Address local_addr;
NTP_Local_Timestamp local_ts;
NTP_Packet *res;
uint32_t prev_rx_count, prev_valid_count;
struct timespec prev_rx_ts;
int prev_open_socket;
res = &res_buffer.ntp_pkt;
local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.if_index = INVALID_IF_INDEX;
local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) == MODE_ACTIVE ? 100 : 101;
local_ts.ts = current_time;
local_ts.err = 0.0;
local_ts.source = NTP_TS_DAEMON;
prev_rx_count = inst->report.total_rx_count;
prev_valid_count = inst->report.total_valid_count;
prev_rx_ts = inst->local_rx.ts;
prev_open_socket = inst->local_addr.sock_fd != INVALID_SOCK_FD;
NCR_ProcessRxKnown(inst, &local_addr, &local_ts, res, res_length);
if (prev_open_socket)
TEST_CHECK(prev_rx_count + 1 == inst->report.total_rx_count);
else
TEST_CHECK(prev_rx_count == inst->report.total_rx_count);
if (valid)
TEST_CHECK(prev_valid_count + 1 == inst->report.total_valid_count);
else
TEST_CHECK(prev_valid_count == inst->report.total_valid_count);
if (updated)
TEST_CHECK(UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
else
TEST_CHECK(!UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
}
void
test_unit(void)
{
char source_line[] = "127.0.0.1";
char conf[][100] = {
"port 0",
"keyfile ntp_core.keys"
};
int i, j, interleaved, authenticated, valid, updated, has_updated;
CPS_NTP_Source source;
NTP_Remote_Address remote_addr;
CNF_Initialise(0);
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
CNF_ParseLine(NULL, i + 1, conf[i]);
LCL_Initialise();
TST_RegisterDummyDrivers();
SCH_Initialise();
SRC_Initialise();
NIO_Initialise(IPADDR_UNSPEC);
NCR_Initialise();
REF_Initialise();
KEY_Initialise();
for (i = 0; i < 1000; i++) {
CPS_ParseNTPSourceAdd(source_line, &source);
if (random() % 2)
source.params.interleaved = 1;
if (random() % 2)
source.params.authkey = 1;
UTI_ZeroTimespec(&current_time);
advance_time(TST_GetRandomDouble(1.0, 1e9));
TST_GetRandomAddress(&remote_addr.ip_addr, IPADDR_UNSPEC, -1);
remote_addr.port = 123;
inst = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
NCR_StartInstance(inst);
has_updated = 0;
for (j = 0; j < 50; j++) {
DEBUG_LOG(0, "iteration %d, %d", i, j);
interleaved = random() % 2;
authenticated = random() % 2;
valid = (!interleaved || (source.params.interleaved && has_updated)) &&
(!source.params.authkey || authenticated);
updated = (valid || inst->mode == MODE_ACTIVE) &&
(!source.params.authkey || authenticated);
has_updated = has_updated || updated;
send_request();
send_response(interleaved, authenticated, 1, 0, 1);
process_response(0, inst->mode == MODE_CLIENT ? 0 : updated);
if (source.params.authkey) {
send_response(interleaved, authenticated, 1, 1, 0);
process_response(0, 0);
}
send_response(interleaved, authenticated, 1, 1, 1);
process_response(valid, updated);
process_response(0, 0);
advance_time(-1.0);
send_response(interleaved, authenticated, 1, 1, 1);
process_response(0, 0);
advance_time(1.0);
send_response(interleaved, authenticated, 1, 1, 1);
process_response(0, inst->mode == MODE_CLIENT ? 0 : updated);
}
NCR_DestroyInstance(inst);
}
KEY_Finalise();
REF_Finalise();
NCR_Finalise();
NIO_Finalise();
SRC_Finalise();
SCH_Finalise();
LCL_Finalise();
CNF_Finalise();
HSH_Finalise();
}

2
test/unit/ntp_core.keys Normal file
View File

@@ -0,0 +1,2 @@
1 MD5 HEX:38979C567358C0896F4D9D459A3C8B8478654579
2 MD5 HEX:38979C567358C0896F4D9D459A3C8B8478654579

View File

@@ -96,4 +96,5 @@ test_unit(void)
SCH_Finalise();
LCL_Finalise();
CNF_Finalise();
HSH_Finalise();
}

View File

@@ -134,4 +134,5 @@ test_unit(void)
SCH_Finalise();
LCL_Finalise();
CNF_Finalise();
HSH_Finalise();
}

View File

@@ -74,6 +74,14 @@ void test_unit(void) {
TEST_CHECK(!UTI_IsZeroTimespec(&ts));
TEST_CHECK(!UTI_IsZeroNtp64(&ntp_ts));
ntp_ts.hi = 0;
ntp_ts.lo = 0;
UTI_Ntp64ToTimespec(&ntp_ts, &ts);
TEST_CHECK(UTI_IsZeroTimespec(&ts));
UTI_TimespecToNtp64(&ts, &ntp_ts, NULL);
TEST_CHECK(UTI_IsZeroNtp64(&ntp_ts));
ntp_fuzz.hi = htonl(1);
ntp_fuzz.lo = htonl(3);
ntp_ts.hi = htonl(1);

11
util.c
View File

@@ -329,12 +329,14 @@ UTI_StringToIP(const char *addr, IPAddr *ip)
if (inet_pton(AF_INET, addr, &in4) > 0) {
ip->family = IPADDR_INET4;
ip->_pad = 0;
ip->addr.in4 = ntohl(in4.s_addr);
return 1;
}
if (inet_pton(AF_INET6, addr, &in6) > 0) {
ip->family = IPADDR_INET6;
ip->_pad = 0;
memcpy(ip->addr.in6, in6.s6_addr, sizeof (ip->addr.in6));
return 1;
}
@@ -344,6 +346,7 @@ UTI_StringToIP(const char *addr, IPAddr *ip)
n = sscanf(addr, "%lu.%lu.%lu.%lu", &a, &b, &c, &d);
if (n == 4) {
ip->family = IPADDR_INET4;
ip->_pad = 0;
ip->addr.in4 = ((a & 0xff) << 24) | ((b & 0xff) << 16) |
((c & 0xff) << 8) | (d & 0xff);
return 1;
@@ -442,6 +445,7 @@ void
UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest)
{
dest->family = ntohs(src->family);
dest->_pad = 0;
switch (dest->family) {
case IPADDR_INET4:
@@ -754,8 +758,11 @@ UTI_Ntp64ToTimespec(NTP_int64 *src, struct timespec *dest)
{
uint32_t ntp_sec, ntp_frac;
/* As yet, there is no need to check for zero - all processing that
has to detect that case is in the NTP layer */
/* Zero is a special value */
if (UTI_IsZeroNtp64(src)) {
UTI_ZeroTimespec(dest);
return;
}
ntp_sec = ntohl(src->hi);
ntp_frac = ntohl(src->lo);