Compare commits

..

56 Commits

Author SHA1 Message Date
Miroslav Lichvar
1f0e6296c6 doc: update NEWS 2015-06-22 12:54:52 +02:00
Miroslav Lichvar
ab1f01bacd ntp: use specific reference ID when smoothing served time
Set refid in server/broadcast packets to 127.127.1.255 when a time
smoothing offset is applied to the timestamps. This allows the clients
and administrators to detect that the server is not serving its best
estimate of the true time.
2015-06-22 12:54:50 +02:00
Miroslav Lichvar
b9b896d8e7 ntp: remove unnecessary casting 2015-06-22 12:54:33 +02:00
Miroslav Lichvar
6be54f366c reference: move definition of special refids to ntp.h 2015-06-22 12:54:22 +02:00
Miroslav Lichvar
802cdb3230 test: require latest clknetsim 2015-06-19 14:20:58 +02:00
Miroslav Lichvar
7e27880cb6 doc: update leapsecmode and smoothtime descriptions 2015-06-19 14:20:58 +02:00
Miroslav Lichvar
d3ad85aa43 doc: add Mac OS X to supported platforms 2015-06-18 16:35:26 +02:00
Miroslav Lichvar
59192fc695 update copyright years 2015-06-18 15:30:22 +02:00
Miroslav Lichvar
9095b80c5b doc: refer to authhash command in password command description 2015-06-17 18:31:16 +02:00
Miroslav Lichvar
ed5b78bf09 doc: convert FAQ to AsciiDoc and update it
It's now in a separate file again.
2015-06-17 18:05:14 +02:00
Bryan Christianson
d6aafa3f64 sys: MacOS X driver ported from NetBSD 2015-06-15 14:40:54 +02:00
Miroslav Lichvar
8de04a808d ntp: add debug message to print number of resolved addresses 2015-06-15 13:03:11 +02:00
Miroslav Lichvar
2a299233b3 update NEWS 2015-06-10 14:44:54 +02:00
Miroslav Lichvar
64f83c8861 cmdmon: reply with STT_INVALID on invalid option in handle_manual() 2015-06-09 17:05:45 +02:00
Miroslav Lichvar
1009fe3d9c makefile: warn when Makefile needs to be regenerated 2015-06-09 16:43:56 +02:00
Miroslav Lichvar
ba341fe81a sources: remove unused code in SRC_SelectSource() 2015-06-09 16:15:30 +02:00
Miroslav Lichvar
36e8cb6530 client: add smoothtime command 2015-06-09 16:15:30 +02:00
Miroslav Lichvar
273da62aec cmdmon: add smoothtime command
This adds a command to reset or activate the time smoothing process.
2015-06-09 16:15:30 +02:00
Miroslav Lichvar
41788184a7 client: add smoothing command 2015-06-09 16:15:30 +02:00
Miroslav Lichvar
fb9c2c7dc8 cmdmon: add smoothing command
This adds a new request to get a current report on time smoothing.
2015-06-09 16:15:30 +02:00
Miroslav Lichvar
43116be122 smooth: fix resetting 2015-06-08 17:22:01 +02:00
Miroslav Lichvar
ee038d5de5 cmdmon: use SCH_GetLastEventTime() to get current time
It's cheaper and accurate enough.
2015-06-08 15:07:18 +02:00
Miroslav Lichvar
ea7fae5277 sched: detect timeout overflow in SCH_AddTimeoutByDelay()
Abort when the system time gets so close to the end of 32-bit time_t
that timeouts added by delay start to overflow. This is an addition to
the loop detector in dispatch_timeouts().
2015-06-08 14:49:52 +02:00
Miroslav Lichvar
70b108ab69 array: allow arrays larger than 4 GB
It's not expected we will work with such large arrays anytime soon, but
better be safe than sorry.

Also, limit the number of elements to 2^31-1 to prevent infinite loop in
the calculation of allocated elements.
2015-06-08 14:43:16 +02:00
Miroslav Lichvar
08b152d6a2 test: add 202-prefer 2015-06-08 12:33:46 +02:00
Miroslav Lichvar
83c6213c67 test: add option to override generated server directives on client 2015-06-08 12:33:34 +02:00
Miroslav Lichvar
4253075a97 sources: fix marking of non-preferred selectable sources
When reducing the list of selectable sources to sources with the prefer
option, sources before the first preferred source were left with the
SRC_OK status, which triggered an assertion failure in the next
selection.
2015-06-08 11:54:43 +02:00
Miroslav Lichvar
0abdc2a350 smooth: add option to smooth out only leap seconds
The leaponly option can be used to enable a mode where only leap seconds
are smoothed out and normal offset/frequency changes are ignored. This
is useful to make the interval in which a leap second is smoothed out
constant and allow an NTP client to use multiple leap smearing servers
safely.
2015-06-02 15:24:01 +02:00
Miroslav Lichvar
31669f343a cmdmon: replace definitions of empty requests with null request 2015-06-01 15:00:14 +02:00
Miroslav Lichvar
438b881ab4 cmdmon: set only non-success status in command handling functions 2015-05-28 15:21:25 +02:00
Miroslav Lichvar
27863146a3 cmdmon: refactor allow/deny functions 2015-05-28 14:32:45 +02:00
Miroslav Lichvar
cd4b73612b ntp: include message precision in peer dispersion 2015-05-28 13:49:43 +02:00
Miroslav Lichvar
3c217a9e37 util: add UTI_Log2ToDouble() 2015-05-28 12:51:54 +02:00
Miroslav Lichvar
cde3a003ea util: handle NaN in UTI_FloatHostToNetwork() 2015-05-18 15:51:32 +02:00
Miroslav Lichvar
2c35f56612 client: handle empty hostname before slash in allow/deny commands 2015-05-18 15:36:52 +02:00
Miroslav Lichvar
4295db25d7 doc: remove chrony(1) man page
It's a copy of README, chrony(1) is not a program itself.
2015-05-18 13:15:43 +02:00
Miroslav Lichvar
3c06e57f24 ntp: increase minimum replacement interval to 30 minutes 2015-05-18 13:15:43 +02:00
Miroslav Lichvar
e949cf5967 ntp: replace non-pool sources when unreachable or falsetickers
Sources that are not specified as a pool and have a name (i.e. not
specified by an IP address or added from chronyc) will be replaced with
a newly resolved address of the name when they become unreachable or
falseticker too.
2015-05-18 13:15:42 +02:00
Miroslav Lichvar
4eeaf34295 ntp: add sources specified by IP directly without name resolving 2015-05-18 13:12:00 +02:00
Miroslav Lichvar
2212a90698 ntp: improve alignment of columns in banner for measurements log 2015-05-04 10:23:17 +02:00
Miroslav Lichvar
dc52b61dad doc: update NEWS 2015-04-27 12:58:19 +02:00
Miroslav Lichvar
bbf4c3186b doc: update chrony description 2015-04-27 12:58:19 +02:00
Miroslav Lichvar
f72016a78e doc: document when smoothtime function is activated 2015-04-27 12:27:55 +02:00
Miroslav Lichvar
29b587a9c5 sys: fix TMX_ResetOffset() to set status back correctly 2015-04-27 12:27:55 +02:00
Miroslav Lichvar
cec4f2b140 reference: use 2012 leap second in leapsectz test 2015-04-24 12:16:47 +02:00
Miroslav Lichvar
05278c3b4c sources: ignore reselect distance when combining with refclock 2015-04-20 12:59:12 +02:00
Miroslav Lichvar
1769b8ea0f use return to exit from main function 2015-04-17 17:34:02 +02:00
Miroslav Lichvar
5686bd87d7 client: improve usage line 2015-04-17 17:33:38 +02:00
Miroslav Lichvar
1cda2db45d main: print usage with -h option 2015-04-17 17:30:38 +02:00
Miroslav Lichvar
fdf9640349 ntp: don't log error when socket() fails for client only socket 2015-04-14 15:59:55 +02:00
Miroslav Lichvar
8f2d5d99f1 doc: don't mention ancient systems
Also, don't try to track working versions of supported systems, assume
current versions are ok.
2015-04-13 17:18:19 +02:00
Miroslav Lichvar
61272e7ce8 update copyright years 2015-04-10 11:06:32 +02:00
Miroslav Lichvar
88b76f49cc doc: warn that unauthenticated peers are vulnerable to DoS attack 2015-04-10 10:52:30 +02:00
Miroslav Lichvar
ad942e352d sys: clamp frequency set in generic driver on exit 2015-04-10 10:22:28 +02:00
Miroslav Lichvar
39c2bcd462 util: don't allow time too close to 32-bit time_t overflow
In UTI_IsTimeOffsetSane() consider time in one year interval before
32-bit time_t overflow (in 2038) as invalid. Hopefully everything will
be using 64-bit time_t when that time comes.
2015-04-10 10:05:15 +02:00
Miroslav Lichvar
ae10664b24 doc: fix CVE-ID in NEWS
CVE-2015-1853 is for chrony, CVE-2015-1799 is for ntp.
2015-04-08 08:44:42 +02:00
47 changed files with 1525 additions and 1084 deletions

2
.gitignore vendored
View File

@@ -2,6 +2,8 @@
.vimrc
*.o
*.swp
*.dSYM
*.DS_Store
RELEASES
Makefile
chrony.conf.5

View File

@@ -73,12 +73,14 @@ $(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ))
$(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $<
distclean : clean
-rm -f .DS_Store
-rm -f Makefile
-rm -f chrony.conf.5 chrony.texi chronyc.1 chronyd.8
clean :
-rm -f *.o *.s chronyc chronyd core *~ chrony.info chrony.html chrony.txt
-rm -rf .deps
-rm -rf *.dSYM
getdate.c :
bison -o getdate.c getdate.y
@@ -112,8 +114,6 @@ install: chronyd chronyc chrony.txt
chmod 644 $(DESTDIR)$(DOCDIR)/COPYING
cp README $(DESTDIR)$(DOCDIR)/README
chmod 644 $(DESTDIR)$(DOCDIR)/README
cp chrony.1 $(DESTDIR)$(MANDIR)/man1
chmod 644 $(DESTDIR)$(MANDIR)/man1/chrony.1
cp chronyc.1 $(DESTDIR)$(MANDIR)/man1
chmod 644 $(DESTDIR)$(MANDIR)/man1/chronyc.1
cp chronyd.8 $(DESTDIR)$(MANDIR)/man8
@@ -152,6 +152,12 @@ chrony.html : chrony.texi
chrony.info : chrony.texi
makeinfo chrony.texi
Makefile : Makefile.in configure
@echo
@echo Makefile needs to be regenerated, run ./configure
@echo
@exit 1
.deps:
@mkdir .deps

26
NEWS
View File

@@ -1,3 +1,24 @@
New in version 2.1
==================
Enhancements
------------
* Add support for Mac OS X
* Try to replace unreachable and falseticker servers/peers specified
by name like pool sources
* Add leaponly option to smoothtime directive to allow synchronised
leap smear between multiple servers
* Use specific reference ID when smoothing served time
* Add smoothing command to report time smoothing status
* Add smoothtime command to activate or reset time smoothing
Bug fixes
---------
* Fix crash in source selection with preferred sources
* Fix resetting of time smoothing
* Include packet precision in peer dispersion
* Fix crash in chronyc on invalid command syntax
New in version 2.0
==================
@@ -15,7 +36,7 @@ Enhancements
* Improve source selection
* Handle offline sources as unreachable
* Open NTP server port only when necessary (client access is allowed by
allow directive/command, peer or broadcast is configured)
allow directive/command or peer/broadcast is configured)
* Change default bindcmdaddress to loopback address
* Change default maxdelay to 3 seconds
* Change default stratumweight to 0.001
@@ -30,6 +51,7 @@ Bug fixes
---------
* Add sanity checks for time and frequency offset
* Don't report synchronised status during leap second
* Don't combine reference clocks with close NTP sources
* Fix accepting requests from configured sources
* Fix initial fallback drift setting
@@ -39,7 +61,7 @@ New in version 1.31.1
Security fixes
--------------
* Protect authenticated symmetric NTP associations against DoS attacks
(CVE-2015-1799)
(CVE-2015-1853)
* Fix access configuration with subnet size indivisible by 4 (CVE-2015-1821)
* Fix initialization of reply slots for authenticated commands (CVE-2015-1822)

84
README
View File

@@ -3,67 +3,35 @@ This is the README for chrony.
What is chrony?
===============
Chrony is a pair of programs for maintaining the accuracy of computer
clocks.
chrony is a versatile implementation of the Network Time Protocol (NTP).
It can synchronize the system clock with NTP servers, reference clocks
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
a time service to other computers in the network.
chronyd is a (background) daemon program that can be started at boot
time. This does most of the work.
It is designed to perform well in a wide range of conditions, including
intermittent network connections, heavily congested networks, changing
temperatures (ordinary computer clocks are sensitive to temperature),
and systems that do not run continuosly, or run on a virtual machine.
chronyc is a command-line interface program which can be used to
monitor chronyd's performance and to change various operating
parameters whilst it is running.
chronyd's main function is to obtain measurements of the true (UTC)
time from one of several sources, and correct the system clock
accordingly. It also works out the rate at which the system clock
gains or loses time and uses this information to keep it accurate
between measurements from the reference.
The reference time can be derived from Network Time Protocol (NTP)
servers, reference clocks, or wristwatch-and-keyboard (via chronyc).
The main source of information about the Network Time Protocol is
http://www.ntp.org.
It is designed so that it can work on computers which only have
intermittent access to reference sources, for example computers which
use a dial-up account to access the Internet or laptops. Of course, it
will work well on computers with permanent connections too.
In addition, on Linux it can monitor the system's real time clock
performance, so the system can maintain accurate time even across
reboots.
Typical accuracies available between 2 machines are
On an ethernet LAN : 100-200 microseconds, often much better
On a V32bis dial-up modem connection : 10's of milliseconds (from one
session to the next)
With a good reference clock the accuracy can reach one microsecond.
chronyd can also operate as an NTPv4 (RFC 5905) server, peer and broadcast
server.
Typical accuracy between two machines on a LAN is in tens, or a few
hundreds, of microseconds; over the Internet, accuracy is typically
within a few milliseconds. With a good hardware reference clock
sub-microsecond accuracy is possible.
Two programs are included in chrony, chronyd is a daemon that can be
started at boot time and chronyc is a command-line interface program
which can be used to monitor chronyd's performance and to change various
operating parameters whilst it is running.
What will chrony run on?
========================
Chrony can be successfully built and run on
1. Linux 2.2.x, 2.3.x, 2.4.x, 2.6.x, 3.x
2. Solaris 2.5/2.5.1/2.6/2.7/2.8 (various platforms)
3. SunOS 4.1.4 (Sparc 2 and Sparc 20)
4. BSD/386 v1.1 has been reported to work using the SunOS 4.1 driver.
5. NetBSD.
Any other system will require a porting exercise. You would need to
start from one of the existing system-specific drivers and look into
the quirks of certain system calls and the kernel on your target
system.
The software is known to work on Linux, FreeBSD, NetBSD, Mac OS X and
Solaris. Closely related systems may work too. Any other system will
likely require a porting exercise. You would need to start from one
of the existing system-specific drivers and look into the quirks of
certain system calls and the kernel on your target system.
How do I set it up?
===================
@@ -116,6 +84,11 @@ chrony-dev-request@chrony.tuxfamily.org
as applicable.
License
=======
chrony is distributed under the GNU General Public License version 2.
Author
======
@@ -155,6 +128,9 @@ Stephan I. Boettcher <stephan@nevis1.columbia.edu>
Erik Bryer <ebryer@spots.ab.ca>
Entries in contrib directory
Bryan Christianson <bryan@whatroute.net>
Support for Mac OS X
Juliusz Chroboczek <jch@pps.jussieu.fr>
Fix install rule in Makefile if chronyd file is in use.

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997,1998,1999,2000,2001,2002,2005
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009, 2015
*
* 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

12
array.c
View File

@@ -44,6 +44,8 @@ ARR_CreateInstance(unsigned int elem_size)
{
ARR_Instance array;
assert(elem_size > 0);
array = MallocNew(struct ARR_Instance_Record);
array->data = NULL;
@@ -64,6 +66,9 @@ ARR_DestroyInstance(ARR_Instance array)
static void
realloc_array(ARR_Instance array, unsigned int min_size)
{
size_t data_size;
assert(min_size <= 2 * min_size);
if (array->allocated >= min_size && array->allocated <= 2 * min_size)
return;
@@ -74,7 +79,10 @@ realloc_array(ARR_Instance array, unsigned int min_size)
array->allocated = min_size;
}
array->data = Realloc(array->data, array->elem_size * array->allocated);
data_size = (size_t)array->elem_size * array->allocated;
assert(data_size / array->elem_size == array->allocated);
array->data = Realloc(array->data, data_size);
}
void *
@@ -89,7 +97,7 @@ void *
ARR_GetElement(ARR_Instance array, unsigned int index)
{
assert(index < array->used);
return (void *)((char *)array->data + index * array->elem_size);
return (void *)((char *)array->data + (size_t)index * array->elem_size);
}
void *

92
candm.h
View File

@@ -89,7 +89,9 @@
#define REQ_RESELECT 48
#define REQ_RESELECTDISTANCE 49
#define REQ_MODIFY_MAKESTEP 50
#define N_REQUEST_TYPES 51
#define REQ_SMOOTHING 51
#define REQ_SMOOTHTIME 52
#define N_REQUEST_TYPES 53
/* Special utoken value used to log on with first exchange being the
password. (This time value has long since gone by) */
@@ -116,6 +118,10 @@ typedef struct {
pktlength.c, to get the number of bytes that ought to be
transmitted for each packet type. */
typedef struct {
int32_t EOR;
} REQ_Null;
typedef struct {
IPAddr mask;
IPAddr address;
@@ -215,19 +221,11 @@ typedef struct {
int32_t EOR;
} REQ_Manual;
typedef struct {
int32_t EOR;
} REQ_N_Sources;
typedef struct {
int32_t index;
int32_t EOR;
} REQ_Source_Data;
typedef struct {
int32_t EOR;
} REQ_Rekey;
typedef struct {
IPAddr ip;
int32_t subnet_bits;
@@ -264,10 +262,6 @@ typedef struct {
int32_t EOR;
} REQ_Del_Source;
typedef struct {
int32_t EOR;
} REQ_WriteRtc;
typedef struct {
Float dfreq;
int32_t EOR;
@@ -279,27 +273,11 @@ typedef struct {
int32_t EOR;
} REQ_Doffset;
typedef struct {
int32_t EOR;
} REQ_Tracking;
typedef struct {
uint32_t index;
int32_t EOR;
} REQ_Sourcestats;
typedef struct {
int32_t EOR;
} REQ_RTCReport;
typedef struct {
int32_t EOR;
} REQ_TrimRTC;
typedef struct {
int32_t EOR;
} REQ_CycleLogs;
/* This is based on the response size rather than the
request size */
#define MAX_CLIENT_ACCESSES 8
@@ -310,32 +288,24 @@ typedef struct {
int32_t EOR;
} REQ_ClientAccessesByIndex;
typedef struct {
int32_t EOR;
} REQ_ManualList;
typedef struct {
int32_t index;
int32_t EOR;
} REQ_ManualDelete;
typedef struct {
int32_t EOR;
} REQ_MakeStep;
typedef struct {
int32_t EOR;
} REQ_Activity;
typedef struct {
int32_t EOR;
} REQ_Reselect;
typedef struct {
Float distance;
int32_t EOR;
} REQ_ReselectDistance;
#define REQ_SMOOTHTIME_RESET 0
#define REQ_SMOOTHTIME_ACTIVATE 1
typedef struct {
int32_t option;
int32_t EOR;
} REQ_SmoothTime;
/* ================================================== */
#define PKT_TYPE_CMD_REQUEST 1
@@ -365,7 +335,7 @@ typedef struct {
Version 6 : added padding to requests to prevent amplification attack,
changed maximum number of samples in manual list to 16, new commands: modify
makestep
makestep, smoothing report, smoothtime command
*/
#define PROTO_VERSION_NUMBER 6
@@ -398,6 +368,7 @@ typedef struct {
uint32_t token; /* Command token (to prevent replay attack) */
union {
REQ_Null null;
REQ_Online online;
REQ_Offline offline;
REQ_Burst burst;
@@ -415,28 +386,18 @@ typedef struct {
REQ_Settime settime;
REQ_Local local;
REQ_Manual manual;
REQ_N_Sources n_sources;
REQ_Source_Data source_data;
REQ_Rekey rekey;
REQ_Allow_Deny allow_deny;
REQ_Ac_Check ac_check;
REQ_NTP_Source ntp_source;
REQ_Del_Source del_source;
REQ_WriteRtc writertc;
REQ_Dfreq dfreq;
REQ_Doffset doffset;
REQ_Tracking tracking;
REQ_Sourcestats sourcestats;
REQ_RTCReport rtcreport;
REQ_TrimRTC trimrtc;
REQ_CycleLogs cyclelogs;
REQ_ClientAccessesByIndex client_accesses_by_index;
REQ_ManualList manual_list;
REQ_ManualDelete manual_delete;
REQ_MakeStep make_step;
REQ_Activity activity;
REQ_Reselect reselect;
REQ_ReselectDistance reselect_distance;
REQ_SmoothTime smoothtime;
} data; /* Command specific parameters */
/* The following fields only set the maximum size of the packet.
@@ -472,7 +433,8 @@ typedef struct {
#define RPY_CLIENT_ACCESSES_BY_INDEX 10
#define RPY_MANUAL_LIST 11
#define RPY_ACTIVITY 12
#define N_REPLY_TYPES 13
#define RPY_SMOOTHING 13
#define N_REPLY_TYPES 14
/* Status codes */
#define STT_SUCCESS 0
@@ -627,6 +589,19 @@ typedef struct {
int32_t EOR;
} RPY_Activity;
#define RPY_SMT_FLAG_ACTIVE 0x1
#define RPY_SMT_FLAG_LEAPONLY 0x2
typedef struct {
uint32_t flags;
Float offset;
Float freq_ppm;
Float wander_ppm;
Float last_update_ago;
Float remaining_time;
int32_t EOR;
} RPY_Smoothing;
typedef struct {
uint8_t version;
uint8_t pkt_type;
@@ -653,6 +628,7 @@ typedef struct {
RPY_ClientAccessesByIndex client_accesses_by_index;
RPY_ManualList manual_list;
RPY_Activity activity;
RPY_Smoothing smoothing;
} data; /* Reply specific parameters */
/* authentication of the packet, there is no hole after the actual data

View File

@@ -1,72 +0,0 @@
.TH CHRONY 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
.SH NAME
chrony \- programs for keeping computer clocks accurate
.SH SYNOPSIS
\fBchronyc\fR [\fIOPTIONS\fR]
\fBchronyd\fR [\fIOPTIONS\fR]
.SH DESCRIPTION
\fBchrony\fR is a pair of programs for keeping computer clocks accurate.
\fIchronyd\fR is a background (daemon) program and \fIchronyc\fR is a
command-line interface to it. Time reference sources for chronyd can be
NTP servers, human (via keyboard and \fIchronyc\fR), or the computer's
real-time clock at boot time (Linux only). chronyd can determine the rate at
which the computer gains or loses time and compensate for it while no external
reference is present. Its use of NTP servers can be switched on and off
(through \fIchronyc\fR) to support computers with dial-up/intermittent access
to the Internet, and it can also act as an NTP server.
.SH USAGE
\fIchronyc\fR is a command-line interface program which can be used to
monitor \fIchronyd\fR's performance and to change various operating
parameters whilst it is running.
\fIchronyd\fR's main function is to obtain measurements of the true (UTC)
time from one of several sources, and correct the system clock
accordingly. It also works out the rate at which the system clock
gains or loses time and uses this information to keep it accurate
between measurements from the reference.
The reference time can be derived from either Network Time Protocol
(NTP) servers, reference clocks, or wristwatch-and-keyboard (via \fIchronyc\fR).
The main source of information about the Network Time Protocol is
\fIhttp://www.ntp.org\fR.
It is designed so that it can work on computers which only have
intermittent access to reference sources, for example computers which
use a dial-up account to access the Internet or laptops. Of course, it
will work well on computers with permanent connections too.
In addition, on Linux it can monitor the system's real time clock
performance, so the system can maintain accurate time even across
reboots.
Typical accuracies available between 2 machines are
On an ethernet LAN : 100-200 microseconds, often much better
On a V32bis dial-up modem connection : 10's of milliseconds (from one
session to the next)
With a good reference clock the accuracy can reach one microsecond.
\fIchronyd\fR can also operate as an NTPv4 (RFC 5905) server, peer and
broadcast server.
.SH "SEE ALSO"
.BR chronyc(1),
.BR chrony.conf(5),
.BR chronyd(8)
.I http://chrony.tuxfamily.org/
.SH AUTHOR
Richard Curnow <rc@rc0.org.uk>
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part
of "The Missing Man Pages Project". Please see
\fIhttp://www.netmeister.org/misc/m2p2/index.html\fR for details.
The complete chrony documentation is supplied in texinfo format.

View File

@@ -40,9 +40,8 @@ useful configuration file would look something like
When using a pool of NTP servers (one name is used for multiple servers which
may change over time), it's better to specify them with the `pool' directive
instead of multiple `server' directives in order to allow \fIchronyd\fR to
replace unreachable or bad servers automatically. The configuration file could
in this case look like
instead of multiple `server' directives. The configuration file could in this
case look like
.EX
pool pool.ntp.org iburst
@@ -52,7 +51,6 @@ in this case look like
.EE
.SH "SEE ALSO"
.BR chrony(1),
.BR chronyc(1),
.BR chronyd(8)

View File

@@ -24,7 +24,7 @@
@page
@vskip 0pt plus 1filll
Copyright @copyright{} 1997-1999 Richard P. Curnow
Copyright @copyright{} 2009-2014 Miroslav Lichvar
Copyright @copyright{} 2009-2015 Miroslav Lichvar
@end titlepage
@c }}}
@c {{{ Top node
@@ -35,7 +35,6 @@ Copyright @copyright{} 2009-2014 Miroslav Lichvar
* Installation:: How to compile and install the software
* Typical scenarios:: How to configure the software for some common cases
* Usage reference:: Reference manual
* FAQ:: Answers to some common questions about chrony
* GPL:: The GNU General Public License
@end menu
@c }}}
@@ -56,34 +55,30 @@ Copyright @copyright{} 2009-2014 Miroslav Lichvar
@c {{{ S:Overview
@node Overview
@section Overview
Chrony is a software package for maintaining the accuracy of computer
system clocks. It consists of a pair of programs :
chrony is a versatile implementation of the Network Time Protocol (NTP).
It can synchronize the system clock with NTP servers, reference clocks
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
a time service to other computers in the network.
@itemize @bullet
@item @code{chronyd}. This is a daemon which runs in background on the
system. It obtains measurements (e.g. via the network) of the system's
offset relative to other systems, and adjusts the system time
accordingly. For isolated systems, the user can periodically enter the
correct time by hand (using @code{chronyc}). In either case,
@code{chronyd} determines the rate at which the computer gains or loses
time, and compensates for this.
It is designed to perform well in a wide range of conditions, including
intermittent network connections, heavily congested networks, changing
temperatures (ordinary computer clocks are sensitive to temperature),
and systems that do not run continuosly, or run on a virtual machine.
@code{chronyd} can also act as an NTP server, and provide a time-of-day service
to other computers. A typical set-up is to run @code{chronyd} on a gateway
computer that has a dial-up link to the Internet, and use it to serve time to
computers on a private LAN sitting behind the gateway. The IP addresses that
can act as clients of @code{chronyd} can be tightly controlled. The default is
no client access.
Typical accuracy between two machines on a LAN is in tens, or a few
hundreds, of microseconds; over the Internet, accuracy is typically
within a few milliseconds. With a good hardware reference clock
sub-microsecond accuracy is possible.
@item @code{chronyc}. This is a command-line driven control and
monitoring program. An administrator can use this to fine-tune various
parameters within the daemon, add or delete servers etc whilst the
daemon is running.
Two programs are included in chrony, @code{chronyd} is a daemon that can
be started at boot time and @code{chronyc} is a command-line interface
program which can be used to monitor @code{chronyd}'s performance and to
change various operating parameters whilst it is running.
The IP addresses from which @code{chronyc} clients may connect can be tightly
controlled. The default is just the computer that @code{chronyd} itself is
running on.
@end itemize
@c }}}
@c {{{ S:Acknowledgments
@node Acknowledgements
@@ -123,24 +118,10 @@ different operating systems may provide different function calls to
achieve this, and even where the same function is used it may have
different quirks in its behaviour.
The software is known to work in the following environments:
@itemize @bullet
@item Linux 2.2 and newer
@item NetBSD
@item BSD/386
@item Solaris 2.3/2.5/2.5.1/2.6/2.7/2.8 on Sparc (Sparc 20, Ultrasparc) and
i386
@item SunOS 4.1.4 on Sparc 2 and Sparc20.
@end itemize
Closely related systems may work too, but they have not been tested.
Porting the software to other system (particularly to those supporting
an @code{adjtime} system call) should not be difficult, however it
requires access to such systems to test out the driver.
The software is known to work on Linux, FreeBSD, NetBSD, Mac OS X and Solaris.
Closely related systems may work too. Porting the software to other systems
(particularly to those supporting an @code{adjtime} system call) should not be
difficult, however it requires access to such systems to test out the driver.
@c }}}
@c {{{ S:Other programs
@node Other time synchronisation packages
@@ -305,8 +286,7 @@ Particular areas that need addressing are :
@item Porting to other Unices
This involves creating equivalents of sys_solaris.c, sys_linux.c etc for the
new system. Note, the Linux driver has been reported as working on a range of
different architectures (Alpha, Sparc, MIPS as well as x86 of course).
new system.
@item Porting to Windows NT
@@ -600,9 +580,8 @@ rtcsync
When using a pool of NTP servers (one name is used for multiple servers which
may change over time), it's better to specify them with the @code{pool}
directive instead of multiple @code{server} directives in order to allow
@code{chronyd} to replace unreachable or bad servers automatically. The
configuration file could in this case look like
directive instead of multiple @code{server} directives. The configuration file
could in this case look like
@example
pool pool.ntp.org iburst
@@ -1012,9 +991,8 @@ configuration file. This option is useful if you want to stop and
restart @code{chronyd} briefly for any reason, e.g. to install a new
version. However, it only makes sense on systems where the kernel can
maintain clock compensation whilst not under @code{chronyd's} control.
The only version where this happens so far is Linux. On systems where
this is not the case, e.g. Solaris and SunOS the option should not be
used.
The only version where this happens so far is Linux. On other systems
this option should not be used.
@item -R
When this option is used, the @code{initstepslew} directive and the
@code{makestep} directive used with a positive limit will be ignored.
@@ -1812,33 +1790,37 @@ start with the @code{generatecommandkey} directive.
@c {{{ leapsecmode
@node leapsecmode directive
@subsection leapsecmode
This directive selects how @code{chronyd} handles leap seconds. The Unix time
doesn't include leap seconds. When a leap second is applied to UTC, the system
clock is off by one second and it needs to be corrected.
A leap second is an adjustment that is occasionally applied to UTC to keep it
close to the mean solar time. When a leap second is inserted, the last day of
June or December has an extra second 23:59:60.
There are four options:
For computer clocks that is a problem. The Unix time is defined as number of
seconds since 00:00:00 UTC on 1 January 1970 without leap seconds. The system
clock cannot have time 23:59:60, every minute has 60 seconds and every day has
86400 seconds by definition. The inserted leap second is skipped and the clock
is suddenly ahead of UTC by one second. The @code{leapsecmode} directive
selects how that error is corrected. There are four options:
@table @code
@item system
The kernel steps the system clock backwards by one second at 0:00:00 UTC
(before correction) when leap second is inserted or steps forward by one second
at 23:59:59 UTC when leap second is deleted. This is the default mode when the
system driver supports leap seconds (currently Linux only).
When inserting a leap second, the kernel steps the system clock backwards by
one second when the clock gets to 00:00:00 UTC. When deleting a leap second,
it steps forward by one second when the clock gets to 23:59:59 UTC. This is
the default mode when the system driver supports leap seconds (currently Linux
only).
@item step
This is similar to the system mode, except the clock is stepped by
@code{chronyd} instead of the kernel. This is the default mode when the system
driver doesn't support leap seconds.
This is similar to the @code{system} mode, except the clock is stepped by
@code{chronyd} instead of the kernel. It can be useful to avoid bugs in the
kernel code that would be executed in the @code{system} mode. This is the
default mode when the system driver doesn't support leap seconds.
@item slew
The clock is corrected by slew starting at 0:00:00 UTC when leap second is
inserted or 23:59:59 UTC when leap second is deleted. This may be preferred
over the system or step mode when applications running on the system are
sensitive to jumps in the system time and it's acceptable that the clock will
be off for a longer time. On Linux with the default @code{maxslewrate} the
correction takes 12 seconds. Note that unless the @code{smoothtime} directive
is used (@pxref{smoothtime directive}), there will still be a jump in the time
that @code{chronyd} serves to NTP clients. With the @code{smoothtime}
directive, the leap second status will not be passed to NTP clients and the
leap second will be "smeared" instead.
The clock is corrected by slewing started at 00:00:00 UTC when a leap second is
inserted or 23:59:59 UTC when a leap second is deleted. This may be preferred
over the @code{system} and @code{step} modes when applications running on the
system are sensitive to jumps in the system time and it's acceptable that the
clock will be off for a longer time. On Linux with the default
@code{maxslewrate} value (@pxref{maxslewrate directive}) the correction takes
12 seconds.
@item ignore
No correction is applied to the clock for the leap second. The clock will be
corrected later in normal operation when new measurements are made and the
@@ -1851,19 +1833,40 @@ An example of the command is
leapsecmode slew
@end example
An example enabling the leap smear for NTP clients with the @code{smoothtime}
directive could be
When serving time to NTP clients that can't be configured to correct their
clocks for a leap second by slewing or they would correct them at slightly
different rates when it's necessary to keep them close together, the
@code{slew} mode can be combined with the @code{smoothtime} directive
(@pxref{smoothtime directive}) to enable a server leap smear.
When smearing a leap second, the leap status is suppressed on the server and
the served time is corrected slowly be slewing instead of stepping. The clients
don't need any special configuration as they don't know there is any leap
second and they follow the server time which eventually brings them back to
UTC. Care must be taken to ensure they use for synchronization only NTP
servers which smear the leap second in exactly the same way.
This feature needs to be used carefully, because the server is intentionally
not serving its best estimate of the true time.
A recommended configuration to enable a server leap smear is:
@example
leapsecmode slew
smoothtime 400 0.001
maxslewrate 1000
smoothtime 400 0.001 leaponly
@end example
With this configuration the NTP clients would not know there was any leap
second. The server time they follow would be slowly corrected in about 16
hours after the leap second was applied to UTC. This configuration should not
be used if the clients poll also other NTP servers, because they could reject
this server as a falseticker or could fail to select a source completely.
The first directive is necessary to disable the clock step which would reset
the smoothing process. The second directive limits the slewing rate of the
local clock to 1000 ppm, which improves the stability of the smoothing process
when the local correction starts and ends. The third directive enables the
server time smoothing process. It will start when the clock gets to 00:00:00
UTC and it will take 17 hours 34 minutes to finish. The frequency offset will
be changing by 0.001 ppm per second and will reach maximum of 31.623 ppm. The
@code{leaponly} option makes the duration of the leap smear constant and allows
the clients to safely synchronise with multiple identically configured leap
smearing servers.
@c }}}
@c {{{ leapsectz
@node leapsectz directive
@@ -2543,6 +2546,21 @@ be reported using the @code{clients} command in @code{chronyc}.
The syntax of this directive is identical to that for the @code{server}
directive (@pxref{server directive}), except that it is used to specify
an NTP peer rather than an NTP server.
Please note that NTP peers that are not configured with a key to enable
authentication are vulnerable to a denial-of-service attack. An attacker
knowing that NTP hosts A and B are peering with each other can send a packet
with random timestamps to host A with source address of B which will set the
NTP state variables on A to the values sent by the attacker. Host A will then
send on its next poll to B a packet with originate timestamp that doesn't match
the transmit timestamp of B and the packet will be dropped. If the attacker
does this periodically for both hosts, they won't be able to synchronize to
each other.
This attack can be prevented by enabling authentication with the key option, or
using the @code{server} directive on both sides to specify the other host as a
server instead of peer, the only drawback is that it will double the network
traffic between the two hosts.
@c }}}
@c {{{ pidfile
@node pidfile directive
@@ -3047,19 +3065,34 @@ it and keep their clocks close together even when large offset or frequency
corrections are applied to the server's clock, for example after being offline
for a longer time.
If a large offset has been accumulated, it may take a very long time to smooth
it out. This directive should be used only when the clients are not configured
to poll also another NTP server, because they could reject this server as a
falseticker or fail to select a source completely.
BE WARNED - the server is intentionally not serving its best estimate of the
true time. If a large offset has been accumulated, it may take a very long
time to smooth it out. This directive should be used only when the clients are
not configured to poll also another NTP server, because they could reject this
server as a falseticker or fail to select a source completely.
The smoothing process is independent from any slewing applied to the local
system clock, but the accumulated offset and frequency for smoothing will be
reset when the clock is corrected by step, e.g. by the @code{makestep}
directive or command.
The smoothing process is implemented with a quadratic spline function with two
or three pieces. It's independent from any slewing applied to the local system
clock, but the accumulated offset and frequency will be reset when the clock is
corrected by stepping, e.g. by the @code{makestep} directive or command. The
process can be reset without stepping the clock by the @code{smoothtime reset}
command (@pxref{smoothtime command}).
The directive takes two arguments, the maximum frequency offset of the smoothed
time to the tracked NTP time (in ppm) and the maximum rate at which the
frequency offset is allowed to change (in ppm per second).
The first two arguments of the directive are the maximum frequency offset of
the smoothed time to the tracked NTP time (in ppm) and the maximum rate at
which the frequency offset is allowed to change (in ppm per second).
@code{leaponly} is an optional third argument which enables a mode where only
leap seconds are smoothed out and normal offset/frequency changes are ignored.
The @code{leaponly} option is useful in a combination with the
@code{leapsecmode slew} option (@pxref{leapsecmode directive}) to allow clients
use multiple time smoothing servers safely.
The smoothing process is activated automatically when 1/10000 of the estimated
skew of the local clock falls below the maximum rate of frequency change. It
can be also activated manually by the @code{smoothtime activate} command,
which is particularly useful when the clock is synchronized only with manual
input and the skew is always larger than the threshold. The @code{smoothing}
command (@pxref{smoothing command}) can be used to monitor the process.
An example suitable for clients using @code{ntpd} and 1024 second polling
interval could be
@@ -3288,6 +3321,7 @@ password:
@item @code{password}
@item @code{quit}
@item @code{rtcdata}
@item @code{smoothing}
@item @code{sources}
@item @code{sourcestats}
@item @code{tracking}
@@ -3348,6 +3382,8 @@ interface.
* retries command:: Set maximum number of retries
* rtcdata command:: Display RTC parameters
* settime command:: Provide a manual input of the current time
* smoothing command:: Display current time smoothing state
* smoothtime command:: Reset/activate server time smoothing
* sources command:: Display information about the current set of sources
* sourcestats command:: Display the rate & offset estimation performance of sources
* timeout command:: Set initial response timeout
@@ -3471,10 +3507,11 @@ directive in the configuration file.
@c {{{ authhash
@node authhash command
@subsubsection authhash
This command sets the hash function used for authenticating user commands.
For successful authentication the hash function has to be the same as the one
set for the command key in the keys file on the server. It needs to be set
before the @code{password} command is used. The default hash function is MD5.
This command selects the hash function used for authenticating user commands.
For successful authentication the hash function has to be the same as the
function specified for the command key in the keys file on the server
(@pxref{keyfile directive}). It needs to be selected before the
@code{password} command is used. The default hash function is MD5.
An example is
@@ -4165,14 +4202,15 @@ password
@end example
The computer will respond with a @samp{Password:} prompt, at which you
should enter the password and press return. (Note that the no-echo mode
is limited to 8 characters on SunOS 4.1 due to limitations in the system
library. Other systems do not have this restriction.)
should enter the password and press return.
The password can be encoded as a string of characters not containing a space
with optional @code{ASCII:} prefix or as a hexadecimal number with @code{HEX:}
prefix. It has to match @code{chronyd's} currently defined command key
(@pxref{commandkey directive}).
(@pxref{commandkey directive}). If the command key was specified with a
different hash function than MD5, it's necessary to select the hash function
with the @code{authhash} command (@pxref{authhash command}) before entering the
password.
The password command is run automatically on start if @code{chronyc} was
started with the `-a' option.
@@ -4326,6 +4364,66 @@ settime Nov 21, 1997 16:30:05
For a full description of @code{getdate}, get hold of the getdate
documentation (bundled, for example, with the source for GNU tar).
@c }}}
@c {{{ smoothing
@node smoothing command
@subsubsection smoothing
The @code{smoothing} command displays the current state of the NTP server time
smoothing. An example of the output is shown below.
@example
Active : Yes
Offset : +1.000268817 seconds
Frequency : -0.142859 ppm
Wander : -0.010000 ppm per second
Last update : 17.8 seconds ago
Remaining time : 19988.4 seconds
@end example
The fields are explained as follows.
@table @code
@item Active
This shows if the server time smoothing is currently active. Possible values
are @code{Yes} and @code{No}. If the @code{leaponly} option is included in the
@code{smoothtime} directive, @code{(leap second only)} will be shown on the
line.
@item Offset
This is the current offset applied to the time sent to NTP clients. Positive
value means the clients are getting time that's ahead of true time.
@item Frequency
The current frequency offset of the served time. Negative value means the time
observed by clients is running slower than true time.
@item Wander
The current frequency wander of the served time. Negative value means the time
observed by clients is slowing down.
@item Last update
This field shows how long ago was the time smoothing process updated, e.g.
@code{chronyd} accumulated a new measurement.
@item Remaining time
The time it would take for the smoothing process to get to zero offset and
frequency if there were no more updates.
@end table
@c }}}
@c {{{ smoothtime
@node smoothtime command
@subsubsection smoothtime
The @code{smoothtime} command can be used to reset or activate the server time
smoothing process if it is configured with the @code{smoothtime} directive
(@pxref{smoothtime directive}).
The syntax is as follows
@example
smoothtime reset
smoothtime activate
@end example
@c }}}
@c {{{ sources
@node sources command
@@ -4551,7 +4649,7 @@ true time (which it reports to NTP clients when it is operating in
server mode). The value reported on this line is the difference due to
this effect.
On systems such as Solaris and SunOS, @code{chronyd} has no means to
On systems other than Linux, @code{chronyd} doesn't
adjust the fundamental rate of the system clock, so keeps the system
time correct by periodically making offsets to it as though an error had
been measured. The build up of these offsets will be observed in this
@@ -4696,332 +4794,6 @@ command is issued.
@c }}}
@c }}}
@c }}}
@c {{{ Ch:FAQ
@node FAQ
@chapter Frequently asked questions
@c {{{ Chapter top
@menu
* Administrative issues::
* Chrony compared to other programs::
* Configuration issues::
* Computer is not synchronising::
* Issues with chronyc::
* Real-time clock issues::
* Microsoft Windows::
* NTP-specific issues::
* Linux-specific issues::
* Solaris-specific issues::
@end menu
@c }}}
@c {{{ S:Administrative issues
@node Administrative issues
@section Administrative issues
@subsection Where can I get chrony source code?
Tarballs are available via the @code{Download} link on the chrony web site.
For the current development from the developers' version control system see the
@code{Git} link on the web site.
@subsection Are there any packaged versions of chrony?
We are aware of packages for Arch, CentOS, Debian, Fedora, Gentoo, Mageia,
OpenSuse, Slackware, Ubuntu, FreeBSD and NetBSD. We are not involved with how
these are built or distributed.
@subsection Where is the home page?
It is currently at
@uref{http://chrony.tuxfamily.org, http://chrony.tuxfamily.org}.
@subsection Is there a mailing list?
Yes, it's currently at @email{chrony-users@@chrony.tuxfamily.org}. There is a
low-volume list called chrony-announce which is just for announcements of new
releases or similar matters of high importance. You can join the lists by
sending a message with the subject subscribe to
@email{chrony-users-request@@chrony.tuxfamily.org} or
@email{chrony-announce-request@@chrony.tuxfamily.org} respectively.
For those who want to contribute to the development of chrony, there is a
developers' mailing list. You can subscribe by sending mail with the subject
subscribe to @email{chrony-dev-request@@chrony.tuxfamily.org}.
@subsection What licence is applied to chrony?
Starting from version 1.15, chrony is licensed under the GNU General Public
License, Version 2. Versions prior to 1.15 were licensed under a custom
BSD-like license.
@c }}}
@c {{{ S:Chrony compared to other programs
@node Chrony compared to other programs
@section Chrony compared to other programs
@subsection How does chrony compare to ntpd?
Chrony can usually synchronise the system clock faster and with better time
accuracy, but it doesn't implement all NTP features, e.g. broadcast/multicast
mode, or authentication based on public-key cryptography. For a more detailed
comparison, see section @code{Comparison with ntpd} in the manual.
If your computer connects to the 'net only for few minutes at a time, you turn
your Linux computer off or suspend it frequently, the clock is not very stable
(e.g. it is a virtual machine), or you want to use NTP on an isolated network
with no hardware clocks in sight, chrony will probably work much better for
you.
The original reason chrony was written was that ntpd (called xntpd at the
time) could not to do anything sensible on a PC which was connected to
the 'net only for about 5 minutes once or twice a day, mainly to
upload/download email and news. The requirements were
@itemize @bullet
@item slew the time to correct it when going online and NTP servers become
visible
@item determine the rate at which the computer gains or loses time and use this
information to keep it reasonably correct between connects to the 'net. This
has to be done using a method that does not care about the intermittent
availability of the references or the fact the computer is turned off between
groups of measurements.
@item maintain the time across reboots, by working out the error and drift rate
of the computer's real-time clock and using this information to set the system
clock correctly at boot up.
@end itemize
Also, when working with isolated networks with no true time references at all
ntpd was found to give no help with managing the local clock's gain/loss rate
on the NTP master node (which was set from watch). Some automated support was
added to chrony to deal with this.
@c }}}
@c {{{ S:Configuration issues
@node Configuration issues
@section Configuration issues
@subsection I have several computers on a LAN. Should be all clients of an external server?
The best configuration is usually to make one computer the master, with the
others as clients of it. Add a @code{local} directive to the master's
chrony.conf file. This configuration will be better because
@itemize @bullet
@item the load on the external connection is less
@item the load on the external NTP server(s) is less
@item if your external connection goes down, the computers on the LAN will
maintain a common time with each other.
@end itemize
@subsection Must I specify servers by IP address if DNS is not available on chronyd start?
No. Starting from version 1.25, @code{chronyd} will keep trying to resolve the
hostnames specified in the @code{server} and @code{peer} directives in
increasing intervals until it succeeds. The @code{online} command can be
issued from @code{chronyc} to try to resolve them immediately.
@subsection How can I make chronyd more secure?
If you don't need to serve time to NTP clients or peers, you can add
@code{port 0} to the @file{chrony.conf} file to completely disable the NTP
server functionality and prevent NTP requests from reaching @code{chronyd}.
Starting from version 2.0, the NTP server port is open only when client access
is allowed by the @code{allow} directive or command, an NTP peer is configured,
or the @code{broadcast} directive is used.
If you don't need to use @code{chronyc} remotely, you can add the following
directives to the configuration file to bind the command sockets to the
loopback interface. This is done by default since version 2.0.
@example
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
@end example
If you don't need to use @code{chronyc} at all, you can disable the command
sockets by adding @code{cmdport 0} to the configuration file.
On Linux, if @code{chronyd} is compiled with support for Linux capabilities
(available in the libcap library), you can specify an unprivileged user with
the `-u' option or @code{user} directive in the @file{chrony.conf} file to drop
root privileges after start. The configure option @code{--with-user} can be
used to drop the privileges by default.
@subsection How can I improve the accuracy of the system clock with NTP sources?
Select NTP servers that are well synchronised, stable and close to your network.
It's better to use more than one server, three or four is usually recommended as
the minimum, so @code{chronyd} can detect falsetickers and combine measurements
from multiple sources.
There are also useful options which can be set in the @code{server} directive,
they are @code{minpoll}, @code{maxpoll}, @code{polltarget}, @code{maxdelay},
@code{maxdelayratio} and @code{maxdelaydevratio}.
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 @code{minpoll}, 10 (1024 seconds) for
@code{maxpoll} and 6 (samples) for @code{polltarget}. The default values
should be used for general servers on the internet. With your own NTP servers
or if have permission to poll some servers more frequently, setting these
options for shorter polling intervals may significantly improve the accuracy of
the system clock.
The optimal polling interval depends on many factors, including the ratio
between the wander of the clock and the network jitter (sometimes expressed in
NTP documents as the Allan intercept), the temperature sensitivity of the
crystal oscillator and the maximum rate of change of the temperature.
An example of the directive for an NTP server on the internet that you are
allowed to poll frequently could be
@example
server foo.example.net minpoll 4 maxpoll 6 polltarget 16
@end example
An example using very short polling intervals for a server located in the
same LAN could be
@example
server ntp.local minpoll 2 maxpoll 4 polltarget 30
@end example
The maxdelay options are useful to ignore measurements with larger delay (e.g.
due to congestion in the network) and improve the stability of the
synchronisation. The @code{maxdelaydevratio} option could be added to the
example with local NTP server
@example
server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
@end example
@c }}}
@c {{{ S:Computer is not synchronising
@node Computer is not synchronising
@section Computer is not synchronising
This is the most common problem. There are a number of reasons, see the
following questions.
@subsection Behind a firewall?
If there is a firewall between you and the NTP server you're trying to use,
the packets may be blocked. Try using a tool like wireshark or tcpdump to see
if you're getting responses from the server. If you have an external modem,
see if the receive light blinks straight after the transmit light (when the
link is quiet apart from the NTP traffic.) Try adding @code{log measurements}
to the @file{chrony.conf} file and look in the measurements.log file after
chrony has been running for a short period. See if any measurements appear.
@subsection Do you have a non-permanent (i.e. intermittent) Internet connection?
Check that you're using chronyc's @code{online} and @code{offline} commands
appropriately. Again, check in measurements.log to see if you're getting any
data back from the server.
@subsection In measurements.log, do the '7' and '8' flag columns always show zero?
Do you have a @code{local stratum X} directive in the @file{chrony.conf} file? If X
is lower than the stratum of the server you're trying to use, this situation
will arise. You should always make X quite high (e.g. 10) in this directive.
@c }}}
@c {{{ S:Issues with chronyc
@node Issues with chronyc
@section Issues with chronyc
@subsection I keep getting the error @code{506 Cannot talk to daemon}
When accessing @code{chronyd} remotely, make sure that the @file{chrony.conf}
file (on the computer where @code{chronyd} is running) has a @code{cmdallow}
entry for the computer you are running @code{chronyc} on and an appropriate
@code{bindcmdaddress} directive. This isn't necessary for localhost.
Perhaps @code{chronyd} is not running. Try using the ps command (e.g. on
Linux, 'ps -auxw') to see if it's running. Or try 'netstat -a' and see if the
ports 123/udp and 323/udp are listening. If @code{chronyd} is not running, you
may have a problem with the way you are trying to start it (e.g. at boot time).
Perhaps you have a firewall set up in a way that blocks packets on port
323/udp. You need to amend the firewall configuration in this case.
@subsection Is the chronyc<->chronyd protocol documented anywhere?
Only by the source code :-) See cmdmon.c (@code{chronyd} side) and client.c
(@code{chronyc} side).
@c }}}
@c {{{ S:Real-time clock issues
@node Real-time clock issues
@section Real-time clock issues
@subsection What is the real-time clock (RTC)?
This is the clock which keeps the time even when your computer is turned off.
It works with 1 second resolution. @code{chronyd} can monitor the rate at
which the real-time clock gains or loses time, and compensate for it when you
set the system time from it at the next reboot. See the documentation for
details.
@subsection I want to use chronyd's real-time clock support. Must I disable hwclock?
The hwclock program is often set-up by default in the boot and shutdown scripts
with many Linux installations. If you want to use chronyd's real-time clock
support, the important thing is to disable hwclock in the shutdown procedure.
If you don't, it will over-write the RTC with a new value, unknown to
@code{chronyd}. At the next reboot, @code{chronyd} will compensate this (wrong)
time with its estimate of how far the RTC has drifted whilst the power was off,
giving a meaningless initial system time.
There is no need to remove hwclock from the boot process, as long as
@code{chronyd} is started after it has run.
@subsection I just keep getting the '513 RTC driver not running' message
For the real time clock support to work, you need the following three things
@itemize @bullet
@item a kernel that is supported (e.g. 2.2 onwards)
@item enhanced RTC support compiled into the kernel
@item an @code{rtcfile} directive in your chrony.conf file
@end itemize
@c }}}
@c {{{ S:Microsoft Windows
@node Microsoft Windows
@section Microsoft Windows
@subsection Does chrony support Windows?
No. The @code{chronyc} program (the command-line client used for configuring
@code{chronyd} while it is running) has been successfully built and run under
Cygwin in the past. @code{chronyd} is not portable, because part of it is very
system-dependent. It needs adapting to work with Windows' equivalent of the
adjtimex() call, and it needs to be made to work as an NT service.
@subsection Are there any plans to support Windows?
We have no plans to do this. Anyone is welcome to pick this work up and
contribute it back to the project.
@c }}}
@c {{{ S:NTP-specific issues
@node NTP-specific issues
@section NTP-specific issues
@subsection Can chrony be driven from broadcast NTP servers?
No, this NTP mode is not implemented yet.
@subsection Can chronyd transmit broadcast NTP packets (e.g. to synchronise other computers on a private LAN)?
Yes. Starting from version 1.17, chrony has this capability.
@subsection Can chrony keep the system clock a fixed offset away from real time?
This is not possible as the program currently stands.
@subsection What happens if the network connection is dropped without using chronyc's 'offline' command first?
In this case @code{chronyd} will keep trying to access the server(s) that it
thinks are online. Eventually it will decide that they are unreachable and no
longer consider itself synchronised to them. If you have other computers on
your LAN accessing the computer that is affected this way, they too will become
'unsynchronised', unless you have the 'local' directive set up on the master
computer.
The 'auto_offline' option to the 'server' entry in the chrony.conf file may be
useful to avoid this situation.
@c }}}
@c {{{ S:Linux-specific issues
@node Linux-specific issues
@section Linux-specific issues
@subsection I get "Could not open /dev/rtc, Device or resource busy" in my syslog file
Some other program running on the system may be using the device.
@c }}}
@c {{{ S:Solaris-specific issues
@node Solaris-specific issues
@section Solaris-specific issues
@subsection On Solaris 2.8, I get an error message about not being able to open kvm to change dosynctodr
(The dosynctodr variable controls whether Solaris couples the equivalent of its
BIOS clock into its system clock at regular intervals). The Solaris port of
chrony was developed in the Solaris 2.5 era. Some aspect of the Solaris kernel
has changed which prevents the same technique working. We no longer have root
access to any Solaris machines to work on this, and we are reliant on somebody
developing the patch and testing it.
@c }}}
@c }}}
@c {{{ apx:GNU General Public License
@node GPL
@appendix GNU General Public License

View File

@@ -60,8 +60,7 @@ interactively.
To report bugs, please visit \fIhttp://chrony.tuxfamily.org\fR
.SH "SEE ALSO"
.BR chronyd(8),
.BR chrony(1)
.BR chronyd(8)
.I http://chrony.tuxfamily.org/

View File

@@ -70,8 +70,7 @@ option is useful if you want to stop and restart \fBchronyd\fR briefly for any
reason, e.g. to install a new version. However, it only makes sense on
systems where the kernel can maintain clock compensation whilst not under
\fBchronyd\fR's control. The only version where this happens so far is Linux.
On systems where this is not the case, e.g. Solaris and SunOS the option
should not be used.
On other systems this option should not be used.
.TP
.B \-R
When this option is used, the \fIinitstepslew\fR directive and the
@@ -135,7 +134,6 @@ To report bugs, please visit \fIhttp://chrony.tuxfamily.org/\fR
\fBchronyd\fR is documented in detail in the documentation supplied with the
distribution (\fIchrony.txt\fR and \fIchrony.texi\fR).
.BR chrony(1),
.BR chronyc(1),
.BR chrony.conf(5),
.BR hwclock(8),

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2014
* Copyright (C) Miroslav Lichvar 2009-2015
*
* 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
@@ -640,7 +640,8 @@ process_cmd_manual(CMD_Request *msg, const char *line)
static int
parse_allow_deny(CMD_Request *msg, char *line)
{
unsigned long a, b, c, d, n;
unsigned long a, b, c, d;
int n, specified_subnet_bits;
IPAddr ip;
char *p;
@@ -657,7 +658,7 @@ parse_allow_deny(CMD_Request *msg, char *line)
n = 0;
if (!UTI_StringToIP(p, &ip) &&
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) == 0) {
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) <= 0) {
/* Try to parse as the name of a machine */
if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
@@ -710,7 +711,6 @@ parse_allow_deny(CMD_Request *msg, char *line)
UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip);
if (slashpos) {
int specified_subnet_bits, n;
n = sscanf(slashpos+1, "%d", &specified_subnet_bits);
if (n == 1) {
msg->data.allow_deny.subnet_bits = htonl(specified_subnet_bits);
@@ -1184,6 +1184,8 @@ give_help(void)
printf("reselect : Reselect synchronisation source\n");
printf("rtcdata : Print current RTC performance parameters\n");
printf("settime <date/time (e.g. Nov 21, 1997 16:30:05 or 16:30:05)> : Manually set the daemon time\n");
printf("smoothing : Display current time smoothing state\n");
printf("smoothtime reset|activate : Reset/activate time smoothing\n");
printf("sources [-v] : Display information about current sources\n");
printf("sourcestats [-v] : Display estimation information about current sources\n");
printf("tracking : Display system time information\n");
@@ -1964,6 +1966,63 @@ process_cmd_tracking(char *line)
}
/* ================================================== */
static int
process_cmd_smoothing(char *line)
{
CMD_Request request;
CMD_Reply reply;
uint32_t flags;
double offset;
double freq_ppm;
double wander_ppm;
double last_update_ago;
double remaining_time;
request.command = htons(REQ_SMOOTHING);
if (request_reply(&request, &reply, RPY_SMOOTHING, 0)) {
flags = ntohl(reply.data.smoothing.flags);
offset = UTI_FloatNetworkToHost(reply.data.smoothing.offset);
freq_ppm = UTI_FloatNetworkToHost(reply.data.smoothing.freq_ppm);
wander_ppm = UTI_FloatNetworkToHost(reply.data.smoothing.wander_ppm);
last_update_ago = UTI_FloatNetworkToHost(reply.data.smoothing.last_update_ago);
remaining_time = UTI_FloatNetworkToHost(reply.data.smoothing.remaining_time);
printf("Active : %s%s\n",
flags & RPY_SMT_FLAG_ACTIVE ? "Yes" : "No",
flags & RPY_SMT_FLAG_LEAPONLY ? " (leap second only)" : "");
printf("Offset : %+.9f seconds\n", offset);
printf("Frequency : %+.6f ppm\n", freq_ppm);
printf("Wander : %+.6f ppm per second\n", wander_ppm);
printf("Last update : %.1f seconds ago\n", last_update_ago);
printf("Remaining time : %.1f seconds\n", remaining_time);
return 1;
}
return 0;
}
/* ================================================== */
static int
process_cmd_smoothtime(CMD_Request *msg, const char *line)
{
if (!strcmp(line, "reset")) {
msg->data.smoothtime.option = htonl(REQ_SMOOTHTIME_RESET);
} else if (!strcmp(line, "activate")) {
msg->data.smoothtime.option = htonl(REQ_SMOOTHTIME_ACTIVATE);
} else {
fprintf(stderr, "Invalid syntax for smoothtime command\n");
return 0;
}
msg->command = htons(REQ_SMOOTHTIME);
return 1;
}
/* ================================================== */
static int
process_cmd_rtcreport(char *line)
{
@@ -2535,6 +2594,11 @@ process_line(char *line, int *quit)
} else if (!strcmp(command, "settime")) {
do_normal_submit = 0;
ret = process_cmd_settime(line);
} else if (!strcmp(command, "smoothing")) {
do_normal_submit = 0;
ret = process_cmd_smoothing(line);
} else if (!strcmp(command, "smoothtime")) {
do_normal_submit = process_cmd_smoothtime(&tx_message, line);
} else if (!strcmp(command, "sources")) {
do_normal_submit = 0;
ret = process_cmd_sources(line);
@@ -2681,7 +2745,7 @@ static void
display_gpl(void)
{
printf("chrony version %s\n"
"Copyright (C) 1997-2003, 2007, 2009-2014 Richard P. Curnow and others\n"
"Copyright (C) 1997-2003, 2007, 2009-2015 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",
@@ -2729,10 +2793,11 @@ main(int argc, char **argv)
family = IPADDR_INET6;
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
printf("chronyc (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYC_FEATURES);
exit(0);
return 0;
} else if (!strncmp(*argv, "-", 1)) {
fprintf(stderr, "Usage : %s [-h <hostname>] [-p <port-number>] [-n] [-4|-6] [-m] [-a] [-f <file>]] [command]\n", progname);
exit(1);
fprintf(stderr, "Usage: %s [-h HOST] [-p PORT] [-n] [-4|-6] [-a] [-f FILE] [-m] [COMMAND]\n",
progname);
return 1;
} else {
break; /* And process remainder of line as a command */
}

370
cmdmon.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2014
* Copyright (C) Miroslav Lichvar 2009-2015
*
* 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
@@ -37,6 +37,7 @@
#include "keys.h"
#include "ntp_sources.h"
#include "ntp_core.h"
#include "smooth.h"
#include "sources.h"
#include "sourcestats.h"
#include "reference.h"
@@ -162,6 +163,8 @@ static const char permissions[] = {
PERMIT_AUTH, /* RESELECT */
PERMIT_AUTH, /* RESELECTDISTANCE */
PERMIT_AUTH, /* MODIFY_MAKESTEP */
PERMIT_OPEN, /* SMOOTHING */
PERMIT_AUTH, /* SMOOTHTIME */
};
/* ================================================== */
@@ -712,13 +715,12 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
}
}
/* ================================================== */
static void
handle_null(CMD_Request *rx_message, CMD_Reply *tx_message)
handle_dump(CMD_Request *rx_message, CMD_Reply *tx_message)
{
tx_message->status = htons(STT_SUCCESS);
SRC_DumpSources();
}
/* ================================================== */
@@ -726,16 +728,12 @@ handle_null(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_online(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address, mask;
UTI_IPNetworkToHost(&rx_message->data.online.mask, &mask);
UTI_IPNetworkToHost(&rx_message->data.online.address, &address);
status = NSR_TakeSourcesOnline(&mask, &address);
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_TakeSourcesOnline(&mask, &address))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -743,16 +741,12 @@ handle_online(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_offline(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address, mask;
UTI_IPNetworkToHost(&rx_message->data.offline.mask, &mask);
UTI_IPNetworkToHost(&rx_message->data.offline.address, &address);
status = NSR_TakeSourcesOffline(&mask, &address);
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_TakeSourcesOffline(&mask, &address))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -760,19 +754,14 @@ handle_offline(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_burst(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address, mask;
UTI_IPNetworkToHost(&rx_message->data.burst.mask, &mask);
UTI_IPNetworkToHost(&rx_message->data.burst.address, &address);
status = NSR_InitiateSampleBurst(ntohl(rx_message->data.burst.n_good_samples),
ntohl(rx_message->data.burst.n_total_samples),
&mask, &address);
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_InitiateSampleBurst(ntohl(rx_message->data.burst.n_good_samples),
ntohl(rx_message->data.burst.n_total_samples),
&mask, &address))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -780,17 +769,12 @@ handle_burst(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_minpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
status = NSR_ModifyMinpoll(&address,
ntohl(rx_message->data.modify_minpoll.new_minpoll));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMinpoll(&address,
ntohl(rx_message->data.modify_minpoll.new_minpoll)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -798,17 +782,12 @@ handle_modify_minpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_maxpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
status = NSR_ModifyMaxpoll(&address,
ntohl(rx_message->data.modify_minpoll.new_minpoll));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMaxpoll(&address,
ntohl(rx_message->data.modify_minpoll.new_minpoll)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -816,16 +795,12 @@ handle_modify_maxpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_maxdelay(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelay.address, &address);
status = NSR_ModifyMaxdelay(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelay.new_max_delay));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMaxdelay(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelay.new_max_delay)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -833,16 +808,12 @@ handle_modify_maxdelay(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelayratio.address, &address);
status = NSR_ModifyMaxdelayratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelayratio.new_max_delay_ratio));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMaxdelayratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelayratio.new_max_delay_ratio)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -850,16 +821,12 @@ handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_maxdelaydevratio(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelaydevratio.address, &address);
status = NSR_ModifyMaxdelaydevratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelaydevratio.new_max_delay_dev_ratio));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMaxdelaydevratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelaydevratio.new_max_delay_dev_ratio)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -867,17 +834,12 @@ handle_modify_maxdelaydevratio(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_minstratum(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
status = NSR_ModifyMinstratum(&address,
ntohl(rx_message->data.modify_minstratum.new_min_stratum));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMinstratum(&address,
ntohl(rx_message->data.modify_minstratum.new_min_stratum)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -885,17 +847,12 @@ handle_modify_minstratum(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_polltarget(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_polltarget.address, &address);
status = NSR_ModifyPolltarget(&address,
ntohl(rx_message->data.modify_polltarget.new_poll_target));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyPolltarget(&address,
ntohl(rx_message->data.modify_polltarget.new_poll_target)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -904,7 +861,6 @@ static void
handle_modify_maxupdateskew(CMD_Request *rx_message, CMD_Reply *tx_message)
{
REF_ModifyMaxupdateskew(UTI_FloatNetworkToHost(rx_message->data.modify_maxupdateskew.new_max_update_skew));
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -914,7 +870,6 @@ handle_modify_makestep(CMD_Request *rx_message, CMD_Reply *tx_message)
{
REF_ModifyMakestep(ntohl(rx_message->data.modify_makestep.limit),
UTI_FloatNetworkToHost(rx_message->data.modify_makestep.threshold));
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -929,7 +884,6 @@ handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message)
if (!MNL_IsEnabled()) {
tx_message->status = htons(STT_NOTENABLED);
} else if (MNL_AcceptTimestamp(&ts, &offset_cs, &dfreq_ppm, &new_afreq_ppm)) {
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_MANUAL_TIMESTAMP);
tx_message->data.manual_timestamp.centiseconds = htonl((int32_t)offset_cs);
tx_message->data.manual_timestamp.dfreq_ppm = UTI_FloatHostToNetwork(dfreq_ppm);
@@ -952,7 +906,6 @@ handle_local(CMD_Request *rx_message, CMD_Reply *tx_message)
} else {
REF_DisableLocal();
}
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -972,8 +925,10 @@ handle_manual(CMD_Request *rx_message, CMD_Reply *tx_message)
case 2:
MNL_Reset();
break;
default:
tx_message->status = htons(STT_INVALID);
break;
}
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -983,7 +938,6 @@ handle_n_sources(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int n_sources;
n_sources = SRC_ReadNumberOfSources();
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_N_SOURCES);
tx_message->data.n_sources.n_sources = htonl(n_sources);
}
@@ -997,7 +951,7 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
struct timeval now_corr;
/* Get data */
LCL_ReadCookedTime(&now_corr, NULL);
SCH_GetLastEventTime(&now_corr, NULL, NULL);
if (SRC_ReportSource(ntohl(rx_message->data.source_data.index), &report, &now_corr)) {
switch (SRC_GetType(ntohl(rx_message->data.source_data.index))) {
case SRC_NTP:
@@ -1008,7 +962,6 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
break;
}
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_SOURCE_DATA);
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.source_data.ip_addr);
@@ -1071,136 +1024,35 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_rekey(CMD_Request *rx_message, CMD_Reply *tx_message)
{
tx_message->status = htons(STT_SUCCESS);
KEY_Reload();
}
/* ================================================== */
static void
handle_allow(CMD_Request *rx_message, CMD_Reply *tx_message)
handle_allowdeny(CMD_Request *rx_message, CMD_Reply *tx_message, int allow, int all)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (NCR_AddAccessRestriction(&ip, subnet_bits, 1, 0)) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NCR_AddAccessRestriction(&ip, subnet_bits, allow, all))
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_allowall(CMD_Request *rx_message, CMD_Reply *tx_message)
handle_cmdallowdeny(CMD_Request *rx_message, CMD_Reply *tx_message, int allow, int all)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (NCR_AddAccessRestriction(&ip, subnet_bits, 1, 1)) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!CAM_AddAccessRestriction(&ip, subnet_bits, allow, all))
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_deny(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (NCR_AddAccessRestriction(&ip, subnet_bits, 0, 0)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_denyall(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (NCR_AddAccessRestriction(&ip, subnet_bits, 0, 1)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_cmdallow(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (CAM_AddAccessRestriction(&ip, subnet_bits, 1, 0)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_cmdallowall(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (CAM_AddAccessRestriction(&ip, subnet_bits, 1, 1)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_cmddeny(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (CAM_AddAccessRestriction(&ip, subnet_bits, 0, 0)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_cmddenyall(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (CAM_AddAccessRestriction(&ip, subnet_bits, 0, 1)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
@@ -1266,7 +1118,6 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m
status = NSR_AddSource(&rem_addr, type, &params);
switch (status) {
case NSR_Success:
tx_message->status = htons(STT_SUCCESS);
break;
case NSR_AlreadyInUse:
tx_message->status = htons(STT_SOURCEALREADYKNOWN);
@@ -1297,7 +1148,6 @@ handle_del_source(CMD_Request *rx_message, CMD_Reply *tx_message)
status = NSR_RemoveSource(&rem_addr);
switch (status) {
case NSR_Success:
tx_message->status = htons(STT_SUCCESS);
break;
case NSR_NoSuchSource:
tx_message->status = htons(STT_NOSUCHSOURCE);
@@ -1317,7 +1167,6 @@ handle_writertc(CMD_Request *rx_message, CMD_Reply *tx_message)
{
switch (RTC_WriteParameters()) {
case RTC_ST_OK:
tx_message->status = htons(STT_SUCCESS);
break;
case RTC_ST_NODRV:
tx_message->status = htons(STT_NORTC);
@@ -1337,7 +1186,6 @@ handle_dfreq(CMD_Request *rx_message, CMD_Reply *tx_message)
dfreq = UTI_FloatNetworkToHost(rx_message->data.dfreq.dfreq);
LCL_AccumulateDeltaFrequency(dfreq * 1.0e-6);
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta freq of %.3fppm", dfreq);
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1352,7 +1200,6 @@ handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
doffset = (double) sec + 1.0e-6 * (double) usec;
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta offset of %.6f seconds", doffset);
LCL_AccumulateOffset(doffset, 0.0);
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1363,7 +1210,6 @@ handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
RPT_TrackingReport rpt;
REF_GetTrackingReport(&rpt);
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_TRACKING);
tx_message->data.tracking.ref_id = htonl(rpt.ref_id);
UTI_IPHostToNetwork(&rpt.ip_addr, &tx_message->data.tracking.ip_addr);
@@ -1383,6 +1229,60 @@ handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
/* ================================================== */
static void
handle_smoothing(CMD_Request *rx_message, CMD_Reply *tx_message)
{
RPT_SmoothingReport report;
struct timeval now;
SCH_GetLastEventTime(&now, NULL, NULL);
if (!SMT_GetSmoothingReport(&report, &now)) {
tx_message->status = htons(STT_NOTENABLED);
return;
}
tx_message->reply = htons(RPY_SMOOTHING);
tx_message->data.smoothing.flags = htonl((report.active ? RPY_SMT_FLAG_ACTIVE : 0) |
(report.leap_only ? RPY_SMT_FLAG_LEAPONLY : 0));
tx_message->data.smoothing.offset = UTI_FloatHostToNetwork(report.offset);
tx_message->data.smoothing.freq_ppm = UTI_FloatHostToNetwork(report.freq_ppm);
tx_message->data.smoothing.wander_ppm = UTI_FloatHostToNetwork(report.wander_ppm);
tx_message->data.smoothing.last_update_ago = UTI_FloatHostToNetwork(report.last_update_ago);
tx_message->data.smoothing.remaining_time = UTI_FloatHostToNetwork(report.remaining_time);
}
/* ================================================== */
static void
handle_smoothtime(CMD_Request *rx_message, CMD_Reply *tx_message)
{
struct timeval now;
int option;
if (!SMT_IsEnabled()) {
tx_message->status = htons(STT_NOTENABLED);
return;
}
option = ntohl(rx_message->data.smoothtime.option);
SCH_GetLastEventTime(&now, NULL, NULL);
switch (option) {
case REQ_SMOOTHTIME_RESET:
SMT_Reset(&now);
break;
case REQ_SMOOTHTIME_ACTIVATE:
SMT_Activate(&now);
break;
default:
tx_message->status = htons(STT_INVALID);
break;
}
}
/* ================================================== */
static void
handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message)
{
@@ -1390,12 +1290,11 @@ handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message)
RPT_SourcestatsReport report;
struct timeval now_corr;
LCL_ReadCookedTime(&now_corr, NULL);
SCH_GetLastEventTime(&now_corr, NULL, NULL);
status = SRC_ReportSourcestats(ntohl(rx_message->data.sourcestats.index),
&report, &now_corr);
if (status) {
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_SOURCESTATS);
tx_message->data.sourcestats.ref_id = htonl(report.ref_id);
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.sourcestats.ip_addr);
@@ -1421,7 +1320,6 @@ handle_rtcreport(CMD_Request *rx_message, CMD_Reply *tx_message)
RPT_RTC_Report report;
status = RTC_GetReport(&report);
if (status) {
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_RTC);
UTI_TimevalHostToNetwork(&report.ref_time, &tx_message->data.rtc.ref_time);
tx_message->data.rtc.n_samples = htons(report.n_samples);
@@ -1439,13 +1337,8 @@ handle_rtcreport(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_trimrtc(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
status = RTC_Trim();
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!RTC_Trim())
tx_message->status = htons(STT_NORTC);
}
}
/* ================================================== */
@@ -1454,8 +1347,6 @@ static void
handle_cyclelogs(CMD_Request *rx_message, CMD_Reply *tx_message)
{
LOG_CycleLogFiles();
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1469,14 +1360,13 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
int i, j;
struct timeval now;
LCL_ReadCookedTime(&now, NULL);
SCH_GetLastEventTime(&now, NULL, NULL);
first_index = ntohl(rx_message->data.client_accesses_by_index.first_index);
n_indices = ntohl(rx_message->data.client_accesses_by_index.n_indices);
if (n_indices > MAX_CLIENT_ACCESSES)
n_indices = MAX_CLIENT_ACCESSES;
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX);
for (i = 0, j = 0; i < n_indices; i++) {
@@ -1521,7 +1411,6 @@ handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
RPY_ManualListSample *sample;
RPT_ManualSamplesReport report[MAX_MANUAL_LIST_SAMPLES];
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_MANUAL_LIST);
MNL_ReportSamples(report, MAX_MANUAL_LIST_SAMPLES, &n_samples);
@@ -1540,16 +1429,11 @@ handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
int index;
index = ntohl(rx_message->data.manual_delete.index);
status = MNL_DeleteSample(index);
if (!status) {
if (!MNL_DeleteSample(index))
tx_message->status = htons(STT_BADSAMPLE);
} else {
tx_message->status = htons(STT_SUCCESS);
}
}
/* ================================================== */
@@ -1557,11 +1441,8 @@ handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message)
{
if (!LCL_MakeStep()) {
if (!LCL_MakeStep())
tx_message->status = htons(STT_FAILED);
} else {
tx_message->status = htons(STT_SUCCESS);
}
}
/* ================================================== */
@@ -1576,7 +1457,6 @@ handle_activity(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->data.activity.burst_online = htonl(report.burst_online);
tx_message->data.activity.burst_offline = htonl(report.burst_offline);
tx_message->data.activity.unresolved = htonl(report.unresolved);
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_ACTIVITY);
}
@@ -1588,7 +1468,6 @@ handle_reselect_distance(CMD_Request *rx_message, CMD_Reply *tx_message)
double dist;
dist = UTI_FloatNetworkToHost(rx_message->data.reselect_distance.distance);
SRC_SetReselectDistance(dist);
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1597,7 +1476,6 @@ static void
handle_reselect(CMD_Request *rx_message, CMD_Reply *tx_message)
{
SRC_ReselectSource();
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1653,8 +1531,8 @@ read_from_cmd_socket(void *anything)
read_length = status;
LCL_ReadRawTime(&now);
LCL_CookTime(&now, &cooked_now, NULL);
/* Get current time cheaply */
SCH_GetLastEventTime(&cooked_now, NULL, &now);
UTI_SockaddrToIPAndPort(&where_from.u, &remote_ip, &remote_port);
@@ -1709,6 +1587,7 @@ read_from_cmd_socket(void *anything)
tx_message.command = rx_message.command;
tx_message.sequence = rx_message.sequence;
tx_message.reply = htons(RPY_NULL);
tx_message.status = htons(STT_SUCCESS);
tx_message.pad1 = 0;
tx_message.pad2 = 0;
tx_message.pad3 = 0;
@@ -1909,7 +1788,11 @@ read_from_cmd_socket(void *anything)
if (allowed) {
switch(rx_command) {
case REQ_NULL:
handle_null(&rx_message, &tx_message);
/* Do nothing */
break;
case REQ_DUMP:
handle_dump(&rx_message, &tx_message);
break;
case REQ_ONLINE:
@@ -1932,11 +1815,6 @@ read_from_cmd_socket(void *anything)
handle_modify_maxpoll(&rx_message, &tx_message);
break;
case REQ_DUMP:
SRC_DumpSources();
tx_message.status = htons(STT_SUCCESS);
break;
case REQ_MODIFY_MAXDELAY:
handle_modify_maxdelay(&rx_message, &tx_message);
break;
@@ -2004,35 +1882,35 @@ read_from_cmd_socket(void *anything)
break;
case REQ_ALLOW:
handle_allow(&rx_message, &tx_message);
handle_allowdeny(&rx_message, &tx_message, 1, 0);
break;
case REQ_ALLOWALL:
handle_allowall(&rx_message, &tx_message);
handle_allowdeny(&rx_message, &tx_message, 1, 1);
break;
case REQ_DENY:
handle_deny(&rx_message, &tx_message);
handle_allowdeny(&rx_message, &tx_message, 0, 0);
break;
case REQ_DENYALL:
handle_denyall(&rx_message, &tx_message);
handle_allowdeny(&rx_message, &tx_message, 0, 1);
break;
case REQ_CMDALLOW:
handle_cmdallow(&rx_message, &tx_message);
handle_cmdallowdeny(&rx_message, &tx_message, 1, 0);
break;
case REQ_CMDALLOWALL:
handle_cmdallowall(&rx_message, &tx_message);
handle_cmdallowdeny(&rx_message, &tx_message, 1, 1);
break;
case REQ_CMDDENY:
handle_cmddeny(&rx_message, &tx_message);
handle_cmdallowdeny(&rx_message, &tx_message, 0, 0);
break;
case REQ_CMDDENYALL:
handle_cmddenyall(&rx_message, &tx_message);
handle_cmdallowdeny(&rx_message, &tx_message, 0, 1);
break;
case REQ_ACCHECK:
@@ -2071,6 +1949,14 @@ read_from_cmd_socket(void *anything)
handle_tracking(&rx_message, &tx_message);
break;
case REQ_SMOOTHING:
handle_smoothing(&rx_message, &tx_message);
break;
case REQ_SMOOTHTIME:
handle_smoothtime(&rx_message, &tx_message);
break;
case REQ_SOURCESTATS:
handle_sourcestats(&rx_message, &tx_message);
break;

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2013
* Copyright (C) Miroslav Lichvar 2013-2014
*
* 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

20
conf.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2014
* Copyright (C) Miroslav Lichvar 2009-2015
*
* 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
@@ -189,6 +189,7 @@ static char *pidfile;
/* Smoothing constants */
static double smooth_max_freq = 0.0; /* in ppm */
static double smooth_max_wander = 0.0; /* in ppm/s */
static int smooth_leap_only = 0;
/* Temperature sensor, update interval and compensation coefficients */
static char *tempcomp_sensor_file = NULL;
@@ -1174,11 +1175,23 @@ parse_broadcast(char *line)
static void
parse_smoothtime(char *line)
{
check_number_of_args(line, 2);
if (get_number_of_args(line) != 3)
check_number_of_args(line, 2);
if (sscanf(line, "%lf %lf", &smooth_max_freq, &smooth_max_wander) != 2) {
smooth_max_freq = 0.0;
command_parse_error();
}
line = CPS_SplitWord(CPS_SplitWord(line));
smooth_leap_only = 0;
if (*line) {
if (!strcasecmp(line, "leaponly"))
smooth_leap_only = 1;
else
command_parse_error();
}
}
/* ================================================== */
@@ -1738,10 +1751,11 @@ CNF_GetLockMemory(void)
/* ================================================== */
void
CNF_GetSmooth(double *max_freq, double *max_wander)
CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only)
{
*max_freq = smooth_max_freq;
*max_wander = smooth_max_wander;
*leap_only = smooth_leap_only;
}
/* ================================================== */

2
conf.h
View File

@@ -96,7 +96,7 @@ extern void CNF_SetupAccessRestrictions(void);
extern int CNF_GetSchedPriority(void);
extern int CNF_GetLockMemory(void);
extern void CNF_GetSmooth(double *max_freq, double *max_wander);
extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only);
extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
extern char *CNF_GetUser(void);

7
configure vendored
View File

@@ -404,6 +404,13 @@ case $SYSTEM in
SYSDEFS=""
echo "Configuring for $SYSTEM"
;;
Darwin-* )
EXTRA_OBJECTS="sys_macosx.o"
EXTRA_LIBS="-lresolv"
EXTRA_CLI_LIBS="-lresolv"
add_def MACOSX
echo "Configuring for MacOS X (" $SYSTEM "MacOS X version" $VERSION ")"
;;
SunOS-i86pc* )
# Doug Woodward <dougw@whistler.com> reported that this configuration
# works for Solaris 2.8 / SunOS 5.8 on x86 platforms

273
doc/faq.adoc Normal file
View File

@@ -0,0 +1,273 @@
:toc:
:numbered:
Frequently Asked Questions
==========================
== Chrony compared to other programs
=== How does +chrony+ compare to +ntpd+?
+chrony+ can usually synchronise the system clock faster and with better time
accuracy, but it doesn't implement all NTP features, e.g. broadcast/multicast
mode, or authentication based on public-key cryptography. For a more detailed
comparison, see the http://chrony.tuxfamily.org/comparison.html[comparison
page] on the chrony website and section
http://chrony.tuxfamily.org/manual.html#Comparison-with-ntpd[Comparison with
ntpd] in the manual.
If your computer connects to the 'net only for few minutes at a time, you turn
your Linux computer off or suspend it frequently, the clock is not very stable
(e.g. it is a virtual machine), or you want to use NTP on an isolated network
with no hardware clocks in sight, +chrony+ will probably work much better for
you.
The original reason +chrony+ was written was that ntpd (called xntpd at the
time) could not to do anything sensible on a PC which was connected to the 'net
only for about 5 minutes once or twice a day, mainly to upload/download email
and news. The requirements were
* slew the time to correct it when going online and NTP servers
become visible
* determine the rate at which the computer gains or loses time and
use this information to keep it reasonably correct between connects
to the 'net. This has to be done using a method that does not care
about the intermittent availability of the references or the fact
the computer is turned off between groups of measurements.
* maintain the time across reboots, by working out the error and
drift rate of the computer's real-time clock and using this
information to set the system clock correctly at boot up.
Also, when working with isolated networks with no true time references at all
ntpd was found to give no help with managing the local clock's gain/loss rate
on the NTP master node (which was set from watch). Some automated support was
added to +chrony+ to deal with this.
== Configuration issues
=== I have several computers on a LAN. Should be all clients of an external server?
The best configuration is usually to make one computer the master, with
the others as clients of it. Add a +local+ directive to the master's
'chrony.conf' file. This configuration will be better because
* the load on the external connection is less
* the load on the external NTP server(s) is less
* if your external connection goes down, the computers on the LAN
will maintain a common time with each other.
=== Must I specify servers by IP address if DNS is not available on chronyd start?
No. Starting from version 1.25, +chronyd+ will keep trying to resolve
the hostnames specified in the +server+ and +peer+ directives in
increasing intervals until it succeeds. The +online+ command can be
issued from +chronyc+ to try to resolve them immediately.
=== How can I make chronyd more secure?
If you don't need to serve time to NTP clients or peers, you can add +port 0+
to the 'chrony.conf' file to completely disable the NTP server functionality
and prevent NTP requests from reaching +chronyd+. Starting from version 2.0,
the NTP server port is open only when client access is allowed by the +allow+
directive or command, an NTP peer is configured, or the +broadcast+ directive
is used.
If you don't need to use +chronyc+ remotely, you can add the following
directives to the configuration file to bind the command sockets to the
loopback interface. This is done by default since version 2.0.
----
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
----
If you don't need to use +chronyc+ at all, you can disable the command sockets
by adding +cmdport 0+ to the configuration file.
On Linux, if +chronyd+ is compiled with support for Linux capabilities
(available in the libcap library), you can specify an unprivileged user with
the +-u+ option or +user+ directive in the 'chrony.conf' file to drop root
privileges after start. The configure option +--with-user+ can be used to drop
the privileges by default.
=== How can I improve the accuracy of the system clock with NTP sources?
Select NTP servers that are well synchronised, stable and close to your
network. It's better to use more than one server, three or four is usually
recommended as the minimum, so +chronyd+ can detect falsetickers and combine
measurements from multiple sources.
There are also useful options which can be set in the +server+ directive, they
are +minpoll+, +maxpoll+, +polltarget+, +maxdelay+, +maxdelayratio+ and
+maxdelaydevratio+.
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 6 (samples) for +polltarget+. The default values should be used
for general servers on the internet. With your own NTP servers or if have
permission to poll some servers more frequently, setting these options for
shorter polling intervals may significantly improve the accuracy of the system
clock.
The optimal polling interval depends on many factors, including the ratio
between the wander of the clock and the network jitter (sometimes expressed in
NTP documents as the Allan intercept), the temperature sensitivity of the
crystal oscillator and the maximum rate of change of the temperature.
An example of the directive for an NTP server on the internet that you are
allowed to poll frequently could be
----
server foo.example.net minpoll 4 maxpoll 6 polltarget 16
----
An example using very short polling intervals for a server located in the same
LAN could be
----
server ntp.local minpoll 2 maxpoll 4 polltarget 30
----
The maxdelay options are useful to ignore measurements with larger delay (e.g.
due to congestion in the network) and improve the stability of the
synchronisation. The +maxdelaydevratio+ option could be added to the example
with local NTP server
----
server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
----
== Computer is not synchronising
This is the most common problem. There are a number of reasons, see the
following questions.
=== Behind a firewall?
If there is a firewall between you and the NTP server you're trying to use, the
packets may be blocked. Try using a tool like wireshark or tcpdump to see if
you're getting responses from the server. If you have an external modem, see
if the receive light blinks straight after the transmit light (when the link is
quiet apart from the NTP traffic.) Try adding +log measurements+ to the
'chrony.conf' file and look in the 'measurements.log' file after +chrony+ has
been running for a short period. See if any measurements appear.
=== 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.
== Issues with +chronyc+
=== I keep getting the error +506 Cannot talk to daemon+
When accessing +chronyd+ remotely, make sure that the 'chrony.conf' file (on
the computer where +chronyd+ is running) has a 'cmdallow' entry for the
computer you are running +chronyc+ on and an appropriate 'bindcmdaddress'
directive. This isn't necessary for localhost.
Perhaps +chronyd+ is not running. Try using the +ps+ command (e.g. on Linux,
+ps -auxw+) to see if it's running. Or try +netstat -a+ and see if the ports
123/udp and 323/udp are listening. If +chronyd+ is not running, you may have a
problem with the way you are trying to start it (e.g. at boot time).
Perhaps you have a firewall set up in a way that blocks packets on port
323/udp. You need to amend the firewall configuration in this case.
=== Is the +chronyc+ / +chronyd+ protocol documented anywhere?
Only by the source code :-) See 'cmdmon.c' (+chronyd+ side) and 'client.c'
(+chronyc+ side).
== Real-time clock issues
=== What is the real-time clock (RTC)?
This is the clock which keeps the time even when your computer is turned off.
It works with 1 second resolution. +chronyd+ can monitor the rate at which the
real-time clock gains or loses time, and compensate for it when you set the
system time from it at the next reboot. See the documentation for details.
=== I want to use +chronyd+'s real-time clock support. Must I disable hwclock?
The hwclock program is often set-up by default in the boot and shutdown scripts
with many Linux installations. If you want to use +chronyd+'s real-time clock
support, the important thing is to disable hwclock in the shutdown procedure.
If you don't, it will over-write the RTC with a new value, unknown to
+chronyd+. At the next reboot, +chronyd+ will compensate this (wrong) time
with its estimate of how far the RTC has drifted whilst the power was off,
giving a meaningless initial system time.
There is no need to remove hwclock from the boot process, as long as +chronyd+
is started after it has run.
=== I just keep getting the +513 RTC driver not running+ message
For the real time clock support to work, you need the following three
things
* a kernel that is supported (e.g. 2.2 onwards)
* enhanced RTC support compiled into the kernel
* an +rtcfile+ directive in your 'chrony.conf' file
== Microsoft Windows
=== Does +chrony+ support Windows?
No. The +chronyc+ program (the command-line client used for configuring
+chronyd+ while it is running) has been successfully built and run under
Cygwin in the past. +chronyd+ is not portable, because part of it is
very system-dependent. It needs adapting to work with Windows'
equivalent of the adjtimex() call, and it needs to be made to work as a
service.
=== Are there any plans to support Windows?
We have no plans to do this. Anyone is welcome to pick this work up and
contribute it back to the project.
== NTP-specific issues
=== Can +chrony+ be driven from broadcast NTP servers?
No, this NTP mode is not implemented yet.
=== Can chronyd transmit broadcast NTP packets (e.g. to synchronise other computers on a private LAN)?
Yes. Starting from version 1.17, +chrony+ has this capability.
=== Can +chrony+ keep the system clock a fixed offset away from real time?
This is not possible as the program currently stands.
=== 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 current 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.
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.
== Linux-specific issues
=== I get +Could not open /dev/rtc, Device or resource busy+ in my syslog file
Some other program running on the system may be using the device.
== Solaris-specific issues
=== I get an error message about not being able to open kvm to change dosynctodr
(The dosynctodr variable controls whether Solaris couples the equivalent
of its BIOS clock into its system clock at regular intervals). The
Solaris port of +chrony+ was developed in the Solaris 2.5 era. Some
aspect of the Solaris kernel has changed which prevents the same
technique working. We no longer have root access to any Solaris
machines to work on this, and we are reliant on somebody developing the
patch and testing it.

View File

@@ -45,7 +45,6 @@ cp chrony.info* $RPM_BUILD_ROOT%{_infodir}
%{_sbindir}/chronyd
%{_bindir}/chronyc
%{_infodir}/chrony.info*
%{_mandir}/man1/chrony.1.gz
%{_mandir}/man1/chronyc.1.gz
%{_mandir}/man5/chrony.conf.5.gz
%{_mandir}/man8/chronyd.8.gz

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-2015
*
* 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
@@ -564,6 +564,9 @@ LCL_NotifyLeap(int leap)
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL);
/* Smooth the leap second out */
SMT_Leap(&cooked, leap);
/* Dispatch to all handlers as if the clock was stepped */
invoke_parameter_change_handlers(&raw, &cooked, 0.0, -leap, LCL_ChangeStep);
}

View File

@@ -94,6 +94,7 @@ typedef enum {
LOGF_Sys,
LOGF_SysGeneric,
LOGF_SysLinux,
LOGF_SysMacOSX,
LOGF_SysNetBSD,
LOGF_SysSolaris,
LOGF_SysSunOS,

9
main.c
View File

@@ -347,6 +347,7 @@ int main
(int argc, char **argv)
{
const char *conf_file = DEFAULT_CONF_FILE;
const char *progname = argv[0];
char *user = NULL;
int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
int do_init_rtc = 0, restarted = 0;
@@ -386,7 +387,7 @@ int main
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
exit(0);
return 0;
} else if (!strcmp("-n", *argv)) {
nofork = 1;
} else if (!strcmp("-d", *argv)) {
@@ -405,6 +406,10 @@ int main
address_family = IPADDR_INET4;
} else if (!strcmp("-6", *argv)) {
address_family = IPADDR_INET6;
} else if (!strcmp("-h", *argv) || !strcmp("--help", *argv)) {
printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-f FILE|COMMAND...]\n",
progname);
return 0;
} else if (*argv[0] == '-') {
LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
} else {
@@ -417,7 +422,7 @@ int main
if (getuid() != 0) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
fprintf(stderr,"Not superuser\n");
exit(1);
return 1;
}
/* Turn into a daemon */

View File

@@ -39,7 +39,7 @@ echo $version > version.txt
sed -i -e "s%@@VERSION@@%${version}%" examples/chrony.spec
for m in chrony.1 chronyc.1.in chrony.conf.5.in chronyd.8.in; do
for m in chronyc.1.in chrony.conf.5.in chronyd.8.in; do
sed -e "s%@VERSION@%${version}%;s%@MAN_DATE@%${mandate}%" \
< $m > ${m}_
mv -f ${m}_ $m
@@ -59,15 +59,9 @@ if [ $(wc -l < INSTALL) -gt 100 -o $(wc -l < INSTALL) -lt 85 ]; then
exit 3
fi
awk '/^[1-9] Frequently asked questions$/{p=1}
/^Appendix A GNU General Public License$/{exit}; p' chrony.txt | \
tail -n +4 | sed 's/^[1-9]\.\([1-9]\)/\1/' | sed 's/^----/--/' | \
sed 's/^====/==/' > FAQ
if [ $(wc -l < FAQ) -gt 400 -o $(wc -l < FAQ) -lt 200 ]; then
echo "FAQ generated incorrectly?"
exit 3
fi
a2x --lynx -f text doc/faq.adoc || exit 1
mv doc/faq.text FAQ
rm -rf doc
rm -f config.h config.log make_release .gitignore

5
ntp.h
View File

@@ -109,4 +109,9 @@ typedef struct {
#define NTP_LVM(leap, version, mode) \
((((leap) << 6) & 0xc0) | (((version) << 3) & 0x38) | ((mode) & 0x07))
/* Special NTP reference IDs */
#define NTP_REFID_UNSYNC 0x0UL
#define NTP_REFID_LOCAL 0x7F7F0101UL /* 127.127.1.1 */
#define NTP_REFID_SMOOTH 0x7F7F01FFUL /* 127.127.1.255 */
#endif /* GOT_NTP_H */

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2014
* Copyright (C) Miroslav Lichvar 2009-2015
*
* 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
@@ -316,7 +316,7 @@ NCR_Initialise(void)
do_time_checks();
logfileid = CNF_GetLogMeasurements() ? 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.")
" Date (UTC) Time IP Address L St 123 567 ABCD LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
: -1;
access_auth_table = ADF_CreateTable();
@@ -789,8 +789,8 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
/* Get current smoothing offset when sending packet to a client */
if (SMT_IsEnabled() && (my_mode == MODE_SERVER || my_mode == MODE_BROADCAST)) {
smooth_time = 1;
smooth_offset = SMT_GetOffset(&local_transmit);
smooth_time = fabs(smooth_offset) > LCL_GetSysPrecisionAsQuantum();
/* Suppress leap second when smoothing and slew mode are enabled */
if (REF_GetLeapMode() == REF_LeapModeSlew &&
@@ -801,6 +801,14 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
smooth_offset = 0.0;
}
if (smooth_time) {
our_ref_id = NTP_REFID_SMOOTH;
UTI_AddDoubleToTimeval(&our_ref_time, smooth_offset, &our_ref_time);
UTI_AddDoubleToTimeval(local_rx, smooth_offset, &local_receive);
} else {
local_receive = *local_rx;
}
if (are_we_synchronised) {
leap = (int) leap_status;
} else {
@@ -824,17 +832,10 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
message.root_delay = UTI_DoubleToInt32(our_root_delay);
message.root_dispersion = UTI_DoubleToInt32(our_root_dispersion);
message.reference_id = htonl((NTP_int32) our_ref_id);
message.reference_id = htonl(our_ref_id);
/* Now fill in timestamps */
if (smooth_time) {
UTI_AddDoubleToTimeval(&our_ref_time, smooth_offset, &our_ref_time);
UTI_AddDoubleToTimeval(local_rx, smooth_offset, &local_receive);
} else {
local_receive = *local_rx;
}
UTI_TimevalToInt64(&our_ref_time, &message.reference_ts, 0);
/* Originate - this comes from the last packet the source sent us */
@@ -1230,7 +1231,8 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
inst->local_ntp_tx.hi = inst->local_ntp_tx.lo = 0;
if (valid_packet) {
precision = LCL_GetSysPrecisionAsQuantum();
precision = LCL_GetSysPrecisionAsQuantum() +
UTI_Log2ToDouble(message->precision);
SRC_GetFrequencyRange(inst->source, &source_freq_lo, &source_freq_hi);

View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Timo Teras 2009
* Copyright (C) Miroslav Lichvar 2009, 2013-2014
* Copyright (C) Miroslav Lichvar 2009, 2013-2015
*
* 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,8 +97,13 @@ prepare_socket(int family, int port_number, int client_only)
sock_fd = socket(family, SOCK_DGRAM, 0);
if (sock_fd < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
if (!client_only) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
} else {
DEBUG_LOG(LOGF_NtpIO, "Could not open %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
}
return INVALID_SOCK_FD;
}

View File

@@ -49,6 +49,7 @@ typedef struct {
NTP_Remote_Address *remote_addr; /* The address of this source, non-NULL
means this slot in table is in use */
NCR_Instance data; /* Data for the protocol engine for this source */
char *name; /* Name of the source, may be NULL */
int pool; /* Number of the pool from which was this source
added or INVALID_POOL */
int tentative; /* Flag indicating there was no valid response
@@ -85,6 +86,7 @@ struct UnresolvedSource {
#define RESOLVE_INTERVAL_UNIT 7
#define MIN_RESOLVE_INTERVAL 2
#define MAX_RESOLVE_INTERVAL 9
#define MIN_REPLACEMENT_INTERVAL 8
static struct UnresolvedSource *unresolved_sources = NULL;
static int resolving_interval = 0;
@@ -92,15 +94,11 @@ static SCH_TimeoutID resolving_id;
static struct UnresolvedSource *resolving_source = NULL;
static NSR_SourceResolvingEndHandler resolving_end_handler = NULL;
#define MIN_POOL_RESOLVE_INTERVAL 5
#define MAX_POOL_SOURCES 16
#define INVALID_POOL (-1)
/* Pool of sources, the name is expected to resolve to multiple addresses
which change over time */
/* Pool of sources with the same name */
struct SourcePool {
char *name;
int port;
/* Number of sources added from this pool (ignoring tentative sources) */
int sources;
/* Maximum number of sources */
@@ -115,6 +113,7 @@ static ARR_Instance pools;
static void resolve_sources(void *arg);
static void rehash_records(void);
static void clean_source_record(SourceRecord *record);
static void
slew_sources(struct timeval *raw,
@@ -162,16 +161,12 @@ NSR_Finalise(void)
struct UnresolvedSource *us;
unsigned int i;
for (i = 0; i < ARR_GetSize(pools); i++)
Free(((struct SourcePool *)ARR_GetElement(pools, i))->name);
ARR_DestroyInstance(pools);
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (!record->remote_addr)
continue;
record->remote_addr = NULL;
NCR_DestroyInstance(record->data);
if (record->remote_addr)
clean_source_record(record);
}
ARR_DestroyInstance(records);
@@ -296,7 +291,7 @@ rehash_records(void)
/* Procedure to add a new source */
static NSR_Status
add_source(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params, int pool)
add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, SourceParameters *params, int pool)
{
SourceRecord *record;
int slot, found;
@@ -323,6 +318,7 @@ add_source(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParamete
record = get_record(slot);
record->data = NCR_GetInstance(remote_addr, type, params);
record->remote_addr = NCR_GetRemoteAddress(record->data);
record->name = name ? Strdup(name) : NULL;
record->pool = pool;
record->tentative = pool != INVALID_POOL ? 1 : 0;
@@ -373,7 +369,7 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
int i, added;
for (i = added = 0; i < n_addrs; i++) {
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %s", us->name, UTI_IPToString(&ip_addrs[i]));
DEBUG_LOG(LOGF_NtpSources, "(%d) %s", i + 1, UTI_IPToString(&ip_addrs[i]));
address.ip_addr = ip_addrs[i];
address.port = us->port;
@@ -382,7 +378,7 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
if (replace_source(&us->replace_source, &address) != NSR_AlreadyInUse)
break;
} else {
if (add_source(&address, us->new_source.type, &us->new_source.params,
if (add_source(&address, us->name, us->new_source.type, &us->new_source.params,
us->new_source.pool) == NSR_Success)
added++;
@@ -403,6 +399,8 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *any
assert(us == resolving_source);
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %d addrs", us->name, n_addrs);
switch (status) {
case DNS_TryAgain:
break;
@@ -495,7 +493,7 @@ append_unresolved_source(struct UnresolvedSource *us)
NSR_Status
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
{
return add_source(remote_addr, type, params, INVALID_POOL);
return add_source(remote_addr, NULL, type, params, INVALID_POOL);
}
/* ================================================== */
@@ -505,6 +503,15 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, Source
{
struct UnresolvedSource *us;
struct SourcePool *sp;
NTP_Remote_Address remote_addr;
/* If the name is an IP address, don't bother with full resolving now
or later when trying to replace the source */
if (UTI_StringToIP(name, &remote_addr.ip_addr)) {
remote_addr.port = port;
NSR_AddSource(&remote_addr, type, params);
return;
}
us = MallocNew(struct UnresolvedSource);
us->name = Strdup(name);
@@ -518,8 +525,6 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, Source
us->new_source.max_new_sources = 1;
} else {
sp = (struct SourcePool *)ARR_GetNewElement(pools);
sp->name = Strdup(name);
sp->port = port;
sp->sources = 0;
sp->max_sources = params->max_sources;
us->new_source.pool = ARR_GetSize(pools) - 1;
@@ -587,6 +592,8 @@ clean_source_record(SourceRecord *record)
assert(record->remote_addr);
record->remote_addr = NULL;
NCR_DestroyInstance(record->data);
if (record->name)
Free(record->name);
n_sources--;
}
@@ -640,15 +647,18 @@ NSR_RemoveAllSources(void)
/* ================================================== */
static void
resolve_pool_replacement(struct SourcePool *sp, NTP_Remote_Address *addr)
resolve_source_replacement(SourceRecord *record)
{
struct UnresolvedSource *us;
DEBUG_LOG(LOGF_NtpSources, "trying to replace %s",
UTI_IPToString(&record->remote_addr->ip_addr));
us = MallocNew(struct UnresolvedSource);
us->name = Strdup(sp->name);
us->port = sp->port;
us->name = Strdup(record->name);
us->port = record->remote_addr->port;
us->replacement = 1;
us->replace_source = *addr;
us->replace_source = *record->remote_addr;
append_unresolved_source(us);
NSR_ResolveSources();
@@ -662,32 +672,33 @@ NSR_HandleBadSource(IPAddr *address)
static struct timeval last_replacement;
struct timeval now;
NTP_Remote_Address remote_addr;
struct SourcePool *pool;
int pool_index, slot, found;
SourceRecord *record;
int slot, found;
double diff;
remote_addr.ip_addr = *address;
remote_addr.port = 0;
/* Only sources from a pool can be replaced */
find_slot(&remote_addr, &slot, &found);
if (!found || (pool_index = get_record(slot)->pool) == INVALID_POOL)
if (!found)
return;
pool = (struct SourcePool *)ARR_GetElement(pools, pool_index);
record = get_record(slot);
/* Don't resolve the pool name too frequently */
/* Only sources with a name can be replaced */
if (!record->name)
return;
/* Don't resolve names too frequently */
SCH_GetLastEventTime(NULL, NULL, &now);
UTI_DiffTimevalsToDouble(&diff, &now, &last_replacement);
if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_POOL_RESOLVE_INTERVAL)) {
if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_REPLACEMENT_INTERVAL)) {
DEBUG_LOG(LOGF_NtpSources, "replacement postponed");
return;
}
last_replacement = now;
DEBUG_LOG(LOGF_NtpSources, "pool replacement for %s", UTI_IPToString(address));
resolve_pool_replacement(pool, &remote_addr);
resolve_source_replacement(record);
}
/* ================================================== */
@@ -741,7 +752,7 @@ NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP
pool->sources++;
DEBUG_LOG(LOGF_NtpSources, "pool %s has %d confirmed sources",
pool->name, pool->sources);
record->name, pool->sources);
/* If the number of sources reached the configured maximum, remove
the tentative sources added from this pool */

View File

@@ -44,9 +44,8 @@ command_unpadded_length(CMD_Request *r)
return 0;
} else {
switch (type) {
case REQ_NULL:
return offsetof(CMD_Request, data);
return offsetof(CMD_Request, data.null.EOR);
case REQ_ONLINE:
return offsetof(CMD_Request, data.online.EOR);
case REQ_OFFLINE:
@@ -78,11 +77,11 @@ command_unpadded_length(CMD_Request *r)
case REQ_MANUAL :
return offsetof(CMD_Request, data.manual.EOR);
case REQ_N_SOURCES :
return offsetof(CMD_Request, data.n_sources.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_SOURCE_DATA :
return offsetof(CMD_Request, data.source_data.EOR);
case REQ_REKEY :
return offsetof(CMD_Request, data.rekey.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_ALLOW :
return offsetof(CMD_Request, data.allow_deny.EOR);
case REQ_ALLOWALL :
@@ -110,21 +109,21 @@ command_unpadded_length(CMD_Request *r)
case REQ_DEL_SOURCE :
return offsetof(CMD_Request, data.del_source.EOR);
case REQ_WRITERTC :
return offsetof(CMD_Request, data.writertc.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_DFREQ :
return offsetof(CMD_Request, data.dfreq.EOR);
case REQ_DOFFSET :
return offsetof(CMD_Request, data.doffset.EOR);
case REQ_TRACKING :
return offsetof(CMD_Request, data.tracking.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_SOURCESTATS :
return offsetof(CMD_Request, data.sourcestats.EOR);
case REQ_RTCREPORT :
return offsetof(CMD_Request, data.rtcreport.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_TRIMRTC :
return offsetof(CMD_Request, data.trimrtc.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_CYCLELOGS :
return offsetof(CMD_Request, data.cyclelogs.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_SUBNETS_ACCESSED :
case REQ_CLIENT_ACCESSES:
/* No longer supported */
@@ -132,21 +131,25 @@ command_unpadded_length(CMD_Request *r)
case REQ_CLIENT_ACCESSES_BY_INDEX:
return offsetof(CMD_Request, data.client_accesses_by_index.EOR);
case REQ_MANUAL_LIST:
return offsetof(CMD_Request, data.manual_list.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_MANUAL_DELETE:
return offsetof(CMD_Request, data.manual_delete.EOR);
case REQ_MAKESTEP:
return offsetof(CMD_Request, data.make_step.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_ACTIVITY:
return offsetof(CMD_Request, data.activity.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_RESELECT:
return offsetof(CMD_Request, data.reselect.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_RESELECTDISTANCE:
return offsetof(CMD_Request, data.reselect_distance.EOR);
case REQ_MODIFY_MINSTRATUM:
return offsetof(CMD_Request, data.modify_minstratum.EOR);
case REQ_MODIFY_POLLTARGET:
return offsetof(CMD_Request, data.modify_polltarget.EOR);
case REQ_SMOOTHING:
return offsetof(CMD_Request, data.null.EOR);
case REQ_SMOOTHTIME:
return offsetof(CMD_Request, data.smoothtime.EOR);
default:
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
assert(0);
@@ -228,11 +231,11 @@ PKL_CommandPaddingLength(CMD_Request *r)
case REQ_MANUAL:
return PADDING_LENGTH(data.manual.EOR, data.null.EOR);
case REQ_N_SOURCES:
return PADDING_LENGTH(data.n_sources.EOR, data.n_sources.EOR);
return PADDING_LENGTH(data.null.EOR, data.n_sources.EOR);
case REQ_SOURCE_DATA:
return PADDING_LENGTH(data.source_data.EOR, data.source_data.EOR);
case REQ_REKEY:
return PADDING_LENGTH(data.rekey.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_ALLOW:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_ALLOWALL:
@@ -260,21 +263,21 @@ PKL_CommandPaddingLength(CMD_Request *r)
case REQ_DEL_SOURCE:
return PADDING_LENGTH(data.del_source.EOR, data.null.EOR);
case REQ_WRITERTC:
return PADDING_LENGTH(data.writertc.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_DFREQ:
return PADDING_LENGTH(data.dfreq.EOR, data.null.EOR);
case REQ_DOFFSET:
return PADDING_LENGTH(data.doffset.EOR, data.null.EOR);
case REQ_TRACKING:
return PADDING_LENGTH(data.tracking.EOR, data.tracking.EOR);
return PADDING_LENGTH(data.null.EOR, data.tracking.EOR);
case REQ_SOURCESTATS:
return PADDING_LENGTH(data.sourcestats.EOR, data.sourcestats.EOR);
case REQ_RTCREPORT:
return PADDING_LENGTH(data.rtcreport.EOR, data.rtc.EOR);
return PADDING_LENGTH(data.null.EOR, data.rtc.EOR);
case REQ_TRIMRTC:
return PADDING_LENGTH(data.trimrtc.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_CYCLELOGS:
return PADDING_LENGTH(data.cyclelogs.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_SUBNETS_ACCESSED:
case REQ_CLIENT_ACCESSES:
/* No longer supported */
@@ -282,21 +285,25 @@ PKL_CommandPaddingLength(CMD_Request *r)
case REQ_CLIENT_ACCESSES_BY_INDEX:
return PADDING_LENGTH(data.client_accesses_by_index.EOR, data.client_accesses_by_index.EOR);
case REQ_MANUAL_LIST:
return PADDING_LENGTH(data.manual_list.EOR, data.manual_list.EOR);
return PADDING_LENGTH(data.null.EOR, data.manual_list.EOR);
case REQ_MANUAL_DELETE:
return PADDING_LENGTH(data.manual_delete.EOR, data.null.EOR);
case REQ_MAKESTEP:
return PADDING_LENGTH(data.make_step.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_ACTIVITY:
return PADDING_LENGTH(data.activity.EOR, data.activity.EOR);
return PADDING_LENGTH(data.null.EOR, data.activity.EOR);
case REQ_RESELECT:
return PADDING_LENGTH(data.reselect.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_RESELECTDISTANCE:
return PADDING_LENGTH(data.reselect_distance.EOR, data.null.EOR);
case REQ_MODIFY_MINSTRATUM:
return PADDING_LENGTH(data.modify_minstratum.EOR, data.null.EOR);
case REQ_MODIFY_POLLTARGET:
return PADDING_LENGTH(data.modify_polltarget.EOR, data.null.EOR);
case REQ_SMOOTHING:
return PADDING_LENGTH(data.null.EOR, data.smoothing.EOR);
case REQ_SMOOTHTIME:
return PADDING_LENGTH(data.smoothtime.EOR, data.null.EOR);
default:
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
assert(0);
@@ -360,7 +367,8 @@ PKL_ReplyLength(CMD_Reply *r)
}
case RPY_ACTIVITY:
return offsetof(CMD_Reply, data.activity.EOR);
case RPY_SMOOTHING:
return offsetof(CMD_Reply, data.smoothing.EOR);
default:
assert(0);
}

View File

@@ -499,15 +499,6 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
return 1;
}
static double
poll_interval(int poll)
{
if (poll >= 0)
return 1 << poll;
else
return 1.0 / (1 << -poll);
}
static int
valid_sample_time(RCL_Instance instance, struct timeval *tv)
{
@@ -516,7 +507,7 @@ valid_sample_time(RCL_Instance instance, struct timeval *tv)
LCL_ReadRawTime(&raw_time);
UTI_DiffTimevalsToDouble(&diff, &raw_time, tv);
if (diff < 0.0 || diff > poll_interval(instance->poll + 1)) {
if (diff < 0.0 || diff > UTI_Log2ToDouble(instance->poll + 1)) {
DEBUG_LOG(LOGF_Refclock, "%s refclock sample not valid age=%.6f tv=%s",
UTI_RefidToString(instance->ref_id), diff, UTI_TimevalToString(tv));
return 0;
@@ -595,7 +586,7 @@ poll_timeout(void *arg)
}
}
inst->timeout_id = SCH_AddTimeoutByDelay(poll_interval(poll), poll_timeout, arg);
inst->timeout_id = SCH_AddTimeoutByDelay(UTI_Log2ToDouble(poll), poll_timeout, arg);
}
static void

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2014
* Copyright (C) Miroslav Lichvar 2009-2015
*
* 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
@@ -120,11 +120,6 @@ static LOG_FileID logfileid;
/* ================================================== */
/* Reference ID supplied when we are locally referenced */
#define LOCAL_REFERENCE_ID 0x7f7f0101UL
/* ================================================== */
/* Exponential moving averages of absolute clock frequencies
used as a fallback when synchronisation is lost. */
@@ -248,9 +243,9 @@ REF_Initialise(void)
leap_tzname = CNF_GetLeapSecTimezone();
if (leap_tzname) {
/* Check that the timezone has good data for Jun 30 2008 and Dec 31 2008 */
if (get_tz_leap(1214784000) == LEAP_Normal &&
get_tz_leap(1230681600) == LEAP_InsertSecond) {
/* Check that the timezone has good data for Jun 30 2012 and Dec 31 2012 */
if (get_tz_leap(1341014400) == LEAP_InsertSecond &&
get_tz_leap(1356912000) == LEAP_Normal) {
LOG(LOGS_INFO, LOGF_Reference, "Using %s timezone to obtain leap second data", leap_tzname);
} else {
LOG(LOGS_WARN, LOGF_Reference, "Timezone %s failed leap second check, ignoring", leap_tzname);
@@ -1109,12 +1104,10 @@ REF_SetManualReference
double skew
)
{
uint32_t manual_refid = 0x4D414E55; /* MANU */
/* We are not synchronised to an external source, as such. This is
only supposed to be used with the local source option, really
... */
REF_SetReference(0, LEAP_Unsynchronised, 1, manual_refid, NULL,
only supposed to be used with the local source option, really.
Log as MANU in the tracking log, packets will have NTP_REFID_LOCAL. */
REF_SetReference(0, LEAP_Unsynchronised, 1, 0x4D414E55UL, NULL,
ref_time, offset, 0.0, frequency, skew, 0.0, 0.0);
}
@@ -1200,7 +1193,7 @@ REF_GetReferenceParams
*is_synchronised = 1;
*stratum = local_stratum;
*ref_id = LOCAL_REFERENCE_ID;
*ref_id = NTP_REFID_LOCAL;
/* Make the reference time be now less a second - this will
scarcely affect the client, but will ensure that the transmit
timestamp cannot come before this (which would cause test 7 to
@@ -1222,7 +1215,7 @@ REF_GetReferenceParams
*leap_status = LEAP_Unsynchronised;
*stratum = NTP_MAX_STRATUM;
*ref_id = 0;
*ref_id = NTP_REFID_UNSYNC;
ref_time->tv_sec = ref_time->tv_usec = 0;
/* These values seem to be standard for a client, and
any peer or client of ours will ignore them anyway because
@@ -1336,7 +1329,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
LCL_GetOffsetCorrection(&now_raw, &correction, NULL);
UTI_AddDoubleToTimeval(&now_raw, correction, &now_cooked);
rep->ref_id = 0;
rep->ref_id = NTP_REFID_UNSYNC;
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = 0;
rep->leap_status = our_leap_status;
@@ -1368,7 +1361,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
} else if (enable_local_stratum) {
rep->ref_id = LOCAL_REFERENCE_ID;
rep->ref_id = NTP_REFID_LOCAL;
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = local_stratum;
rep->ref_time = now_cooked;

View File

@@ -112,4 +112,14 @@ typedef struct {
int unresolved;
} RPT_ActivityReport;
typedef struct {
int active;
int leap_only;
double offset;
double freq_ppm;
double wander_ppm;
double last_update_ago;
double remaining_time;
} RPT_SmoothingReport;
#endif /* GOT_REPORTS_H */

View File

@@ -330,6 +330,10 @@ SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArg
LCL_ReadRawTime(&now);
UTI_AddDoubleToTimeval(&now, delay, &then);
if (UTI_CompareTimevals(&now, &then) > 0) {
LOG_FATAL(LOGF_Scheduler, "Timeout overflow");
}
return SCH_AddTimeout(&then, handler, arg);
}

111
smooth.c
View File

@@ -77,6 +77,10 @@ static struct stage stages[NUM_STAGES];
/* Enabled/disabled smoothing */
static int enabled;
/* Enabled/disabled mode where only leap seconds are smoothed out and normal
offset/frequency changes are ignored */
static int leap_only_mode;
/* Maximum skew/max_wander ratio to start updating offset and frequency */
#define UNLOCK_SKEW_WANDER_RATIO 10000
@@ -93,15 +97,17 @@ static struct timeval last_update;
static void
get_offset_freq(struct timeval *now, double *offset, double *freq)
get_smoothing(struct timeval *now, double *poffset, double *pfreq,
double *pwander)
{
double elapsed, length;
double elapsed, length, offset, freq, wander;
int i;
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
*offset = smooth_offset;
*freq = smooth_freq;
offset = smooth_offset;
freq = smooth_freq;
wander = 0.0;
for (i = 0; i < NUM_STAGES; i++) {
if (elapsed <= 0.0)
@@ -111,13 +117,21 @@ get_offset_freq(struct timeval *now, double *offset, double *freq)
if (length >= elapsed)
length = elapsed;
*offset -= length * (2.0 * *freq + stages[i].wander * length) / 2.0;
*freq += stages[i].wander * length;
wander = stages[i].wander;
offset -= length * (2.0 * freq + wander * length) / 2.0;
freq += wander * length;
elapsed -= length;
}
if (elapsed > 0.0)
*offset -= elapsed * *freq;
if (elapsed > 0.0) {
wander = 0.0;
offset -= elapsed * freq;
}
*poffset = offset;
*pfreq = freq;
if (pwander)
*pwander = wander;
}
static void
@@ -185,14 +199,12 @@ update_smoothing(struct timeval *now, double offset, double freq)
{
/* Don't accept offset/frequency until the clock has stabilized */
if (locked) {
if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO) {
LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated");
locked = 0;
}
if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO || leap_only_mode)
SMT_Activate(now);
return;
}
get_offset_freq(now, &smooth_offset, &smooth_freq);
get_smoothing(now, &smooth_offset, &smooth_freq, NULL);
smooth_offset += offset;
smooth_freq = (smooth_freq - freq) / (1.0 - freq);
last_update = *now;
@@ -208,15 +220,19 @@ handle_slew(struct timeval *raw, struct timeval *cooked, double dfreq,
{
double delta;
if (change_type == LCL_ChangeAdjust)
update_smoothing(cooked, doffset, dfreq);
if (change_type == LCL_ChangeAdjust) {
if (leap_only_mode)
update_smoothing(cooked, 0.0, 0.0);
else
update_smoothing(cooked, doffset, dfreq);
}
UTI_AdjustTimeval(&last_update, cooked, &last_update, &delta, dfreq, doffset);
}
void SMT_Initialise(void)
{
CNF_GetSmooth(&max_freq, &max_wander);
CNF_GetSmooth(&max_freq, &max_wander, &leap_only_mode);
if (max_freq <= 0.0 || max_wander <= 0.0) {
enabled = 0;
return;
@@ -249,19 +265,78 @@ SMT_GetOffset(struct timeval *now)
if (!enabled)
return 0.0;
get_offset_freq(now, &offset, &freq);
get_smoothing(now, &offset, &freq, NULL);
return offset;
}
void
SMT_Activate(struct timeval *now)
{
if (!enabled || !locked)
return;
LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated%s", leap_only_mode ?
" (leap seconds only)" : "");
locked = 0;
last_update = *now;
}
void
SMT_Reset(struct timeval *now)
{
int i;
if (!enabled)
return;
locked = 1;
smooth_offset = 0.0;
smooth_freq = 0.0;
last_update = *now;
for (i = 0; i < NUM_STAGES; i++)
stages[i].wander = stages[i].length = 0.0;
}
void
SMT_Leap(struct timeval *now, int leap)
{
/* When the leap-only mode is disabled, the leap second will be accumulated
in handle_slew() as a normal offset */
if (!enabled || !leap_only_mode)
return;
update_smoothing(now, leap, 0.0);
}
int
SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timeval *now)
{
double length, elapsed;
int i;
if (!enabled)
return 0;
report->active = !locked;
report->leap_only = leap_only_mode;
get_smoothing(now, &report->offset, &report->freq_ppm, &report->wander_ppm);
/* Convert to ppm and negate (positive values mean faster/speeding up) */
report->freq_ppm *= -1.0e6;
report->wander_ppm *= -1.0e6;
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
if (!locked && elapsed >= 0.0) {
for (i = 0, length = 0.0; i < NUM_STAGES; i++)
length += stages[i].length;
report->last_update_ago = elapsed;
report->remaining_time = elapsed < length ? length - elapsed : 0.0;
} else {
report->last_update_ago = 0.0;
report->remaining_time = 0.0;
}
return 1;
}

View File

@@ -27,6 +27,8 @@
#ifndef GOT_SMOOTH_H
#define GOT_SMOOTH_H
#include "reports.h"
extern void SMT_Initialise(void);
extern void SMT_Finalise(void);
@@ -35,6 +37,12 @@ extern int SMT_IsEnabled(void);
extern double SMT_GetOffset(struct timeval *now);
extern void SMT_Activate(struct timeval *now);
extern void SMT_Reset(struct timeval *now);
extern void SMT_Leap(struct timeval *now, int leap);
extern int SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timeval *now);
#endif

View File

@@ -513,7 +513,7 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
{
struct timeval src_ref_time;
double src_offset, src_offset_sd, src_frequency, src_skew;
double src_root_delay, src_root_dispersion, elapsed;
double src_root_delay, src_root_dispersion, sel_src_distance, elapsed;
double offset_weight, sum_offset_weight, sum_offset, sum2_offset_sd;
double frequency_weight, sum_frequency_weight, sum_frequency, inv_sum2_skew;
int i, index, combined;
@@ -524,6 +524,10 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
sum_offset_weight = sum_offset = sum2_offset_sd = 0.0;
sum_frequency_weight = sum_frequency = inv_sum2_skew = 0.0;
sel_src_distance = sources[selected_source_index]->sel_info.root_distance;
if (sources[selected_source_index]->type == SRC_NTP)
sel_src_distance += reselect_distance;
for (i = combined = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
SST_GetTrackingData(sources[index]->stats, &src_ref_time,
@@ -536,8 +540,7 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
are not close, or it was recently marked as distant */
if (index != selected_source_index &&
(sources[index]->sel_info.root_distance > combine_limit *
(reselect_distance + sources[selected_source_index]->sel_info.root_distance) ||
(sources[index]->sel_info.root_distance > combine_limit * sel_src_distance ||
fabs(*frequency - src_frequency) >
combine_limit * (*skew + src_skew + LCL_GetMaxClockError()))) {
/* Use a smaller penalty in first few updates */
@@ -804,43 +807,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
}
#if 0
/* We now have a list of indices for the sources which pass the
false-ticker test. Now go on to reject those whose variance is
greater than the minimum distance of any other */
/* Find minimum distance */
index = sel_sources[0];
min_distance = sources[index]->sel_info.root_distance;
for (i = 1; i < n_sel_sources; i++) {
index = sel_sources[i];
distance = sources[index]->sel_info.root_distance;
if (distance < min_distance) {
min_distance = distance;
}
}
/* Now go through and prune any NTP sources that have excessive
variance */
for (i = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
if (sources[index]->type == SRC_NTP &&
sqrt(sources[index]->sel_info.variance) > min_distance) {
sel_sources[i] = INVALID_SOURCE;
sources[index]->status = SRC_JITTERY;
}
}
/* Now crunch the list and mark all sources as selectable */
for (i = j = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
if (index == INVALID_SOURCE)
continue;
sel_sources[j++] = index;
}
n_sel_sources = j;
#endif
if (n_sel_sources == 0 || n_sel_sources < CNF_GetMinSources()) {
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: %s selectable sources",
@@ -869,16 +835,18 @@ SRC_SelectSource(SRC_Instance updated_inst)
/* If there are any sources with prefer option, reduce the list again
only to the preferred sources */
for (i = j = 0; i < n_sel_sources; i++) {
for (i = 0; i < n_sel_sources; i++) {
if (sources[sel_sources[i]]->sel_option == SRC_SelectPrefer)
sel_sources[j++] = sel_sources[i];
break;
}
if (j > 0) {
for (i = 0; i < n_sel_sources; i++) {
if (i < n_sel_sources) {
for (i = j = 0; i < n_sel_sources; i++) {
if (sources[sel_sources[i]]->sel_option != SRC_SelectPrefer)
sources[sel_sources[i]]->status = SRC_NONPREFERRED;
else
sel_sources[j++] = sel_sources[i];
}
assert(j > 0);
n_sel_sources = j;
sel_prefer = 1;
} else {

12
sys.c
View File

@@ -46,6 +46,10 @@
#include "sys_netbsd.h"
#endif
#if defined (MACOSX)
#include "sys_macosx.h"
#endif
/* ================================================== */
void
@@ -68,6 +72,10 @@ SYS_Initialise(void)
SYS_NetBSD_Initialise();
#endif
#if defined(MACOSX)
SYS_MacOSX_Initialise();
#endif
}
/* ================================================== */
@@ -91,6 +99,10 @@ SYS_Finalise(void)
#if defined(__NetBSD__)
SYS_NetBSD_Finalise();
#endif
#if defined(MACOSX)
SYS_MacOSX_Finalise();
#endif
}
/* ================================================== */

View File

@@ -107,6 +107,18 @@ handle_step(struct timeval *raw, struct timeval *cooked, double dfreq,
}
}
/* ================================================== */
static double
clamp_freq(double freq)
{
if (freq > max_freq)
return max_freq;
if (freq < -max_freq)
return -max_freq;
return freq;
}
/* ================================================== */
/* End currently running slew and start a new one */
@@ -144,11 +156,7 @@ update_slew(void)
corr_freq = max_corr_freq;
/* Get the new real frequency and clamp it */
total_freq = base_freq + corr_freq * (1.0e6 - base_freq);
if (total_freq > max_freq)
total_freq = max_freq;
else if (total_freq < -max_freq)
total_freq = -max_freq;
total_freq = clamp_freq(base_freq + corr_freq * (1.0e6 - base_freq));
/* Set the new frequency (the actual frequency returned by the call may be
slightly different from the requested frequency due to rounding) */
@@ -330,7 +338,7 @@ SYS_Generic_Finalise(void)
slew_timer_running = 0;
}
(*drv_set_freq)(base_freq);
(*drv_set_freq)(clamp_freq(base_freq));
}
/* ================================================== */

314
sys_macosx.c Normal file
View File

@@ -0,0 +1,314 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2001
* Copyright (C) J. Hannken-Illjes 2001
* Copyright (C) Bryan Christianson 2015
*
* 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.
*
**********************************************************************
=======================================================================
Driver file for the MacOS X operating system.
*/
#include "config.h"
#ifdef MACOSX
#include <sys/sysctl.h>
#include <sys/time.h>
#include <nlist.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/time.h>
#include <stdio.h>
#include <signal.h>
#include "sys_macosx.h"
#include "localp.h"
#include "logging.h"
#include "util.h"
/* ================================================== */
/* This register contains the number of seconds by which the local
clock was estimated to be fast of reference time at the epoch when
gettimeofday() returned T0 */
static double offset_register;
/* This register contains the epoch to which the offset is referenced */
static struct timeval T0;
/* This register contains the current estimate of the system
frequency, in absolute (NOT ppm) */
static double current_freq;
/* This register contains the number of seconds of adjustment that
were passed to adjtime last time it was called. */
static double adjustment_requested;
/* Kernel parameters to calculate adjtime error. */
static int kern_tickadj;
static long kern_bigadj;
/* ================================================== */
static void
clock_initialise(void)
{
struct timeval newadj, oldadj;
offset_register = 0.0;
adjustment_requested = 0.0;
current_freq = 0.0;
if (gettimeofday(&T0, NULL) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
}
newadj.tv_sec = 0;
newadj.tv_usec = 0;
if (adjtime(&newadj, &oldadj) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
}
}
/* ================================================== */
static void
clock_finalise(void)
{
/* Nothing to do yet */
}
/* ================================================== */
static void
start_adjust(void)
{
struct timeval newadj, oldadj;
struct timeval T1;
double elapsed, accrued_error;
double adjust_required;
struct timeval exact_newadj;
long delta, tickdelta;
double rounding_error;
double old_adjust_remaining;
/* Determine the amount of error built up since the last adjustment */
if (gettimeofday(&T1, NULL) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
accrued_error = elapsed * current_freq;
adjust_required = - (accrued_error + offset_register);
UTI_DoubleToTimeval(adjust_required, &exact_newadj);
/* At this point, we need to round the required adjustment the
same way the kernel does. */
delta = exact_newadj.tv_sec * 1000000 + exact_newadj.tv_usec;
if (delta > kern_bigadj || delta < -kern_bigadj)
tickdelta = 10 * kern_tickadj;
else
tickdelta = kern_tickadj;
if (delta % tickdelta)
delta = delta / tickdelta * tickdelta;
newadj.tv_sec = 0;
newadj.tv_usec = (int)delta;
UTI_NormaliseTimeval(&newadj);
/* Add rounding error back onto offset register. */
UTI_DiffTimevalsToDouble(&rounding_error, &newadj, &exact_newadj);
if (adjtime(&newadj, &oldadj) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
}
UTI_TimevalToDouble(&oldadj, &old_adjust_remaining);
offset_register = rounding_error - old_adjust_remaining;
T0 = T1;
UTI_TimevalToDouble(&newadj, &adjustment_requested);
}
/* ================================================== */
static void
stop_adjust(void)
{
struct timeval T1;
struct timeval zeroadj, remadj;
double adjustment_remaining, adjustment_achieved;
double elapsed, elapsed_plus_adjust;
zeroadj.tv_sec = 0;
zeroadj.tv_usec = 0;
if (adjtime(&zeroadj, &remadj) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "adjtime() failed");
}
if (gettimeofday(&T1, NULL) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
}
UTI_DiffTimevalsToDouble(&elapsed, &T1, &T0);
UTI_TimevalToDouble(&remadj, &adjustment_remaining);
adjustment_achieved = adjustment_requested - adjustment_remaining;
elapsed_plus_adjust = elapsed - adjustment_achieved;
offset_register += current_freq * elapsed_plus_adjust - adjustment_remaining;
adjustment_requested = 0.0;
T0 = T1;
}
/* ================================================== */
/* Positive offset means system clock is fast of true time, therefore
slew backwards */
static void
accrue_offset(double offset, double corr_rate)
{
stop_adjust();
offset_register += offset;
start_adjust();
}
/* ================================================== */
/* Positive offset means system clock is fast of true time, therefore
step backwards */
static int
apply_step_offset(double offset)
{
struct timeval old_time, new_time, T1;
stop_adjust();
if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysMacOSX, "gettimeofday() failed");
}
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, NULL) < 0) {
DEBUG_LOG(LOGF_SysMacOSX, "settimeofday() failed");
return 0;
}
UTI_AddDoubleToTimeval(&T0, offset, &T1);
T0 = T1;
start_adjust();
return 1;
}
/* ================================================== */
static double
set_frequency(double new_freq_ppm)
{
stop_adjust();
current_freq = new_freq_ppm * 1.0e-6;
start_adjust();
return current_freq * 1.0e6;
}
/* ================================================== */
static double
read_frequency(void)
{
return current_freq * 1.0e6;
}
/* ================================================== */
static void
get_offset_correction(struct timeval *raw,
double *corr, double *err)
{
stop_adjust();
*corr = -offset_register;
start_adjust();
if (err)
*err = 0.0;
}
/* ================================================== */
void
SYS_MacOSX_Initialise(void)
{
int result;
size_t len;
struct clockinfo clockinfo;
int mib[2];
mib[0] = CTL_KERN;
mib[1] = KERN_CLOCKRATE;
len = sizeof(clockinfo);
result = sysctl(mib, 2, &clockinfo, &len, NULL, 0);
if(result < 0) {
LOG_FATAL(LOGF_SysMacOSX, "Cannot read clockinfo");
}
kern_tickadj = clockinfo.tickadj;
kern_bigadj = clockinfo.tick;
clock_initialise();
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
get_offset_correction,
NULL /* set_leap */,
NULL /* set_sync_status */);
}
/* ================================================== */
void
SYS_MacOSX_Finalise(void)
{
clock_finalise();
}
/* ================================================== */
#endif

37
sys_macosx.h Normal file
View File

@@ -0,0 +1,37 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2001
* Copyright (C) J. Hannken-Illjes 2001
* Copyright (C) Bryan Christianson 2015
*
* 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.
*
**********************************************************************
=======================================================================
Header file for MacOS X driver
*/
#ifndef GOT_SYS_MACOSX_H
#define GOT_SYS_MACOSX_H
void SYS_MacOSX_Initialise(void);
void SYS_MacOSX_Finalise(void);
#endif

View File

@@ -29,9 +29,9 @@
#ifndef GOT_SYSINCL_H
#define GOT_SYSINCL_H
#if defined (SOLARIS) || defined(SUNOS) || defined(LINUX) || defined(__NetBSD__)
#if defined (SOLARIS) || defined(SUNOS) || defined(LINUX) || defined(__NetBSD__) || defined (MACOSX)
#if !defined(__NetBSD__) && !defined(__FreeBSD__)
#if !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(MACOSX)
#include <alloca.h>
#endif
#include <assert.h>
@@ -39,7 +39,7 @@
#include <errno.h>
#include <fcntl.h>
#include <float.h>
#if !defined(__FreeBSD__)
#if !defined(__FreeBSD__) && !defined(MACOSX)
#include <malloc.h>
#endif
#include <math.h>

View File

@@ -27,18 +27,20 @@ for leapmode in system step slew; do
check_sync || test_fail
done
server_conf="refclock SHM 0 dpoll 10 poll 10
leapsectz right/UTC
leapsecmode slew
smoothtime 400 0.001"
client_conf="leapsecmode system"
min_sync_time=230000
max_sync_time=240000
for smoothmode in "" "leaponly"; do
server_conf="refclock SHM 0 dpoll 10 poll 10
leapsectz right/UTC
leapsecmode slew
smoothtime 400 0.001 $smoothmode"
client_conf="leapsecmode system"
min_sync_time=230000
max_sync_time=240000
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
done
test_pass

21
test/simulation/202-prefer Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
. test.common
# Test fix in commit 4253075a97141edfa62043ab71bd0673587e6629
test_start "prefer option"
servers=3
client_server_conf="
server 192.168.123.1
server 192.168.123.2
server 192.168.123.3 prefer"
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
test_pass

View File

@@ -18,7 +18,7 @@ export PATH=../../:$PATH
export CLKNETSIM_PATH=clknetsim
# Known working clknetsim revision
clknetsim_revision=3eb3a8d9acf60c31f5acc66617175fc748ef367e
clknetsim_revision=1e56224dee1db69c0027e9bd63c2a202d4765959
clknetsim_url=https://github.com/mlichvar/clknetsim/archive/$clknetsim_revision.tar.gz
# Only Linux is supported
@@ -65,6 +65,7 @@ default_chronyc_start=1000.0
default_server_step=""
default_client_step=""
default_client_server_conf=""
default_server_server_options=""
default_client_server_options=""
default_server_peer_options=""
@@ -192,9 +193,13 @@ get_chronyd_conf() {
done
echo "$server_conf"
else
for i in $(seq 1 $servers); do
echo "server 192.168.123.$[$servers * ($stratum - 2) + $i] $client_server_options"
done
if [ -n "$client_server_conf" ]; then
echo "$client_server_conf"
else
for i in $(seq 1 $servers); do
echo "server 192.168.123.$[$servers * ($stratum - 2) + $i] $client_server_options"
done
fi
for i in $(seq 1 $peers); do
[ $i -eq $peer -o $i -gt $clients ] && continue
echo "peer 192.168.123.$[$servers * ($stratum - 1) + $i] $client_peer_options"

29
util.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009, 2012-2013
* Copyright (C) Miroslav Lichvar 2009, 2012-2015
*
* 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
@@ -609,6 +609,9 @@ UTI_Int64ToTimeval(NTP_int64 *src,
/* Maximum offset between two sane times */
#define MAX_OFFSET 4294967296.0
/* Minimum allowed distance from maximum 32-bit time_t */
#define MIN_ENDOFTIME_DISTANCE (365 * 24 * 3600)
int
UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
{
@@ -629,6 +632,10 @@ UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
/* Check if it's in the interval to which NTP time is mapped */
if (t < (double)NTP_ERA_SPLIT || t > (double)(NTP_ERA_SPLIT + (1LL << 32)))
return 0;
#else
/* Don't get too close to 32-bit time_t overflow */
if (t > (double)(0x7fffffff - MIN_ENDOFTIME_DISTANCE))
return 0;
#endif
return 1;
@@ -636,6 +643,22 @@ UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
/* ================================================== */
double
UTI_Log2ToDouble(int l)
{
if (l >= 0) {
if (l > 31)
l = 31;
return 1 << l;
} else {
if (l < -31)
l = -31;
return 1.0 / (1 << -l);
}
}
/* ================================================== */
void
UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest)
{
@@ -700,7 +723,11 @@ UTI_FloatHostToNetwork(double x)
if (x < 0.0) {
x = -x;
neg = 1;
} else if (x >= 0.0) {
neg = 0;
} else {
/* Save NaN as zero */
x = 0.0;
neg = 0;
}

3
util.h
View File

@@ -107,6 +107,9 @@ extern void UTI_Int64ToTimeval(NTP_int64 *src, struct timeval *dest);
/* Check if time + offset is sane */
extern int UTI_IsTimeOffsetSane(struct timeval *tv, double offset);
/* Get 2 raised to power of a signed integer */
extern double UTI_Log2ToDouble(int l);
extern void UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest);
extern void UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest);

View File

@@ -71,7 +71,7 @@ TMX_ResetOffset(void)
/* Set status back */
txc.modes = ADJ_STATUS;
txc.modes = status;
txc.status = status;
if (adjtimex(&txc) < 0)
return -1;