mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 18:25:07 -05:00
Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5187c08c90 | ||
|
|
c8076ac10d | ||
|
|
362d155558 | ||
|
|
7b7eb0a6e5 | ||
|
|
d96f49f67d | ||
|
|
43ba5d2126 | ||
|
|
48f7598fed | ||
|
|
510b22e96b | ||
|
|
0a0aff14d8 | ||
|
|
e225ac68bc | ||
|
|
58060c40a5 | ||
|
|
2ac1b3d5c4 | ||
|
|
c174566982 | ||
|
|
60fca19d40 | ||
|
|
8bcb15b02f | ||
|
|
65c2cebcd5 | ||
|
|
2a51b45a43 | ||
|
|
5ac791665e | ||
|
|
a4e3f83611 | ||
|
|
8a837f9c2b | ||
|
|
da2d33e9a8 | ||
|
|
4b98dadae9 | ||
|
|
86acea5c46 | ||
|
|
a60fc73e7b | ||
|
|
50f99ec5f4 | ||
|
|
31b6a14444 | ||
|
|
9df4d36157 | ||
|
|
b70f0b674f | ||
|
|
510784077f | ||
|
|
9800e397fb | ||
|
|
1436d9961f | ||
|
|
98f5d05925 | ||
|
|
7a937c7652 | ||
|
|
b198d76676 | ||
|
|
97d4203354 | ||
|
|
beaaaad162 | ||
|
|
4e78975909 | ||
|
|
99147ed8f2 | ||
|
|
dec0d3bfc2 | ||
|
|
cd84c99e70 | ||
|
|
d5c507975c | ||
|
|
b4235abd36 | ||
|
|
1966085a97 | ||
|
|
e31e7af48f | ||
|
|
adb9123fc3 | ||
|
|
b0f7efd59e | ||
|
|
e28dfada8c | ||
|
|
ac0b28cce6 | ||
|
|
48b16ae66c | ||
|
|
061579ec28 | ||
|
|
f2f834e7e7 | ||
|
|
a7802e9a76 | ||
|
|
8f7ab95ff0 | ||
|
|
042c670747 | ||
|
|
cacbe9976f | ||
|
|
8efec1d640 | ||
|
|
c44d282f0b | ||
|
|
4432f29bd2 | ||
|
|
5fee3ed5e9 | ||
|
|
b76ea64263 | ||
|
|
ed904f08a4 | ||
|
|
96cc80ffc8 | ||
|
|
ab99373cfc | ||
|
|
dbfb49384b | ||
|
|
14bb9f29a3 | ||
|
|
16519ee2cc | ||
|
|
50022e9286 | ||
|
|
5059019535 | ||
|
|
c6a38f5069 | ||
|
|
11ed197663 | ||
|
|
5634e6b963 | ||
|
|
db312a5ff6 | ||
|
|
88c31b3785 | ||
|
|
967f3e4f77 | ||
|
|
2e311d1766 | ||
|
|
11f7cc0507 | ||
|
|
a4f28892a5 | ||
|
|
5bc53741be | ||
|
|
95a4f33265 | ||
|
|
fac1093ebf | ||
|
|
1b1384ccaa | ||
|
|
0c9a19ded5 | ||
|
|
b7bd7469b7 |
@@ -64,10 +64,10 @@ chronyc : $(CLI_OBJS)
|
||||
$(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_CLI_LIBS)
|
||||
|
||||
distclean : clean
|
||||
-rm -f .DS_Store
|
||||
-rm -f Makefile config.h config.log
|
||||
$(MAKE) -C doc distclean
|
||||
$(MAKE) -C test/unit distclean
|
||||
-rm -f .DS_Store
|
||||
-rm -f Makefile config.h config.log
|
||||
|
||||
clean :
|
||||
-rm -f *.o *.s chronyc chronyd core *~
|
||||
|
||||
21
NEWS
21
NEWS
@@ -1,3 +1,18 @@
|
||||
New in version 3.1
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add support for precise cross timestamping of PHC on Linux
|
||||
* Add minpoll, precision, nocrossts options to hwtimestamp directive
|
||||
* Add rawmeasurements option to log directive and modify measurements
|
||||
option to log only valid measurements from synchronised sources
|
||||
* Allow sub-second polling interval with NTP sources
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix time smoothing in interleaved mode
|
||||
|
||||
New in version 3.0
|
||||
==================
|
||||
|
||||
@@ -16,14 +31,20 @@ Enhancements
|
||||
* Add -t option to chronyd to exit after specified time
|
||||
* Add partial protection against replay attacks on symmetric mode
|
||||
* Don't reset polling interval when switching sources to online state
|
||||
* Allow rate limiting with very short intervals
|
||||
* Improve maximum server throughput on Linux and NetBSD
|
||||
* Remove dump files after start
|
||||
* Add tab-completion to chronyc with libedit/readline
|
||||
* Add ntpdata command to print details about NTP measurements
|
||||
* Allow all source options to be set in add server/peer command
|
||||
* Indicate truncated addresses/hostnames in chronyc output
|
||||
* Print reference IDs as hexadecimal numbers to avoid confusion with
|
||||
IPv4 addresses
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix crash with disabled asynchronous name resolving
|
||||
|
||||
New in version 2.4.1
|
||||
====================
|
||||
|
||||
|
||||
5
README
5
README
@@ -16,7 +16,7 @@ and systems that do not run continuosly, or run on a virtual machine.
|
||||
|
||||
Typical accuracy between two machines synchronised over the Internet is
|
||||
within a few milliseconds; on a LAN, accuracy is typically in tens of
|
||||
microseconds. With hardware timestamping or a hardware reference clock
|
||||
microseconds. With hardware timestamping, or a hardware reference clock,
|
||||
sub-microsecond accuracy may be possible.
|
||||
|
||||
Two programs are included in chrony, chronyd is a daemon that can be
|
||||
@@ -203,6 +203,9 @@ Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
|
||||
Frank Otto <sandwichmacher@web.de>
|
||||
Handling arbitrary HZ values
|
||||
|
||||
Denny Page <dennypage@me.com>
|
||||
Advice on support for hardware timestamping
|
||||
|
||||
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
|
||||
Patch to add refresh command to chronyc
|
||||
|
||||
|
||||
@@ -50,8 +50,11 @@ typedef struct {
|
||||
unsigned short port;
|
||||
} NTP_Remote_Address;
|
||||
|
||||
#define INVALID_IF_INDEX -1
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
int if_index;
|
||||
int sock_fd;
|
||||
} NTP_Local_Address;
|
||||
|
||||
|
||||
5
candm.h
5
candm.h
@@ -362,8 +362,8 @@ typedef struct {
|
||||
domain socket.
|
||||
|
||||
Version 6 (no authentication) : changed format of client accesses by index
|
||||
(using new request/reply types), new flags in NTP source request and report,
|
||||
new commands: refresh, serverstats
|
||||
(using new request/reply types), new fields and flags in NTP source request
|
||||
and report, new commands: ntpdata, refresh, serverstats
|
||||
*/
|
||||
|
||||
#define PROTO_VERSION_NUMBER 6
|
||||
@@ -672,6 +672,7 @@ typedef struct {
|
||||
uint32_t total_tx_count;
|
||||
uint32_t total_rx_count;
|
||||
uint32_t total_valid_count;
|
||||
uint32_t reserved[4];
|
||||
int32_t EOR;
|
||||
} RPY_NTPData;
|
||||
|
||||
|
||||
172
client.c
172
client.c
@@ -3,6 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Lonnie Abelbeck 2016
|
||||
* Copyright (C) Miroslav Lichvar 2009-2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -1191,7 +1192,7 @@ give_help(void)
|
||||
"\0\0"
|
||||
"NTP sources:\0\0"
|
||||
"activity\0Check how many NTP sources are online/offline\0"
|
||||
"ntpdata <address>\0Display information about last valid measurement\0"
|
||||
"ntpdata [<address>]\0Display information about last valid measurement\0"
|
||||
"add server <address> [options]\0Add new NTP server\0"
|
||||
"add peer <address> [options]\0Add new NTP peer\0"
|
||||
"delete <address>\0Remove server or peer\0"
|
||||
@@ -1241,6 +1242,7 @@ give_help(void)
|
||||
"Other daemon commands:\0\0"
|
||||
"cyclelogs\0Close and re-open log files\0"
|
||||
"dump\0Dump all measurements to save files\0"
|
||||
"rekey\0Re-read keys from key file\0"
|
||||
"\0\0"
|
||||
"Client commands:\0\0"
|
||||
"dns -n|+n\0Disable/enable resolving IP addresses to hostnames\0"
|
||||
@@ -2214,8 +2216,8 @@ process_cmd_tracking(char *line)
|
||||
"Frequency : %.3F\n"
|
||||
"Residual freq : %+.3f ppm\n"
|
||||
"Skew : %.3f ppm\n"
|
||||
"Root delay : %.6f seconds\n"
|
||||
"Root dispersion : %.6f seconds\n"
|
||||
"Root delay : %.9f seconds\n"
|
||||
"Root dispersion : %.9f seconds\n"
|
||||
"Update interval : %.1f seconds\n"
|
||||
"Leap status : %L\n",
|
||||
(unsigned long)ref_id, name,
|
||||
@@ -2244,71 +2246,107 @@ process_cmd_ntpdata(char *line)
|
||||
CMD_Reply reply;
|
||||
IPAddr remote_addr, local_addr;
|
||||
struct timespec ref_time;
|
||||
uint32_t i, n_sources;
|
||||
uint16_t mode;
|
||||
int specified_addr;
|
||||
|
||||
if (DNS_Name2IPAddress(line, &remote_addr, 1) != DNS_Success) {
|
||||
LOG(LOGS_ERR, LOGF_Client, "Could not get address for hostname");
|
||||
return 0;
|
||||
if (*line) {
|
||||
specified_addr = 1;
|
||||
n_sources = 1;
|
||||
} else {
|
||||
specified_addr = 0;
|
||||
request.command = htons(REQ_N_SOURCES);
|
||||
if (!request_reply(&request, &reply, RPY_N_SOURCES, 0))
|
||||
return 0;
|
||||
n_sources = ntohl(reply.data.n_sources.n_sources);
|
||||
}
|
||||
|
||||
request.command = htons(REQ_NTP_DATA);
|
||||
UTI_IPHostToNetwork(&remote_addr, &request.data.ntp_data.ip_addr);
|
||||
if (!request_reply(&request, &reply, RPY_NTP_DATA, 0))
|
||||
return 0;
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
if (specified_addr) {
|
||||
if (DNS_Name2IPAddress(line, &remote_addr, 1) != DNS_Success) {
|
||||
LOG(LOGS_ERR, LOGF_Client, "Could not get address for hostname");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
request.command = htons(REQ_SOURCE_DATA);
|
||||
request.data.source_data.index = htonl(i);
|
||||
if (!request_reply(&request, &reply, RPY_SOURCE_DATA, 0))
|
||||
return 0;
|
||||
|
||||
UTI_IPNetworkToHost(&reply.data.ntp_data.remote_addr, &remote_addr);
|
||||
UTI_IPNetworkToHost(&reply.data.ntp_data.local_addr, &local_addr);
|
||||
UTI_TimespecNetworkToHost(&reply.data.ntp_data.ref_time, &ref_time);
|
||||
mode = ntohs(reply.data.source_data.mode);
|
||||
if (mode != RPY_SD_MD_CLIENT && mode != RPY_SD_MD_PEER)
|
||||
continue;
|
||||
|
||||
print_report("Remote address : %s (%R)\n"
|
||||
"Remote port : %u\n"
|
||||
"Local address : %s (%R)\n"
|
||||
"Leap status : %L\n"
|
||||
"Version : %u\n"
|
||||
"Mode : %M\n"
|
||||
"Stratum : %u\n"
|
||||
"Poll : %d\n"
|
||||
"Precision : %.9f seconds\n"
|
||||
"Root delay : %.6f seconds\n"
|
||||
"Root dispersion : %.6f seconds\n"
|
||||
"Reference ID : %R\n"
|
||||
"Reference time : %T\n"
|
||||
"Offset : %+.9f seconds\n"
|
||||
"Peer delay : %.9f seconds\n"
|
||||
"Peer dispersion : %.9f seconds\n"
|
||||
"Response time : %.9f seconds\n"
|
||||
"Jitter asymmetry: %+.2f\n"
|
||||
"NTP tests : %.3b %.3b %.4b\n"
|
||||
"Interleaved : %B\n"
|
||||
"Authenticated : %B\n"
|
||||
"TX timestamping : %N\n"
|
||||
"RX timestamping : %N\n"
|
||||
"Total TX : %U\n"
|
||||
"Total RX : %U\n"
|
||||
"Total valid RX : %U\n",
|
||||
UTI_IPToString(&remote_addr), (unsigned long)UTI_IPToRefid(&remote_addr),
|
||||
ntohs(reply.data.ntp_data.remote_port),
|
||||
UTI_IPToString(&local_addr), (unsigned long)UTI_IPToRefid(&local_addr),
|
||||
reply.data.ntp_data.leap, reply.data.ntp_data.version,
|
||||
reply.data.ntp_data.mode, reply.data.ntp_data.stratum,
|
||||
reply.data.ntp_data.poll, UTI_Log2ToDouble(reply.data.ntp_data.precision),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.root_delay),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.root_dispersion),
|
||||
(unsigned long)ntohl(reply.data.ntp_data.ref_id), &ref_time,
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.offset),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.peer_delay),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.peer_dispersion),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.response_time),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.jitter_asymmetry),
|
||||
ntohs(reply.data.ntp_data.flags) >> 7,
|
||||
ntohs(reply.data.ntp_data.flags) >> 4,
|
||||
ntohs(reply.data.ntp_data.flags),
|
||||
ntohs(reply.data.ntp_data.flags) & RPY_NTP_FLAG_INTERLEAVED,
|
||||
ntohs(reply.data.ntp_data.flags) & RPY_NTP_FLAG_AUTHENTICATED,
|
||||
reply.data.ntp_data.tx_tss_char, reply.data.ntp_data.rx_tss_char,
|
||||
(unsigned long)ntohl(reply.data.ntp_data.total_tx_count),
|
||||
(unsigned long)ntohl(reply.data.ntp_data.total_rx_count),
|
||||
(unsigned long)ntohl(reply.data.ntp_data.total_valid_count),
|
||||
REPORT_END);
|
||||
UTI_IPNetworkToHost(&reply.data.source_data.ip_addr, &remote_addr);
|
||||
}
|
||||
|
||||
request.command = htons(REQ_NTP_DATA);
|
||||
UTI_IPHostToNetwork(&remote_addr, &request.data.ntp_data.ip_addr);
|
||||
if (!request_reply(&request, &reply, RPY_NTP_DATA, 0))
|
||||
return 0;
|
||||
|
||||
UTI_IPNetworkToHost(&reply.data.ntp_data.remote_addr, &remote_addr);
|
||||
UTI_IPNetworkToHost(&reply.data.ntp_data.local_addr, &local_addr);
|
||||
UTI_TimespecNetworkToHost(&reply.data.ntp_data.ref_time, &ref_time);
|
||||
|
||||
if (!specified_addr && !csv_mode)
|
||||
printf("\n");
|
||||
|
||||
print_report("Remote address : %s (%R)\n"
|
||||
"Remote port : %u\n"
|
||||
"Local address : %s (%R)\n"
|
||||
"Leap status : %L\n"
|
||||
"Version : %u\n"
|
||||
"Mode : %M\n"
|
||||
"Stratum : %u\n"
|
||||
"Poll interval : %d (%.0f seconds)\n"
|
||||
"Precision : %d (%.9f seconds)\n"
|
||||
"Root delay : %.6f seconds\n"
|
||||
"Root dispersion : %.6f seconds\n"
|
||||
"Reference ID : %R (%s)\n"
|
||||
"Reference time : %T\n"
|
||||
"Offset : %+.9f seconds\n"
|
||||
"Peer delay : %.9f seconds\n"
|
||||
"Peer dispersion : %.9f seconds\n"
|
||||
"Response time : %.9f seconds\n"
|
||||
"Jitter asymmetry: %+.2f\n"
|
||||
"NTP tests : %.3b %.3b %.4b\n"
|
||||
"Interleaved : %B\n"
|
||||
"Authenticated : %B\n"
|
||||
"TX timestamping : %N\n"
|
||||
"RX timestamping : %N\n"
|
||||
"Total TX : %U\n"
|
||||
"Total RX : %U\n"
|
||||
"Total valid RX : %U\n",
|
||||
UTI_IPToString(&remote_addr), (unsigned long)UTI_IPToRefid(&remote_addr),
|
||||
ntohs(reply.data.ntp_data.remote_port),
|
||||
UTI_IPToString(&local_addr), (unsigned long)UTI_IPToRefid(&local_addr),
|
||||
reply.data.ntp_data.leap, reply.data.ntp_data.version,
|
||||
reply.data.ntp_data.mode, reply.data.ntp_data.stratum,
|
||||
reply.data.ntp_data.poll, UTI_Log2ToDouble(reply.data.ntp_data.poll),
|
||||
reply.data.ntp_data.precision, UTI_Log2ToDouble(reply.data.ntp_data.precision),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.root_delay),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.root_dispersion),
|
||||
(unsigned long)ntohl(reply.data.ntp_data.ref_id),
|
||||
reply.data.ntp_data.stratum <= 1 ?
|
||||
UTI_RefidToString(ntohl(reply.data.ntp_data.ref_id)) : "",
|
||||
&ref_time,
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.offset),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.peer_delay),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.peer_dispersion),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.response_time),
|
||||
UTI_FloatNetworkToHost(reply.data.ntp_data.jitter_asymmetry),
|
||||
ntohs(reply.data.ntp_data.flags) >> 7,
|
||||
ntohs(reply.data.ntp_data.flags) >> 4,
|
||||
ntohs(reply.data.ntp_data.flags),
|
||||
ntohs(reply.data.ntp_data.flags) & RPY_NTP_FLAG_INTERLEAVED,
|
||||
ntohs(reply.data.ntp_data.flags) & RPY_NTP_FLAG_AUTHENTICATED,
|
||||
reply.data.ntp_data.tx_tss_char, reply.data.ntp_data.rx_tss_char,
|
||||
(unsigned long)ntohl(reply.data.ntp_data.total_tx_count),
|
||||
(unsigned long)ntohl(reply.data.ntp_data.total_rx_count),
|
||||
(unsigned long)ntohl(reply.data.ntp_data.total_valid_count),
|
||||
REPORT_END);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -2687,7 +2725,8 @@ process_cmd_waitsync(char *line)
|
||||
max_skew_ppm = 0.0;
|
||||
interval = 10.0;
|
||||
|
||||
sscanf(line, "%d %lf %lf %lf", &max_tries, &max_correction, &max_skew_ppm, &interval);
|
||||
if (sscanf(line, "%d %lf %lf %lf", &max_tries, &max_correction, &max_skew_ppm, &interval))
|
||||
;
|
||||
|
||||
/* Don't allow shorter interval than 0.1 seconds */
|
||||
if (interval < 0.1)
|
||||
@@ -2795,7 +2834,8 @@ process_cmd_keygen(char *line)
|
||||
snprintf(hash_name, sizeof (hash_name), "MD5");
|
||||
#endif
|
||||
|
||||
sscanf(line, "%u %16s %d", &id, hash_name, &bits);
|
||||
if (sscanf(line, "%u %16s %d", &id, hash_name, &bits))
|
||||
;
|
||||
|
||||
length = CLAMP(10, (bits + 7) / 8, sizeof (key));
|
||||
if (HSH_GetHashId(hash_name) < 0) {
|
||||
@@ -3058,7 +3098,7 @@ static void
|
||||
display_gpl(void)
|
||||
{
|
||||
printf("chrony version %s\n"
|
||||
"Copyright (C) 1997-2003, 2007, 2009-2016 Richard P. Curnow and others\n"
|
||||
"Copyright (C) 1997-2003, 2007, 2009-2017 Richard P. Curnow and others\n"
|
||||
"chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n"
|
||||
"you are welcome to redistribute it under certain conditions. See the\n"
|
||||
"GNU General Public License version 2 for details.\n\n",
|
||||
|
||||
42
clientlog.c
42
clientlog.c
@@ -86,6 +86,10 @@ static unsigned int max_slots;
|
||||
#define TS_FRAC 4
|
||||
#define INVALID_TS 0
|
||||
|
||||
/* Static offset included in conversion to the fixed-point timestamps to
|
||||
randomise their alignment */
|
||||
static uint32_t ts_offset;
|
||||
|
||||
/* Request rates are saved in the record as 8-bit scaled log2 values */
|
||||
#define RATE_SCALE 4
|
||||
#define MIN_RATE (-14 * RATE_SCALE)
|
||||
@@ -95,7 +99,7 @@ static unsigned int max_slots;
|
||||
number of tokens spent on response are determined from configured
|
||||
minimum inverval between responses (in log2) and burst length. */
|
||||
|
||||
#define MIN_LIMIT_INTERVAL (-TS_FRAC)
|
||||
#define MIN_LIMIT_INTERVAL (-15 - TS_FRAC)
|
||||
#define MAX_LIMIT_INTERVAL 12
|
||||
#define MIN_LIMIT_BURST 1
|
||||
#define MAX_LIMIT_BURST 255
|
||||
@@ -105,7 +109,8 @@ static uint16_t max_cmd_tokens;
|
||||
static uint16_t ntp_tokens_per_packet;
|
||||
static uint16_t cmd_tokens_per_packet;
|
||||
|
||||
/* Reduction of token rates to avoid overflow of 16-bit counters */
|
||||
/* Reduction of token rates to avoid overflow of 16-bit counters. Negative
|
||||
shift is used for coarse limiting with intervals shorter than -TS_FRAC. */
|
||||
static int ntp_token_shift;
|
||||
static int cmd_token_shift;
|
||||
|
||||
@@ -133,6 +138,8 @@ static uint32_t total_ntp_drops;
|
||||
static uint32_t total_cmd_drops;
|
||||
static uint32_t total_record_drops;
|
||||
|
||||
#define NSEC_PER_SEC 1000000000U
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int expand_hashtable(void);
|
||||
@@ -271,10 +278,17 @@ set_bucket_params(int interval, int burst, uint16_t *max_tokens,
|
||||
interval = CLAMP(MIN_LIMIT_INTERVAL, interval, MAX_LIMIT_INTERVAL);
|
||||
burst = CLAMP(MIN_LIMIT_BURST, burst, MAX_LIMIT_BURST);
|
||||
|
||||
/* Find smallest shift with which the maximum number fits in 16 bits */
|
||||
for (*token_shift = 0; *token_shift < interval + TS_FRAC; (*token_shift)++) {
|
||||
if (burst << (TS_FRAC + interval - *token_shift) < 1U << 16)
|
||||
break;
|
||||
if (interval >= -TS_FRAC) {
|
||||
/* Find the smallest shift with which the maximum number fits in 16 bits */
|
||||
for (*token_shift = 0; *token_shift < interval + TS_FRAC; (*token_shift)++) {
|
||||
if (burst << (TS_FRAC + interval - *token_shift) < 1U << 16)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Coarse rate limiting */
|
||||
*token_shift = interval + TS_FRAC;
|
||||
*tokens_per_packet = 1;
|
||||
burst = MAX(1U << -*token_shift, burst);
|
||||
}
|
||||
|
||||
*tokens_per_packet = 1U << (TS_FRAC + interval - *token_shift);
|
||||
@@ -325,6 +339,9 @@ CLG_Initialise(void)
|
||||
records = NULL;
|
||||
|
||||
expand_hashtable();
|
||||
|
||||
UTI_GetRandomBytes(&ts_offset, sizeof (ts_offset));
|
||||
ts_offset %= NSEC_PER_SEC / (1U << TS_FRAC);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -345,6 +362,12 @@ get_ts_from_timespec(struct timespec *ts)
|
||||
{
|
||||
uint32_t sec = ts->tv_sec, nsec = ts->tv_nsec;
|
||||
|
||||
nsec += ts_offset;
|
||||
if (nsec >= NSEC_PER_SEC) {
|
||||
nsec -= NSEC_PER_SEC;
|
||||
sec++;
|
||||
}
|
||||
|
||||
/* This is fast and accurate enough */
|
||||
return sec << TS_FRAC | (140740U * (nsec >> 15)) >> (32 - TS_FRAC);
|
||||
}
|
||||
@@ -369,7 +392,12 @@ update_record(struct timespec *now, uint32_t *last_hit, uint32_t *hits,
|
||||
if (prev_hit == INVALID_TS || (int32_t)interval < 0)
|
||||
return;
|
||||
|
||||
new_tokens = (now_ts >> token_shift) - (prev_hit >> token_shift);
|
||||
if (token_shift >= 0)
|
||||
new_tokens = (now_ts >> token_shift) - (prev_hit >> token_shift);
|
||||
else if (now_ts - prev_hit > max_tokens)
|
||||
new_tokens = max_tokens;
|
||||
else
|
||||
new_tokens = (now_ts - prev_hit) << -token_shift;
|
||||
*tokens = MIN(*tokens + new_tokens, max_tokens);
|
||||
|
||||
/* Convert the interval to scaled and rounded log2 */
|
||||
|
||||
1
cmdmon.c
1
cmdmon.c
@@ -1232,6 +1232,7 @@ handle_ntp_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
tx_message->data.ntp_data.total_tx_count = htonl(report.total_tx_count);
|
||||
tx_message->data.ntp_data.total_rx_count = htonl(report.total_rx_count);
|
||||
tx_message->data.ntp_data.total_valid_count = htonl(report.total_valid_count);
|
||||
memset(tx_message->data.ntp_data.reserved, 0xff, sizeof (tx_message->data.ntp_data.reserved));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
80
conf.c
80
conf.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2016
|
||||
* Copyright (C) Miroslav Lichvar 2009-2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -97,6 +97,7 @@ static double combine_limit = 3.0;
|
||||
|
||||
static int cmd_port = DEFAULT_CANDM_PORT;
|
||||
|
||||
static int raw_measurements = 0;
|
||||
static int do_log_measurements = 0;
|
||||
static int do_log_statistics = 0;
|
||||
static int do_log_tracking = 0;
|
||||
@@ -194,10 +195,10 @@ static char *pidfile;
|
||||
static int ntp_ratelimit_enabled = 0;
|
||||
static int ntp_ratelimit_interval = 3;
|
||||
static int ntp_ratelimit_burst = 8;
|
||||
static int ntp_ratelimit_leak = 3;
|
||||
static int ntp_ratelimit_leak = 2;
|
||||
static int cmd_ratelimit_enabled = 0;
|
||||
static int cmd_ratelimit_interval = 1;
|
||||
static int cmd_ratelimit_burst = 16;
|
||||
static int cmd_ratelimit_interval = -4;
|
||||
static int cmd_ratelimit_burst = 8;
|
||||
static int cmd_ratelimit_leak = 2;
|
||||
|
||||
/* Smoothing constants */
|
||||
@@ -223,7 +224,7 @@ static char *leapsec_tz = NULL;
|
||||
/* Name of the user to which will be dropped root privileges. */
|
||||
static char *user;
|
||||
|
||||
/* Array of strings for interfaces with HW timestamping */
|
||||
/* Array of CNF_HwTsInterface */
|
||||
static ARR_Instance hwts_interfaces;
|
||||
|
||||
typedef struct {
|
||||
@@ -327,7 +328,7 @@ CNF_Initialise(int r)
|
||||
{
|
||||
restarted = r;
|
||||
|
||||
hwts_interfaces = ARR_CreateInstance(sizeof (char *));
|
||||
hwts_interfaces = ARR_CreateInstance(sizeof (CNF_HwTsInterface));
|
||||
|
||||
init_sources = ARR_CreateInstance(sizeof (IPAddr));
|
||||
ntp_sources = ARR_CreateInstance(sizeof (NTP_Source));
|
||||
@@ -354,7 +355,7 @@ CNF_Finalise(void)
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARR_GetSize(hwts_interfaces); i++)
|
||||
Free(*(char **)ARR_GetElement(hwts_interfaces, i));
|
||||
Free(((CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, i))->name);
|
||||
ARR_DestroyInstance(hwts_interfaces);
|
||||
|
||||
for (i = 0; i < ARR_GetSize(ntp_sources); i++)
|
||||
@@ -814,7 +815,10 @@ parse_log(char *line)
|
||||
log_name = line;
|
||||
line = CPS_SplitWord(line);
|
||||
if (*log_name) {
|
||||
if (!strcmp(log_name, "measurements")) {
|
||||
if (!strcmp(log_name, "rawmeasurements")) {
|
||||
do_log_measurements = 1;
|
||||
raw_measurements = 1;
|
||||
} else if (!strcmp(log_name, "measurements")) {
|
||||
do_log_measurements = 1;
|
||||
} else if (!strcmp(log_name, "statistics")) {
|
||||
do_log_statistics = 1;
|
||||
@@ -1245,8 +1249,51 @@ parse_tempcomp(char *line)
|
||||
static void
|
||||
parse_hwtimestamp(char *line)
|
||||
{
|
||||
check_number_of_args(line, 1);
|
||||
*(char **)ARR_GetNewElement(hwts_interfaces) = Strdup(line);
|
||||
CNF_HwTsInterface *iface;
|
||||
char *p;
|
||||
int n;
|
||||
|
||||
if (!*line) {
|
||||
command_parse_error();
|
||||
return;
|
||||
}
|
||||
|
||||
p = line;
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
iface = ARR_GetNewElement(hwts_interfaces);
|
||||
iface->name = Strdup(p);
|
||||
iface->minpoll = 0;
|
||||
iface->nocrossts = 0;
|
||||
iface->precision = 100.0e-9;
|
||||
iface->tx_comp = 0.0;
|
||||
iface->rx_comp = 0.0;
|
||||
|
||||
for (p = line; *p; line += n, p = line) {
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
if (!strcasecmp(p, "minpoll")) {
|
||||
if (sscanf(line, "%d%n", &iface->minpoll, &n) != 1)
|
||||
break;
|
||||
} else if (!strcasecmp(p, "precision")) {
|
||||
if (sscanf(line, "%lf%n", &iface->precision, &n) != 1)
|
||||
break;
|
||||
} else if (!strcasecmp(p, "rxcomp")) {
|
||||
if (sscanf(line, "%lf%n", &iface->rx_comp, &n) != 1)
|
||||
break;
|
||||
} else if (!strcasecmp(p, "txcomp")) {
|
||||
if (sscanf(line, "%lf%n", &iface->tx_comp, &n) != 1)
|
||||
break;
|
||||
} else if (!strcasecmp(p, "nocrossts")) {
|
||||
n = 0;
|
||||
iface->nocrossts = 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*p)
|
||||
command_parse_error();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -1425,8 +1472,9 @@ CNF_GetDumpDir(void)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetLogMeasurements(void)
|
||||
CNF_GetLogMeasurements(int *raw)
|
||||
{
|
||||
*raw = raw_measurements;
|
||||
return do_log_measurements;
|
||||
}
|
||||
|
||||
@@ -1930,8 +1978,12 @@ CNF_GetInitStepThreshold(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
ARR_Instance
|
||||
CNF_GetHwTsInterfaces(void)
|
||||
int
|
||||
CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface)
|
||||
{
|
||||
return hwts_interfaces;
|
||||
if (index >= ARR_GetSize(hwts_interfaces))
|
||||
return 0;
|
||||
|
||||
*iface = (CNF_HwTsInterface *)ARR_GetElement(hwts_interfaces, index);
|
||||
return 1;
|
||||
}
|
||||
|
||||
14
conf.h
14
conf.h
@@ -29,7 +29,6 @@
|
||||
#define GOT_CONF_H
|
||||
|
||||
#include "addressing.h"
|
||||
#include "array.h"
|
||||
#include "reference.h"
|
||||
|
||||
extern void CNF_Initialise(int restarted);
|
||||
@@ -53,7 +52,7 @@ extern char *CNF_GetDriftFile(void);
|
||||
extern char *CNF_GetLogDir(void);
|
||||
extern char *CNF_GetDumpDir(void);
|
||||
extern int CNF_GetLogBanner(void);
|
||||
extern int CNF_GetLogMeasurements(void);
|
||||
extern int CNF_GetLogMeasurements(int *raw);
|
||||
extern int CNF_GetLogStatistics(void);
|
||||
extern int CNF_GetLogTracking(void);
|
||||
extern int CNF_GetLogRtc(void);
|
||||
@@ -120,6 +119,15 @@ extern char *CNF_GetHwclockFile(void);
|
||||
extern int CNF_GetInitSources(void);
|
||||
extern double CNF_GetInitStepThreshold(void);
|
||||
|
||||
extern ARR_Instance CNF_GetHwTsInterfaces(void);
|
||||
typedef struct {
|
||||
char *name;
|
||||
int minpoll;
|
||||
int nocrossts;
|
||||
double precision;
|
||||
double tx_comp;
|
||||
double rx_comp;
|
||||
} CNF_HwTsInterface;
|
||||
|
||||
extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
|
||||
|
||||
#endif /* GOT_CONF_H */
|
||||
|
||||
25
configure
vendored
25
configure
vendored
@@ -4,7 +4,8 @@
|
||||
# chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
#
|
||||
# Copyright (C) Richard P. Curnow 1997-2003
|
||||
# Copyright (C) Miroslav Lichvar 2009, 2012-2015
|
||||
# Copyright (C) Bryan Christianson 2016
|
||||
# Copyright (C) Miroslav Lichvar 2009, 2012-2016
|
||||
#
|
||||
# =======================================================================
|
||||
|
||||
@@ -219,6 +220,7 @@ try_lockmem=0
|
||||
feat_asyncdns=1
|
||||
feat_forcednsretry=1
|
||||
try_clock_gettime=1
|
||||
try_recvmmsg=1
|
||||
feat_timestamping=1
|
||||
try_timestamping=0
|
||||
feat_ntp_signd=0
|
||||
@@ -400,6 +402,9 @@ case $OPERATINGSYSTEM in
|
||||
echo "Configuring for " $SYSTEM
|
||||
;;
|
||||
FreeBSD)
|
||||
# recvmmsg() seems to be broken on FreeBSD 11.0 and it's just
|
||||
# a wrapper around recvmsg()
|
||||
try_recvmmsg=0
|
||||
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o"
|
||||
add_def FREEBSD
|
||||
if [ $feat_droproot = "1" ]; then
|
||||
@@ -629,14 +634,16 @@ fi
|
||||
RECVMMSG_CODE='
|
||||
struct mmsghdr hdr;
|
||||
return !recvmmsg(0, &hdr, 1, MSG_DONTWAIT, 0);'
|
||||
if test_code 'recvmmsg()' 'sys/socket.h' '' "$EXTRA_LIBS" "$RECVMMSG_CODE"; then
|
||||
add_def HAVE_RECVMMSG
|
||||
else
|
||||
if test_code 'recvmmsg() with _GNU_SOURCE' 'sys/socket.h' '-D_GNU_SOURCE' \
|
||||
"$EXTRA_LIBS" "$RECVMMSG_CODE"
|
||||
then
|
||||
add_def _GNU_SOURCE
|
||||
if [ $try_recvmmsg = "1" ]; then
|
||||
if test_code 'recvmmsg()' 'sys/socket.h' '' "$EXTRA_LIBS" "$RECVMMSG_CODE"; then
|
||||
add_def HAVE_RECVMMSG
|
||||
else
|
||||
if test_code 'recvmmsg() with _GNU_SOURCE' 'sys/socket.h' '-D_GNU_SOURCE' \
|
||||
"$EXTRA_LIBS" "$RECVMMSG_CODE"
|
||||
then
|
||||
add_def _GNU_SOURCE
|
||||
add_def HAVE_RECVMMSG
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -725,7 +732,7 @@ fi
|
||||
if [ $feat_refclock = "1" ] && [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
|
||||
grep '#define HAVE_CLOCK_GETTIME' config.h > /dev/null && \
|
||||
test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
|
||||
'ioctl(1, PTP_CLOCK_GETCAPS, 0);'
|
||||
'ioctl(1, PTP_CLOCK_GETCAPS + PTP_SYS_OFFSET, 0);'
|
||||
then
|
||||
add_def FEAT_PHC
|
||||
fi
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// This file is part of chrony
|
||||
//
|
||||
// Copyright (C) Richard P. Curnow 1997-2003
|
||||
// Copyright (C) Miroslav Lichvar 2009-2016
|
||||
// Copyright (C) Stephen Wadeley 2016
|
||||
// Copyright (C) Miroslav Lichvar 2009-2017
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -67,11 +68,15 @@ options:
|
||||
Although *chronyd* will trim the rate at which it samples the server during
|
||||
normal operation, the user might want to constrain the minimum polling interval.
|
||||
This is always defined as a power of 2, so *minpoll 5* would mean that the
|
||||
polling interval cannot drop below 32 seconds. The default is 6 (64 seconds).
|
||||
polling interval cannot drop below 32 seconds. The default is 6 (64 seconds),
|
||||
the minimum is -4 (1/16th of a second), and the maximum is 24 (6 months). Note
|
||||
that intervals shorter than 6 (64 seconds) should generally not be used with
|
||||
public servers on the Internet, because it might be considered abuse.
|
||||
*maxpoll* _poll_:::
|
||||
In a similar way, the user might want to constrain the maximum polling interval.
|
||||
Again this is specified as a power of 2, *maxpoll 9* indicates that the polling
|
||||
interval must stay at or below 512 seconds. The default is 10 (1024 seconds).
|
||||
interval must stay at or below 512 seconds. The default is 10 (1024 seconds),
|
||||
the minimum is 0 (1 second), and the maximum is 24 (6 months).
|
||||
*iburst*:::
|
||||
If this option is set, the interval between the first four polls will be 2
|
||||
seconds instead of _minpoll_. This is useful to quickly get the first update of
|
||||
@@ -105,12 +110,13 @@ If the user knows that round trip delays above a certain level should cause the
|
||||
measurement to be ignored, this level can be defined with the *maxdelay*
|
||||
option. For example, *maxdelay 0.3* would indicate that measurements with a
|
||||
round-trip delay of 0.3 seconds or more should be ignored. The default value is
|
||||
3 seconds.
|
||||
3 seconds and the maximum value is 1000 seconds.
|
||||
*maxdelayratio* _ratio_:::
|
||||
This option is similar to the maxdelay option above. *chronyd* keeps a record
|
||||
of the minimum round-trip delay amongst the previous measurements that it has
|
||||
buffered. If a measurement has a round trip delay that is greater than the
|
||||
maxdelayratio times the minimum delay, it will be rejected.
|
||||
maxdelayratio times the minimum delay, it will be rejected. This option works
|
||||
only in the *server* directive when not in the interleaved mode.
|
||||
*maxdelaydevratio* _ratio_:::
|
||||
If a measurement has a ratio of the increase in the round-trip delay from the
|
||||
minimum delay amongst the previous measurements to the standard deviation of
|
||||
@@ -159,9 +165,8 @@ synchronisation only if they agree with the trusted and required source.
|
||||
*xleave*:::
|
||||
This option enables an interleaved mode which allows the server or the peer to
|
||||
send transmit timestamps captured after the actual transmission (e.g. when the
|
||||
server or the peer is running *chronyd* with HW timestamping enabled by the
|
||||
<<hwtimestamp,*hwtimestamp*>> directive). This can significantly improve the
|
||||
accuracy of the measurements.
|
||||
server or the peer is running *chronyd* with software (kernel) or hardware
|
||||
timestamping). This can significantly improve the accuracy of the measurements.
|
||||
+
|
||||
The interleaved mode is compatible with servers that support only the basic
|
||||
mode, but peers must both support and have enabled the interleaved mode,
|
||||
@@ -171,9 +176,12 @@ the interleaved mode requires the servers to keep some state for each client
|
||||
and the state might be dropped when there are too many clients (e.g.
|
||||
<<clientloglimit,*clientloglimit*>> is too small), or it might be overwritten
|
||||
by other clients that have the same IP address (e.g. computers behind NAT or
|
||||
someone sending requests with a spoofed source address). The *presend* option
|
||||
can be used to shorten the interval in which the server has to keep the state
|
||||
for this computer and be able to respond in the interleaved mode.
|
||||
someone sending requests with a spoofed source address).
|
||||
+
|
||||
With longer polling intervals, it is recommended to combine the *xleave* option
|
||||
with the *presend* option in order to shorten the interval in which the server
|
||||
has to keep the state to be able to respond in the interleaved mode. The
|
||||
shorter interval also improves accuracy of the measured offset and delay.
|
||||
*polltarget* _target_:::
|
||||
Target number of measurements to use for the regression algorithm which
|
||||
*chronyd* will try to maintain by adjusting the polling interval between
|
||||
@@ -397,9 +405,10 @@ refclock SOCK /var/run/chrony.ttyS0.sock
|
||||
*PHC*:::
|
||||
PTP hardware clock (PHC) driver. The parameter is the path to the device of
|
||||
the PTP clock, which for example can be synchronised by *ptp4l* from
|
||||
http://linuxptp.sourceforge.net[*linuxptp*]. PTP clocks are typically kept in
|
||||
TAI instead of UTC, so the *offset* option should be used to compensate for the
|
||||
current UTC-TAI offset. For example:
|
||||
http://linuxptp.sourceforge.net[*linuxptp*]. String *:nocrossts* can be
|
||||
appended to the path to disable use of precise cross timestamping. PTP clocks
|
||||
are typically kept in TAI instead of UTC, so the *offset* option should be used
|
||||
to compensate for the current UTC-TAI offset. For example:
|
||||
+
|
||||
----
|
||||
refclock PHC /dev/ptp0 poll 3 dpoll -2 offset -36
|
||||
@@ -993,7 +1002,7 @@ both a client of its servers, and a server to other clients.
|
||||
Examples of the use of the directive are as follows:
|
||||
+
|
||||
----
|
||||
allow foo.example.net
|
||||
allow 1.2.3.4
|
||||
allow 1.2
|
||||
allow 3.4.5
|
||||
allow 6.7.8/22
|
||||
@@ -1004,7 +1013,8 @@ allow ::/0
|
||||
allow
|
||||
----
|
||||
+
|
||||
The first directive allows the named node to be an NTP client of this computer.
|
||||
The first directive allows a node with IPv4 address _1.2.3.4_ to be an NTP
|
||||
client of this computer.
|
||||
The second directive allows any node with an IPv4 address of the form _1.2.x.y_
|
||||
(with _x_ and _y_ arbitrary) to be an NTP client of this computer. Likewise,
|
||||
the third directive allows any node with an IPv4 address of the form _3.4.5.x_
|
||||
@@ -1045,6 +1055,10 @@ Within a configuration file this capability is probably rather moot; however,
|
||||
it is of greater use for reconfiguration at run-time via *chronyc* with the
|
||||
<<chronyc.adoc#allow,*allow all*>> command.
|
||||
+
|
||||
The directive allows a hostname to be specified instead of an IP address, but
|
||||
the name must be resolvable when *chronyd* is started (i.e. *chronyd* needs
|
||||
to be started when the network is already up and DNS is working).
|
||||
+
|
||||
Note, if the <<initstepslew,*initstepslew*>> directive is used in the
|
||||
configuration file, each of the computers listed in that directive must allow
|
||||
client access by this computer for it to work.
|
||||
@@ -1237,7 +1251,10 @@ in any order):
|
||||
*interval*:::
|
||||
This option sets the minimum interval between responses. It is defined as a
|
||||
power of 2 in seconds. The default value is 3 (8 seconds). The minimum value
|
||||
is -4 and the maximum value is 12.
|
||||
is -19 (524288 packets per second) and the maximum value is 12 (one packet per
|
||||
4096 seconds). Note that with values below -4 the rate limiting is coarse
|
||||
(responses are allowed in bursts, even if the interval between them is shorter
|
||||
than the specified interval).
|
||||
*burst*:::
|
||||
This option sets the maximum number of responses that can be sent in a burst,
|
||||
temporarily exceeding the limit specified by the *interval* option. This is
|
||||
@@ -1249,20 +1266,20 @@ This option sets the rate at which responses are randomly allowed even if the
|
||||
limits specified by the *interval* and *burst* options are exceeded. This is
|
||||
necessary to prevent an attacker who is sending requests with a spoofed
|
||||
source address from completely blocking responses to that address. The leak
|
||||
rate is defined as a power of 1/2 and it is 3 by default, i.e. on average at
|
||||
least every eighth request has a response. The minimum value is 1 and the
|
||||
rate is defined as a power of 1/2 and it is 2 by default, i.e. on average at
|
||||
least every fourth request has a response. The minimum value is 1 and the
|
||||
maximum value is 4.
|
||||
::
|
||||
+
|
||||
An example use of the directive is:
|
||||
+
|
||||
----
|
||||
ratelimit interval 4 burst 4
|
||||
ratelimit interval 1 burst 16
|
||||
----
|
||||
+
|
||||
This would reduce the response rate for IP addresses that send packets on
|
||||
average more frequently than once per 16 seconds or send packets in bursts
|
||||
of more than 4 packets.
|
||||
This would reduce the response rate for IP addresses sending packets on average
|
||||
more than once per 2 seconds, or sending packets in bursts of more than 16
|
||||
packets, by up to 75% (with default *leak* of 2).
|
||||
|
||||
[[smoothtime]]*smoothtime* _max-freq_ _max-wander_ [*leaponly*]::
|
||||
The *smoothtime* directive can be used to enable smoothing of the time that
|
||||
@@ -1391,8 +1408,8 @@ need to be run with the *-p 257* switch to inter-operate correctly.)
|
||||
[[cmdratelimit]]*cmdratelimit* [_option_]...::
|
||||
This directive enables response rate limiting for command packets. It is
|
||||
similar to the <<ratelimit,*ratelimit*>> directive, except responses to
|
||||
localhost are never limited and the default interval is 1 (2 seconds), the default
|
||||
burst is 16, and the default leak rate is 2.
|
||||
localhost are never limited and the default interval is -4 (16 packets per
|
||||
second).
|
||||
+
|
||||
An example of the use of the directive is:
|
||||
+
|
||||
@@ -1501,10 +1518,12 @@ The log files are written to the directory specified by the <<logdir,*logdir*>>
|
||||
directive. A banner is periodically written to the files to indicate the
|
||||
meanings of the columns.
|
||||
+
|
||||
*measurements*:::
|
||||
*rawmeasurements*:::
|
||||
This option logs the raw NTP measurements and related information to a file
|
||||
called _measurements.log_. An example line (which actually appears as a single
|
||||
line in the file) from the log file is shown below.
|
||||
called _measurements.log_. An entry is made for each packet received from the
|
||||
source. This can be useful when debugging a problem. An example line (which
|
||||
actually appears as a single line in the file) from the log file is shown
|
||||
below.
|
||||
+
|
||||
----
|
||||
2016-11-09 05:40:50 203.0.113.15 N 2 111 111 1111 10 10 1.0 \
|
||||
@@ -1546,6 +1565,12 @@ from the example line above):
|
||||
. Source of the local receive timestamp
|
||||
(_D_=daemon, _K_=kernel, _H_=hardware). [K]
|
||||
+
|
||||
*measurements*:::
|
||||
This option is identical to the *rawmeasurements* option, except it logs only
|
||||
valid measurements from synchronised sources, i.e. measurements which passed
|
||||
the RFC 5905 tests 1 through 7. This can be useful for producing graphs of the
|
||||
source's performance.
|
||||
+
|
||||
*statistics*:::
|
||||
This option logs information about the regression processing to a file called
|
||||
_statistics.log_. An example line (which actually appears as a single line in
|
||||
@@ -1772,17 +1797,18 @@ sendmail binary.
|
||||
|
||||
=== Miscellaneous
|
||||
|
||||
[[hwtimestamp]]*hwtimestamp* _interface_::
|
||||
[[hwtimestamp]]*hwtimestamp* _interface_ [_option_]...::
|
||||
This directive enables hardware timestamping of NTP packets sent to and
|
||||
received from the specified network interface. The network interface controller
|
||||
(NIC) uses its own clock to accurately timestamp the actual transmissions and
|
||||
receptions, avoiding processing and queueing delays in the kernel, network
|
||||
driver, and hardware. This can significantly improve the accuracy of the
|
||||
timestamps and the measured offset, which is used for synchronisation of the
|
||||
system clock. In order to get best results, it is necessary to enable HW
|
||||
timestamping on both sides receiving and sending the packets (i.e. server and
|
||||
client, or both peers), and also enable the interleaved mode with the *xleave*
|
||||
option in the <<server,*server*>> or the <<peer,*peer*>> directive.
|
||||
system clock. In order to get the best results, both sides receiving and
|
||||
sending NTP packets (i.e. server and client, or two peers) need to use HW
|
||||
timestamping. If the server or peer supports the interleaved mode, it needs to
|
||||
be enabled by the *xleave* option in the <<server,*server*>> or the
|
||||
<<peer,*peer*>> directive.
|
||||
+
|
||||
This directive is supported on Linux 3.19 and newer. The NIC must support HW
|
||||
timestamping, which can be verified with the *ethtool -T* command. The list of
|
||||
@@ -1799,10 +1825,40 @@ interfaces. The timestamping used in measurements is indicated in the
|
||||
_measurements.log_ file if enabled by the <<log,*log measurements*>> directive,
|
||||
and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in *chronyc*.
|
||||
+
|
||||
An example of the directive is:
|
||||
If the specified interface is _*_, *chronyd* will try to enable HW timestamping
|
||||
on all available interfaces.
|
||||
+
|
||||
The *hwtimestamp* directive has the following options:
|
||||
+
|
||||
*minpoll* _poll_:::
|
||||
This option specifies the minimum interval between readings of the NIC clock.
|
||||
It's defined as a power of two. It should correspond to the minimum polling
|
||||
interval of all NTP sources and the minimum expected polling interval of NTP
|
||||
clients. The default value is 0 (1 second) and the minimum value is -6 (1/64th
|
||||
of a second).
|
||||
*precision* _precision_:::
|
||||
This option specifies the assumed precision of reading of the NIC clock. The
|
||||
default value is 100e-9 (100 nanoseconds).
|
||||
*txcomp* _compensation_:::
|
||||
This option specifies the difference in seconds between the actual transmission
|
||||
time at the physical layer and the reported transmit timestamp. This value will
|
||||
be added to transmit timestamps obtained from the NIC. The default value is 0.
|
||||
*rxcomp* _compensation_:::
|
||||
This option specifies the difference in seconds between the reported receive
|
||||
timestamp and the actual reception time at the physical layer. This value will
|
||||
be subtracted from receive timestamps obtained from the NIC. The default value
|
||||
is 0.
|
||||
*nocrossts*:::
|
||||
Some hardware can precisely cross timestamp the NIC clock with the system
|
||||
clock. This option disables the use of the cross timestamping.
|
||||
::
|
||||
+
|
||||
Examples of the directive are:
|
||||
+
|
||||
----
|
||||
hwtimestamp eth0
|
||||
hwtimestamp eth1 txcomp 300e-9 rxcomp 645e-9
|
||||
hwtimestamp *
|
||||
----
|
||||
|
||||
[[include]]*include* _pattern_::
|
||||
@@ -2211,24 +2267,34 @@ information to be saved.
|
||||
*chronyd* can be configured to operate as a public NTP server, e.g. to join the
|
||||
http://www.pool.ntp.org/en/join.html[pool.ntp.org] project. The configuration
|
||||
is similar to the NTP client with permanent connection, except it needs to
|
||||
allow client access from all addresses. It is recommended to handpick at least
|
||||
few good servers, and possibly combine them with a random selection of other
|
||||
servers in the pool. Rate limiting can be enabled to not waste too much
|
||||
bandwidth on misconfigured and broken NTP clients. The *-r* option with the
|
||||
*dumpdir* directive shortens the time for which *chronyd* will not serve time
|
||||
to its clients when it needs to be restarted for any reason.
|
||||
allow client access from all addresses. It is recommended to find at least four
|
||||
good servers (e.g. from the pool, or on the NTP homepage). If the server has a
|
||||
hardware reference clock (e.g. a GPS receiver), it can be specified by the
|
||||
<<refclock,*refclock*>> directive.
|
||||
|
||||
The configuration file might be:
|
||||
The amount of memory used for logging client accesses can be increased in order
|
||||
to enable clients to use the interleaved mode even when the server has a large
|
||||
number of clients, and better support rate limiting if it is enabled by the
|
||||
<<ratelimit,*ratelimit*>> directive. The system timezone database, if it is
|
||||
kept up to date and includes the *right/UTC* timezone, can be used as a
|
||||
reliable source to determine when a leap second will be applied to UTC. The
|
||||
*-r* option with the <<dumpdir,*dumpdir*>> directive shortens the time in which
|
||||
*chronyd* will not be able to serve time to its clients when it needs to be
|
||||
restarted (e.g. after upgrading to a newer version, or a change in the
|
||||
configuration).
|
||||
|
||||
The configuration file could look like:
|
||||
|
||||
----
|
||||
server foo.example.net iburst
|
||||
server bar.example.net iburst
|
||||
server baz.example.net iburst
|
||||
pool pool.ntp.org iburst
|
||||
server qux.example.net iburst
|
||||
makestep 1.0 3
|
||||
rtcsync
|
||||
allow
|
||||
ratelimit interval 2 burst 10
|
||||
clientloglimit 100000000
|
||||
leapsectz right/UTC
|
||||
driftfile @CHRONYVARDIR@/drift
|
||||
dumpdir @CHRONYRUNDIR@
|
||||
dumponexit
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// This file is part of chrony
|
||||
//
|
||||
// Copyright (C) Richard P. Curnow 1997-2003
|
||||
// Copyright (C) Stephen Wadeley 2016
|
||||
// Copyright (C) Miroslav Lichvar 2009-2016
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
@@ -129,15 +130,15 @@ performance. An example of the output is shown below.
|
||||
----
|
||||
Reference ID : CB00710F (foo.example.net)
|
||||
Stratum : 3
|
||||
Ref time (UTC) : Fri Feb 3 15:00:29 2012
|
||||
System time : 0.000001501 seconds slow of NTP time
|
||||
Last offset : -0.000001632 seconds
|
||||
RMS offset : 0.000002360 seconds
|
||||
Frequency : 331.898 ppm fast
|
||||
Residual freq : 0.004 ppm
|
||||
Skew : 0.154 ppm
|
||||
Root delay : 0.373169 seconds
|
||||
Root dispersion : 0.024780 seconds
|
||||
Ref time (UTC) : Fri Jan 27 09:49:17 2017
|
||||
System time : 0.000006523 seconds slow of NTP time
|
||||
Last offset : -0.000006747 seconds
|
||||
RMS offset : 0.000035822 seconds
|
||||
Frequency : 3.225 ppm slow
|
||||
Residual freq : -0.000 ppm
|
||||
Skew : 0.129 ppm
|
||||
Root delay : 0.013639022 seconds
|
||||
Root dispersion : 0.001100737 seconds
|
||||
Update interval : 64.2 seconds
|
||||
Leap status : Normal
|
||||
----
|
||||
@@ -186,9 +187,6 @@ The '`frequency`' is the rate by which the system's clock would be wrong if
|
||||
For example, a value of 1 ppm would mean that when the system's clock thinks it
|
||||
has advanced 1 second, it has actually advanced by 1.000001 seconds relative to
|
||||
true time.
|
||||
+
|
||||
As you can see in the example, the clock in the computer is not a very
|
||||
good one; it would gain about 30 seconds per day if it was not corrected!
|
||||
*Residual freq*:::
|
||||
This shows the '`residual frequency`' for the currently selected reference
|
||||
source. This reflects any difference between what the measurements from the
|
||||
@@ -441,10 +439,10 @@ the offline state.
|
||||
the name of the server or peer was not resolved to an address yet; this source is
|
||||
not visible in the *sources* and *sourcestats* reports.
|
||||
|
||||
[[ntpdata]]*ntpdata* _address_::
|
||||
[[ntpdata]]*ntpdata* [_address_]::
|
||||
The *ntpdata* command displays the last valid measurement and other
|
||||
NTP-specific information about the NTP source. An example of the output is
|
||||
shown below.
|
||||
NTP-specific information about the specified NTP source, or all NTP sources if
|
||||
no address was specified. An example of the output is shown below.
|
||||
+
|
||||
----
|
||||
Remote address : 203.0.113.15 (CB00710F)
|
||||
@@ -454,11 +452,11 @@ Leap status : Normal
|
||||
Version : 4
|
||||
Mode : Server
|
||||
Stratum : 1
|
||||
Poll : 10
|
||||
Precision : 0.000000060 seconds
|
||||
Poll interval : 10 (1024 seconds)
|
||||
Precision : -24 (0.000000060 seconds)
|
||||
Root delay : 0.000015 seconds
|
||||
Root dispersion : 0.000015 seconds
|
||||
Reference ID : 50505331
|
||||
Reference ID : 47505300 (GPS)
|
||||
Reference time : Fri Nov 25 15:22:12 2016
|
||||
Offset : -0.000060878 seconds
|
||||
Peer delay : 0.000175634 seconds
|
||||
@@ -489,7 +487,7 @@ reference ID.
|
||||
*Version*:::
|
||||
*Mode*:::
|
||||
*Stratum*:::
|
||||
*Poll*:::
|
||||
*Poll interval*:::
|
||||
*Precision*:::
|
||||
*Root delay*:::
|
||||
*Root dispersion*:::
|
||||
@@ -1132,6 +1130,10 @@ directory into which the dump files will be written. This can only be
|
||||
done in the configuration file with the <<chrony.conf.adoc#dumpdir,*dumpdir*>>
|
||||
directive.
|
||||
|
||||
[[rekey]]*rekey*::
|
||||
The *rekey* command causes *chronyd* to re-read the key file specified in the
|
||||
configuration file by the <<chrony.conf.adoc#keyfile,*keyfile*>> directive.
|
||||
|
||||
=== Client commands
|
||||
|
||||
[[dns]]*dns* _option_::
|
||||
|
||||
53
doc/faq.adoc
53
doc/faq.adoc
@@ -79,7 +79,7 @@ rtcsync
|
||||
|
||||
You need to add an `allow` directive to the _chrony.conf_ file in order to open
|
||||
the NTP port and allow `chronyd` to reply to client requests. `allow` with no
|
||||
specified subnet allows all IPv4 and IPv6 addresses.
|
||||
specified subnet allows access from all IPv4 and IPv6 addresses.
|
||||
|
||||
=== I have several computers on a LAN. Should be all clients of an external server?
|
||||
|
||||
@@ -97,7 +97,7 @@ _chrony.conf_ file. This configuration will be better because
|
||||
No. Starting from version 1.25, `chronyd` will keep trying to resolve
|
||||
the names specified by the `server`, `pool`, and `peer` directives in an
|
||||
increasing interval until it succeeds. The `online` command can be issued from
|
||||
`chronyc` to try to resolve them immediately.
|
||||
`chronyc` to force `chronyd` to try to resolve the names immediately.
|
||||
|
||||
=== How can I make `chronyd` more secure?
|
||||
|
||||
@@ -161,7 +161,7 @@ The first three options set the minimum and maximum allowed polling interval,
|
||||
and how should be the actual interval adjusted in the specified range. Their
|
||||
default values are 6 (64 seconds) for `minpoll`, 10 (1024 seconds) for
|
||||
`maxpoll` and 8 (samples) for `polltarget`. The default values should be used
|
||||
for general servers on the Internet. With your own NTP servers or if have
|
||||
for general servers on the Internet. With your own NTP servers, or if you have
|
||||
permission to poll some servers more frequently, setting these options for
|
||||
shorter polling intervals may significantly improve the accuracy of the system
|
||||
clock.
|
||||
@@ -195,15 +195,27 @@ server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
|
||||
----
|
||||
|
||||
If your server supports the interleaved mode, the `xleave` option should be
|
||||
added to the `server` directive in order to receive server's more accurate
|
||||
hardware or kernel transmit timestamps. When combined with local hardware
|
||||
timestamping, a sub-microsecond accuracy may be possible. An example could be
|
||||
added to the `server` directive in order to allow the server to send the
|
||||
client more accurate hardware or kernel transmit timestamps. When combined with
|
||||
local hardware timestamping, sub-microsecond accuracy may be possible. An
|
||||
example could be
|
||||
|
||||
----
|
||||
server ntp.local minpoll 2 maxpoll 2 xleave
|
||||
hwtimestamp eth0
|
||||
----
|
||||
|
||||
=== Does `chronyd` have an ntpdate mode?
|
||||
|
||||
Yes. With the `-q` option `chronyd` will set the system clock once and exit.
|
||||
With the `-Q` option it will print the measured offset without setting the
|
||||
clock. If you don't want to use a configuration file, NTP servers can be
|
||||
specified on the command line. For example:
|
||||
|
||||
----
|
||||
# chronyd -q 'pool pool.ntp.org iburst'
|
||||
----
|
||||
|
||||
=== What happened to the `commandkey` and `generatecommandkey` directives?
|
||||
|
||||
They were removed in version 2.2. Authentication is no longer supported in the
|
||||
@@ -242,8 +254,17 @@ MS Name/IP address Stratum Poll Reach LastRx Last sample
|
||||
=== Are NTP servers specified with the `offline` option?
|
||||
|
||||
Check that you're using ``chronyc``'s `online` and `offline` commands
|
||||
appropriately. Again, check in _measurements.log_ to see if you're getting any
|
||||
data back from the server.
|
||||
appropriately. The `activity` command prints the number of sources that are
|
||||
currently online and offline. For example:
|
||||
|
||||
----
|
||||
200 OK
|
||||
3 sources online
|
||||
0 sources offline
|
||||
0 sources doing burst (return to online)
|
||||
0 sources doing burst (return to offline)
|
||||
0 sources with unknown address
|
||||
----
|
||||
|
||||
=== Is `chronyd` allowed to step the system clock?
|
||||
|
||||
@@ -396,15 +417,15 @@ option for all time sources in the _chrony.conf_ file.
|
||||
|
||||
=== What happens if the network connection is dropped without using ``chronyc``'s `offline` command first?
|
||||
|
||||
`chronyd` will keep trying to access the server(s) that it thinks are online.
|
||||
When the network is connected again, it will take some time (on average half of
|
||||
the maximum polling interval) before new measurements are made and the clock is
|
||||
corrected. If the servers were set to offline and the `online` command was
|
||||
issued when the network was connected, `chronyd` would make new measurements
|
||||
immediately.
|
||||
`chronyd` will keep trying to access the sources that it thinks are online, and
|
||||
it will take longer before new measurements are actually made and the clock is
|
||||
corrected when the network is connected again. If the sources were set to
|
||||
offline, `chronyd` would make new measurements immediately after issuing the
|
||||
`online` command.
|
||||
|
||||
The `auto_offline` option to the `server` entry in the _chrony.conf_ file may
|
||||
be useful to switch the servers to the offline state automatically.
|
||||
Unless the network connection lasts only few minutes (less than the maximum
|
||||
polling interval), the delay is usually not a problem, and it may be acceptable
|
||||
to keep all sources online all the time.
|
||||
|
||||
== Operating systems
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
[Unit]
|
||||
Description=Wait for chrony to synchronize system clock
|
||||
Documentation=man:chronyc(1)
|
||||
After=chronyd.service
|
||||
Requires=chronyd.service
|
||||
Before=time-sync.target
|
||||
@@ -9,7 +10,7 @@ Wants=time-sync.target
|
||||
Type=oneshot
|
||||
# Wait up to ~10 minutes for chronyd to synchronize and the remaining
|
||||
# clock correction to be less than 0.1 seconds
|
||||
ExecStart=/usr/bin/chronyc waitsync 600 0.1 0.0 1
|
||||
ExecStart=/usr/bin/chronyc -h 127.0.0.1,::1 waitsync 600 0.1 0.0 1
|
||||
RemainAfterExit=yes
|
||||
StandardOutput=null
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ pool pool.ntp.org iburst
|
||||
# Record the rate at which the system clock gains/losses time.
|
||||
driftfile /var/lib/chrony/drift
|
||||
|
||||
# In first three updates step the system clock instead of slew
|
||||
# if the adjustment is larger than 1 second.
|
||||
# Allow the system clock to be stepped in the first three updates
|
||||
# if its offset is larger than 1 second.
|
||||
makestep 1.0 3
|
||||
|
||||
# Enable kernel synchronization of the real-time clock (RTC).
|
||||
|
||||
@@ -5,17 +5,24 @@ pool pool.ntp.org iburst
|
||||
# Record the rate at which the system clock gains/losses time.
|
||||
driftfile /var/lib/chrony/drift
|
||||
|
||||
# In first three updates step the system clock instead of slew
|
||||
# if the adjustment is larger than 1 second.
|
||||
# Allow the system clock to be stepped in the first three updates
|
||||
# if its offset is larger than 1 second.
|
||||
makestep 1.0 3
|
||||
|
||||
# Enable kernel synchronization of the real-time clock (RTC).
|
||||
rtcsync
|
||||
|
||||
# Allow NTP client access from local network.
|
||||
#allow 192.168/16
|
||||
# Enable hardware timestamping on all interfaces that support it.
|
||||
#hwtimestamp *
|
||||
|
||||
# Serve time even if not synchronized to any NTP server.
|
||||
# Increase the minimum number of selectable sources required to adjust
|
||||
# the system clock.
|
||||
#minsources 2
|
||||
|
||||
# Allow NTP client access from local network.
|
||||
#allow 192.168.0.0/16
|
||||
|
||||
# Serve time even if not synchronized to a time source.
|
||||
#local stratum 10
|
||||
|
||||
# Specify file containing keys for NTP authentication.
|
||||
|
||||
@@ -33,42 +33,30 @@
|
||||
|
||||
! pool pool.ntp.org iburst
|
||||
|
||||
# However, for dial-up use you probably want these instead. The word
|
||||
# 'offline' means that the server is not visible at boot time. Use
|
||||
# chronyc's 'online' command to tell chronyd that these servers have
|
||||
# become visible after you go on-line.
|
||||
|
||||
! server foo.example.net offline
|
||||
! server bar.example.net offline
|
||||
! server baz.example.net offline
|
||||
|
||||
! pool pool.ntp.org offline
|
||||
|
||||
# You may want to specify NTP 'peers' instead. If you run a network
|
||||
# with a lot of computers and want several computers running chrony to
|
||||
# have the 'front-line' interface to the public NTP servers, you can
|
||||
# 'peer' these machines together to increase robustness.
|
||||
|
||||
! peer foo.example.net
|
||||
|
||||
# There are other options to the 'server' and 'peer' directives that you
|
||||
# might want to use. For example, you can ignore measurements whose
|
||||
# round-trip-time is too large (indicating that the measurement is
|
||||
# probably useless, because you don't know which way the measurement
|
||||
# message got held up.) Consult the full documentation for details.
|
||||
|
||||
#######################################################################
|
||||
### AVOIDING POTENTIALLY BOGUS CHANGES TO YOUR CLOCK
|
||||
#
|
||||
# To avoid changes being made to your computer's gain/loss compensation
|
||||
# when the measurement history is too erratic, you might want to enable
|
||||
# one of the following lines. The first seems good for dial-up (or
|
||||
# other high-latency connections like slow leased lines), the second
|
||||
# seems OK for a LAN environment.
|
||||
# one of the following lines. The first seems good with servers on the
|
||||
# Internet, the second seems OK for a LAN environment.
|
||||
|
||||
! maxupdateskew 100
|
||||
! maxupdateskew 5
|
||||
|
||||
# If you want to increase the minimum number of selectable sources
|
||||
# required to update the system clock in order to make the
|
||||
# synchronisation more reliable, uncomment (and edit) the following
|
||||
# line.
|
||||
|
||||
! minsources 2
|
||||
|
||||
# If your computer has a good stable clock (e.g. it is not a virtual
|
||||
# machine), you might also want to reduce the maximum assumed drift
|
||||
# (frequency error) of the clock (the value is specified in ppm).
|
||||
|
||||
! maxdrift 100
|
||||
|
||||
#######################################################################
|
||||
### FILENAMES ETC
|
||||
# Chrony likes to keep information about your computer's clock in files.
|
||||
@@ -181,13 +169,12 @@ driftfile /var/lib/chrony/drift
|
||||
# machine accesses it. The information can be accessed by the 'clients'
|
||||
# command of chronyc. You can disable this facility by uncommenting the
|
||||
# following line. This will save a bit of memory if you have many
|
||||
# clients.
|
||||
# clients and it will also disable support for the interleaved mode.
|
||||
|
||||
! noclientlog
|
||||
|
||||
# The clientlog size is limited to 512KB by default. If you have many
|
||||
# clients, especially in many different subnets, you might want to
|
||||
# increase the limit.
|
||||
# clients, you might want to increase the limit.
|
||||
|
||||
! clientloglimit 4194304
|
||||
|
||||
@@ -196,7 +183,7 @@ driftfile /var/lib/chrony/drift
|
||||
# clients that are sending requests too frequently, uncomment and edit
|
||||
# the following line.
|
||||
|
||||
! limitrate interval 3 burst 8
|
||||
! ratelimit interval 3 burst 8
|
||||
|
||||
#######################################################################
|
||||
### REPORTING BIG CLOCK CHANGES
|
||||
@@ -243,7 +230,17 @@ driftfile /var/lib/chrony/drift
|
||||
# Rate limiting can be enabled also for command packets. (Note,
|
||||
# commands from localhost are never limited.)
|
||||
|
||||
! cmdratelimit interval 1 burst 16
|
||||
! cmdratelimit interval -4 burst 16
|
||||
|
||||
#######################################################################
|
||||
### HARDWARE TIMESTAMPING
|
||||
# On Linux, if the network interface controller and its driver support
|
||||
# hardware timestamping, it can significantly improve the accuracy of
|
||||
# synchronisation. It can be enabled on specified interfaces only, or it
|
||||
# can be enabled on all interfaces that support it.
|
||||
|
||||
! hwtimestamp eth0
|
||||
! hwtimestamp *
|
||||
|
||||
#######################################################################
|
||||
### REAL TIME CLOCK
|
||||
@@ -274,6 +271,12 @@ driftfile /var/lib/chrony/drift
|
||||
|
||||
! rtcdevice /dev/misc/rtc
|
||||
|
||||
# Alternatively, if not using the -s option, this directive can be used
|
||||
# to enable a mode in which the RTC is periodically set to the system
|
||||
# time, with no tracking of its drift.
|
||||
|
||||
! rtcsync
|
||||
|
||||
#######################################################################
|
||||
### REAL TIME SCHEDULER
|
||||
# This directive tells chronyd to use the real-time FIFO scheduler with the
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
[Unit]
|
||||
Description=NTP client/server
|
||||
Documentation=man:chronyd(8) man:chrony.conf(5)
|
||||
After=ntpdate.service sntp.service ntpd.service
|
||||
Conflicts=ntpd.service systemd-timesyncd.service
|
||||
ConditionCapability=CAP_SYS_TIME
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
PIDFile=/var/run/chronyd.pid
|
||||
EnvironmentFile=-/etc/sysconfig/chronyd
|
||||
ExecStart=/usr/sbin/chronyd $OPTIONS
|
||||
PrivateTmp=yes
|
||||
ProtectHome=yes
|
||||
ProtectSystem=full
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
21
hwclock.c
21
hwclock.c
@@ -39,9 +39,6 @@
|
||||
/* Maximum number of samples per clock */
|
||||
#define MAX_SAMPLES 16
|
||||
|
||||
/* Minimum interval between samples (in seconds) */
|
||||
#define MIN_SAMPLE_SEPARATION 1.0
|
||||
|
||||
struct HCL_Instance_Record {
|
||||
/* HW and local reference timestamp */
|
||||
struct timespec hw_ref;
|
||||
@@ -55,6 +52,12 @@ struct HCL_Instance_Record {
|
||||
/* Number of samples */
|
||||
int n_samples;
|
||||
|
||||
/* Maximum error of the last sample */
|
||||
double last_err;
|
||||
|
||||
/* Minimum interval between samples */
|
||||
double min_separation;
|
||||
|
||||
/* Flag indicating the offset and frequency values are valid */
|
||||
int valid_coefs;
|
||||
|
||||
@@ -83,7 +86,7 @@ handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
|
||||
/* ================================================== */
|
||||
|
||||
HCL_Instance
|
||||
HCL_CreateInstance(void)
|
||||
HCL_CreateInstance(double min_separation)
|
||||
{
|
||||
HCL_Instance clock;
|
||||
|
||||
@@ -92,6 +95,7 @@ HCL_CreateInstance(void)
|
||||
clock->y_data[MAX_SAMPLES - 1] = 0.0;
|
||||
clock->n_samples = 0;
|
||||
clock->valid_coefs = 0;
|
||||
clock->min_separation = min_separation;
|
||||
|
||||
LCL_AddParameterChangeHandler(handle_slew, clock);
|
||||
|
||||
@@ -112,7 +116,7 @@ int
|
||||
HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now)
|
||||
{
|
||||
if (!clock->n_samples ||
|
||||
fabs(UTI_DiffTimespecsToDouble(now, &clock->local_ref)) >= MIN_SAMPLE_SEPARATION)
|
||||
fabs(UTI_DiffTimespecsToDouble(now, &clock->local_ref)) >= clock->min_separation)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -137,7 +141,7 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
|
||||
hw_delta = UTI_DiffTimespecsToDouble(hw_ts, &clock->hw_ref);
|
||||
local_delta = UTI_DiffTimespecsToDouble(local_ts, &clock->local_ref) / local_freq;
|
||||
|
||||
if (hw_delta <= 0.0 || local_delta < MIN_SAMPLE_SEPARATION / 2.0) {
|
||||
if (hw_delta <= 0.0 || local_delta < clock->min_separation / 2.0) {
|
||||
clock->n_samples = 0;
|
||||
DEBUG_LOG(LOGF_HwClocks, "HW clock reset interval=%f", local_delta);
|
||||
}
|
||||
@@ -151,6 +155,7 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
|
||||
clock->n_samples++;
|
||||
clock->hw_ref = *hw_ts;
|
||||
clock->local_ref = *local_ts;
|
||||
clock->last_err = err;
|
||||
|
||||
/* Get new coefficients */
|
||||
clock->valid_coefs =
|
||||
@@ -196,9 +201,9 @@ HCL_CookTime(HCL_Instance clock, struct timespec *raw, struct timespec *cooked,
|
||||
offset = clock->offset + elapsed / clock->frequency;
|
||||
UTI_AddDoubleToTimespec(&clock->local_ref, offset, cooked);
|
||||
|
||||
/* Estimation of the error is not implemented yet */
|
||||
/* Fow now, just return the error of the last sample */
|
||||
if (err)
|
||||
*err = 0.0;
|
||||
*err = clock->last_err;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
typedef struct HCL_Instance_Record *HCL_Instance;
|
||||
|
||||
/* Create a new HW clock instance */
|
||||
extern HCL_Instance HCL_CreateInstance(void);
|
||||
extern HCL_Instance HCL_CreateInstance(double min_separation);
|
||||
|
||||
/* Destroy a HW clock instance */
|
||||
extern void HCL_DestroyInstance(HCL_Instance clock);
|
||||
|
||||
2
local.c
2
local.c
@@ -144,6 +144,8 @@ calculate_sys_precision(void)
|
||||
best *= 2;
|
||||
}
|
||||
|
||||
assert(precision_log >= -30);
|
||||
|
||||
DEBUG_LOG(LOGF_Local, "Clock precision %.9f (%d)", precision_quantum, precision_log);
|
||||
}
|
||||
|
||||
|
||||
5
main.c
5
main.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) John G. Hasler 2009
|
||||
* Copyright (C) Miroslav Lichvar 2012-2015
|
||||
* Copyright (C) Miroslav Lichvar 2012-2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -325,7 +325,8 @@ go_daemon(void)
|
||||
if (r) {
|
||||
if (r > 0) {
|
||||
/* Print the error message from the child */
|
||||
fprintf(stderr, "%.1024s\n", message);
|
||||
message[sizeof (message) - 1] = '\0';
|
||||
fprintf(stderr, "%s\n", message);
|
||||
}
|
||||
exit(1);
|
||||
} else
|
||||
|
||||
@@ -113,6 +113,9 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
|
||||
LOG_FATAL(LOGF_Nameserv, "pipe() failed");
|
||||
}
|
||||
|
||||
UTI_FdSetCloexec(inst->pipe[0]);
|
||||
UTI_FdSetCloexec(inst->pipe[1]);
|
||||
|
||||
resolving_threads++;
|
||||
assert(resolving_threads <= 1);
|
||||
|
||||
|
||||
219
ntp_core.c
219
ntp_core.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2016
|
||||
* Copyright (C) Miroslav Lichvar 2009-2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -49,6 +49,7 @@
|
||||
/* ================================================== */
|
||||
|
||||
static LOG_FileID logfileid;
|
||||
static int log_raw_measurements;
|
||||
|
||||
/* ================================================== */
|
||||
/* Enumeration used for remembering the operating mode of one of the
|
||||
@@ -205,7 +206,8 @@ static ARR_Instance broadcasts;
|
||||
|
||||
/* Spacing required between samples for any two servers/peers (to
|
||||
minimise risk of network collisions) (in seconds) */
|
||||
#define SAMPLING_SEPARATION 0.2
|
||||
#define MIN_SAMPLING_SEPARATION 0.02
|
||||
#define MAX_SAMPLING_SEPARATION 0.2
|
||||
|
||||
/* Randomness added to spacing between samples for one server/peer */
|
||||
#define SAMPLING_RANDOMNESS 0.02
|
||||
@@ -243,8 +245,14 @@ static ARR_Instance broadcasts;
|
||||
/* Maximum acceptable delay in transmission for timestamp correction */
|
||||
#define MAX_TX_DELAY 1.0
|
||||
|
||||
/* Maximum allowed values of maxdelay parameters */
|
||||
#define MAX_MAXDELAY 1.0e3
|
||||
#define MAX_MAXDELAYRATIO 1.0e6
|
||||
#define MAX_MAXDELAYDEVRATIO 1.0e6
|
||||
|
||||
/* Minimum and maximum allowed poll interval */
|
||||
#define MIN_POLL 0
|
||||
#define MIN_MINPOLL -4
|
||||
#define MIN_MAXPOLL 0
|
||||
#define MAX_POLL 24
|
||||
|
||||
/* Kiss-o'-Death codes */
|
||||
@@ -273,6 +281,7 @@ static const char tss_chars[3] = {'D', 'K', 'H'};
|
||||
|
||||
static void transmit_timeout(void *arg);
|
||||
static double get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx);
|
||||
static double get_separation(int poll);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -345,7 +354,7 @@ NCR_Initialise(void)
|
||||
do_size_checks();
|
||||
do_time_checks();
|
||||
|
||||
logfileid = CNF_GetLogMeasurements() ? LOG_FileOpen("measurements",
|
||||
logfileid = CNF_GetLogMeasurements(&log_raw_measurements) ? LOG_FileOpen("measurements",
|
||||
" Date (UTC) Time IP Address L St 123 567 ABCD LP RP Score Offset Peer del. Peer disp. Root del. Root disp. Refid MTxRx")
|
||||
: -1;
|
||||
|
||||
@@ -393,7 +402,7 @@ restart_timeout(NCR_Instance inst, double delay)
|
||||
SCH_RemoveTimeout(inst->tx_timeout_id);
|
||||
|
||||
/* Start new timer for transmission */
|
||||
inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, SAMPLING_SEPARATION,
|
||||
inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, get_separation(inst->local_poll),
|
||||
SAMPLING_RANDOMNESS,
|
||||
SCH_NtpSamplingClass,
|
||||
transmit_timeout, (void *)inst);
|
||||
@@ -474,6 +483,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
|
||||
|
||||
result->remote_addr = *remote_addr;
|
||||
result->local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
result->local_addr.if_index = INVALID_IF_INDEX;
|
||||
|
||||
switch (type) {
|
||||
case NTP_SERVER:
|
||||
@@ -492,12 +502,12 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
|
||||
result->interleaved = params->interleaved;
|
||||
|
||||
result->minpoll = params->minpoll;
|
||||
if (result->minpoll < MIN_POLL)
|
||||
if (result->minpoll < MIN_MINPOLL)
|
||||
result->minpoll = SRC_DEFAULT_MINPOLL;
|
||||
else if (result->minpoll > MAX_POLL)
|
||||
result->minpoll = MAX_POLL;
|
||||
result->maxpoll = params->maxpoll;
|
||||
if (result->maxpoll < MIN_POLL)
|
||||
if (result->maxpoll < MIN_MAXPOLL)
|
||||
result->maxpoll = SRC_DEFAULT_MAXPOLL;
|
||||
else if (result->maxpoll > MAX_POLL)
|
||||
result->maxpoll = MAX_POLL;
|
||||
@@ -513,9 +523,9 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
|
||||
if (result->presend_minpoll <= MAX_POLL && result->mode != MODE_CLIENT)
|
||||
result->presend_minpoll = MAX_POLL + 1;
|
||||
|
||||
result->max_delay = params->max_delay;
|
||||
result->max_delay_ratio = params->max_delay_ratio;
|
||||
result->max_delay_dev_ratio = params->max_delay_dev_ratio;
|
||||
result->max_delay = CLAMP(0.0, params->max_delay, MAX_MAXDELAY);
|
||||
result->max_delay_ratio = CLAMP(0.0, params->max_delay_ratio, MAX_MAXDELAYRATIO);
|
||||
result->max_delay_dev_ratio = CLAMP(0.0, params->max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
|
||||
result->offset_correction = params->offset;
|
||||
result->auto_offline = params->auto_offline;
|
||||
result->poll_target = params->poll_target;
|
||||
@@ -648,6 +658,7 @@ NCR_ResetPoll(NCR_Instance instance)
|
||||
void
|
||||
NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr)
|
||||
{
|
||||
memset(&inst->report, 0, sizeof (inst->report));
|
||||
NCR_ResetInstance(inst);
|
||||
inst->remote_addr = *remote_addr;
|
||||
|
||||
@@ -656,6 +667,7 @@ NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr)
|
||||
else {
|
||||
NIO_CloseServerSocket(inst->local_addr.sock_fd);
|
||||
inst->local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
inst->local_addr.if_index = INVALID_IF_INDEX;
|
||||
inst->local_addr.sock_fd = NIO_OpenServerSocket(remote_addr);
|
||||
}
|
||||
|
||||
@@ -759,7 +771,7 @@ get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
|
||||
approx the poll interval away */
|
||||
poll_to_use = inst->local_poll;
|
||||
|
||||
delay_time = (double) (1UL<<poll_to_use);
|
||||
delay_time = UTI_Log2ToDouble(poll_to_use);
|
||||
if (inst->presend_done)
|
||||
delay_time = WARM_UP_DELAY;
|
||||
|
||||
@@ -777,7 +789,7 @@ get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
|
||||
if (poll_to_use < inst->minpoll)
|
||||
poll_to_use = inst->minpoll;
|
||||
|
||||
delay_time = (double) (1UL<<poll_to_use);
|
||||
delay_time = UTI_Log2ToDouble(poll_to_use);
|
||||
|
||||
/* If the remote stratum is higher than ours, try to lock on the
|
||||
peer's polling to minimize our response time by slightly extending
|
||||
@@ -816,6 +828,21 @@ get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
|
||||
return delay_time;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Calculate sampling separation for given polling interval */
|
||||
|
||||
static double
|
||||
get_separation(int poll)
|
||||
{
|
||||
double separation;
|
||||
|
||||
/* Allow up to 8 sources using the same short interval to not be limited
|
||||
by the separation */
|
||||
separation = UTI_Log2ToDouble(poll - 3);
|
||||
|
||||
return CLAMP(MIN_SAMPLING_SEPARATION, separation, MAX_SAMPLING_SEPARATION);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Timeout handler for closing the client socket when no acceptable
|
||||
reply can be received from the server */
|
||||
@@ -951,57 +978,63 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
frequency all along */
|
||||
UTI_TimespecToNtp64(&local_receive, &message.receive_ts, &ts_fuzz);
|
||||
|
||||
/* Prepare random bits which will be added to the transmit timestamp. */
|
||||
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
|
||||
do {
|
||||
/* Prepare random bits which will be added to the transmit timestamp */
|
||||
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
|
||||
|
||||
/* Transmit - this our local time right now! Also, we might need to
|
||||
store this for our own use later, next time we receive a message
|
||||
from the source we're sending to now. */
|
||||
LCL_ReadCookedTime(&local_transmit, &local_transmit_err);
|
||||
/* Transmit - this our local time right now! Also, we might need to
|
||||
store this for our own use later, next time we receive a message
|
||||
from the source we're sending to now. */
|
||||
LCL_ReadCookedTime(&local_transmit, &local_transmit_err);
|
||||
|
||||
if (smooth_time)
|
||||
UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
|
||||
if (smooth_time)
|
||||
UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
|
||||
|
||||
length = NTP_NORMAL_PACKET_LENGTH;
|
||||
length = NTP_NORMAL_PACKET_LENGTH;
|
||||
|
||||
/* Authenticate the packet if needed */
|
||||
/* Authenticate the packet */
|
||||
|
||||
if (auth_mode == AUTH_SYMMETRIC || auth_mode == AUTH_MSSNTP) {
|
||||
/* Pre-compensate the transmit time by approx. how long it will
|
||||
take to generate the authentication data. */
|
||||
local_transmit.tv_nsec += auth_mode == AUTH_SYMMETRIC ?
|
||||
KEY_GetAuthDelay(key_id) : NSD_GetAuthDelay(key_id);
|
||||
UTI_NormaliseTimespec(&local_transmit);
|
||||
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
|
||||
&message.transmit_ts, &ts_fuzz);
|
||||
if (auth_mode == AUTH_SYMMETRIC || auth_mode == AUTH_MSSNTP) {
|
||||
/* Pre-compensate the transmit time by approximately how long it will
|
||||
take to generate the authentication data */
|
||||
local_transmit.tv_nsec += auth_mode == AUTH_SYMMETRIC ?
|
||||
KEY_GetAuthDelay(key_id) : NSD_GetAuthDelay(key_id);
|
||||
UTI_NormaliseTimespec(&local_transmit);
|
||||
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
|
||||
&message.transmit_ts, &ts_fuzz);
|
||||
|
||||
if (auth_mode == AUTH_SYMMETRIC) {
|
||||
auth_len = KEY_GenerateAuth(key_id, (unsigned char *) &message,
|
||||
offsetof(NTP_Packet, auth_keyid),
|
||||
(unsigned char *)&message.auth_data,
|
||||
sizeof (message.auth_data));
|
||||
if (!auth_len) {
|
||||
DEBUG_LOG(LOGF_NtpCore, "Could not generate auth data with key %"PRIu32, key_id);
|
||||
return 0;
|
||||
if (auth_mode == AUTH_SYMMETRIC) {
|
||||
auth_len = KEY_GenerateAuth(key_id, (unsigned char *) &message,
|
||||
offsetof(NTP_Packet, auth_keyid),
|
||||
(unsigned char *)&message.auth_data,
|
||||
sizeof (message.auth_data));
|
||||
if (!auth_len) {
|
||||
DEBUG_LOG(LOGF_NtpCore, "Could not generate auth data with key %"PRIu32, key_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
message.auth_keyid = htonl(key_id);
|
||||
mac_len = sizeof (message.auth_keyid) + auth_len;
|
||||
|
||||
/* Truncate MACs in NTPv4 packets to allow deterministic parsing
|
||||
of extension fields (RFC 7822) */
|
||||
if (version == 4 && mac_len > NTP_MAX_V4_MAC_LENGTH)
|
||||
mac_len = NTP_MAX_V4_MAC_LENGTH;
|
||||
|
||||
length += mac_len;
|
||||
} else if (auth_mode == AUTH_MSSNTP) {
|
||||
/* MS-SNTP packets are signed (asynchronously) by ntp_signd */
|
||||
return NSD_SignAndSendPacket(key_id, &message, where_to, from, length);
|
||||
}
|
||||
|
||||
message.auth_keyid = htonl(key_id);
|
||||
mac_len = sizeof (message.auth_keyid) + auth_len;
|
||||
|
||||
/* Truncate MACs in NTPv4 packets to allow deterministic parsing
|
||||
of extension fields (RFC 7822) */
|
||||
if (version == 4 && mac_len > NTP_MAX_V4_MAC_LENGTH)
|
||||
mac_len = NTP_MAX_V4_MAC_LENGTH;
|
||||
|
||||
length += mac_len;
|
||||
} else if (auth_mode == AUTH_MSSNTP) {
|
||||
/* MS-SNTP packets are signed (asynchronously) by ntp_signd */
|
||||
return NSD_SignAndSendPacket(key_id, &message, where_to, from, length);
|
||||
} else {
|
||||
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
|
||||
&message.transmit_ts, &ts_fuzz);
|
||||
}
|
||||
} else {
|
||||
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
|
||||
&message.transmit_ts, &ts_fuzz);
|
||||
}
|
||||
|
||||
/* Avoid sending messages with non-zero transmit timestamp equal to the
|
||||
receive timestamp to allow reliable detection of the interleaved mode */
|
||||
} while (!UTI_CompareNtp64(&message.transmit_ts, &message.receive_ts) &&
|
||||
!UTI_IsZeroNtp64(&message.transmit_ts));
|
||||
|
||||
ret = NIO_SendPacket(&message, where_to, from, length, local_tx != NULL);
|
||||
|
||||
@@ -1064,6 +1097,7 @@ transmit_timeout(void *arg)
|
||||
|
||||
/* Don't require the packet to be sent from the same address as before */
|
||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
local_addr.if_index = INVALID_IF_INDEX;
|
||||
local_addr.sock_fd = inst->local_addr.sock_fd;
|
||||
|
||||
/* Check whether we need to 'warm up' the link to the other end by
|
||||
@@ -1412,12 +1446,8 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
sample_rx_tss = rx_ts->source;
|
||||
}
|
||||
|
||||
/* Work out 'delay' relative to the source's time */
|
||||
delay = (1.0 - (source_freq_lo + source_freq_hi) / 2.0) *
|
||||
local_interval - remote_interval;
|
||||
|
||||
/* Clamp delay to avoid misleading results later */
|
||||
delay = fabs(delay);
|
||||
/* Calculate delay */
|
||||
delay = fabs(local_interval - remote_interval);
|
||||
if (delay < precision)
|
||||
delay = precision;
|
||||
|
||||
@@ -1439,7 +1469,8 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
skew = (source_freq_hi - source_freq_lo) / 2.0;
|
||||
|
||||
/* and then calculate peer dispersion */
|
||||
dispersion = precision + inst->local_tx.err + rx_ts_err + skew * fabs(local_interval);
|
||||
dispersion = MAX(precision, MAX(inst->local_tx.err, rx_ts_err)) +
|
||||
skew * fabs(local_interval);
|
||||
|
||||
/* Additional tests required to pass before accumulating the sample */
|
||||
|
||||
@@ -1448,16 +1479,17 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
processing time is sane, and in the interleaved symmetric mode that
|
||||
the delay is not longer than half of the remote polling interval to
|
||||
detect missed packets */
|
||||
testA = delay - dispersion <= inst->max_delay &&
|
||||
testA = delay - dispersion <= inst->max_delay && precision <= inst->max_delay &&
|
||||
!(inst->mode == MODE_CLIENT && server_interval > MAX_SERVER_INTERVAL) &&
|
||||
!(inst->mode == MODE_ACTIVE && interleaved_packet &&
|
||||
delay > UTI_Log2ToDouble(message->poll - 1));
|
||||
|
||||
/* Test B requires that the ratio of the round trip delay to the
|
||||
minimum one currently in the stats data register is less than an
|
||||
administrator-defined value */
|
||||
/* Test B requires in the basic client mode that the ratio of the round
|
||||
trip delay to the minimum one currently in the stats data register is
|
||||
less than an administrator-defined value */
|
||||
testB = inst->max_delay_ratio <= 1.0 ||
|
||||
(delay - dispersion) / SST_MinRoundTripDelay(stats) <= inst->max_delay_ratio;
|
||||
!(inst->mode == MODE_CLIENT && !interleaved_packet &&
|
||||
(delay - dispersion) / SST_MinRoundTripDelay(stats) > inst->max_delay_ratio);
|
||||
|
||||
/* Test C requires that the ratio of the increase in delay from the minimum
|
||||
one in the stats data register to the standard deviation of the offsets
|
||||
@@ -1599,8 +1631,9 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
server and the socket can be closed */
|
||||
close_client_socket(inst);
|
||||
|
||||
/* Update the local address */
|
||||
/* Update the local address and interface */
|
||||
inst->local_addr.ip_addr = local_addr->ip_addr;
|
||||
inst->local_addr.if_index = local_addr->if_index;
|
||||
|
||||
/* And now, requeue the timer */
|
||||
if (inst->opmode != MD_OFFLINE) {
|
||||
@@ -1608,13 +1641,14 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
UTI_DiffTimespecsToDouble(&inst->local_rx.ts, &inst->local_tx.ts));
|
||||
|
||||
if (kod_rate) {
|
||||
LOG(LOGS_WARN, LOGF_NtpCore, "Received KoD RATE from %s",
|
||||
UTI_IPToString(&inst->remote_addr.ip_addr));
|
||||
|
||||
/* Back off for a while and stop ongoing burst */
|
||||
delay_time += 4 * (1UL << inst->minpoll);
|
||||
delay_time += 4 * UTI_Log2ToDouble(inst->local_poll);
|
||||
|
||||
if (inst->opmode == MD_BURST_WAS_OFFLINE || inst->opmode == MD_BURST_WAS_ONLINE) {
|
||||
inst->burst_good_samples_to_go = 0;
|
||||
LOG(LOGS_WARN, LOGF_NtpCore, "Received KoD RATE from %s, burst sampling stopped",
|
||||
UTI_IPToString(&inst->remote_addr.ip_addr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1654,7 +1688,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
}
|
||||
|
||||
/* Do measurement logging */
|
||||
if (logfileid != -1) {
|
||||
if (logfileid != -1 && (log_raw_measurements || synced_packet)) {
|
||||
LOG_FileWrite(logfileid, "%s %-15s %1c %2d %1d%1d%1d %1d%1d%1d %1d%1d%1d%d %2d %2d %4.2f %10.3e %10.3e %10.3e %10.3e %10.3e %08"PRIX32" %1d%1c %1c %1c",
|
||||
UTI_TimeToLogForm(sample_time.tv_sec),
|
||||
UTI_IPToString(&inst->remote_addr.ip_addr),
|
||||
@@ -1910,10 +1944,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
||||
!UTI_CompareNtp64(&message->originate_ts, local_ntp_rx);
|
||||
|
||||
if (interleaved) {
|
||||
if (!UTI_IsZeroNtp64(local_ntp_tx))
|
||||
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
|
||||
else
|
||||
interleaved = 0;
|
||||
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
|
||||
tx_ts = &local_tx;
|
||||
} else {
|
||||
UTI_ZeroNtp64(local_ntp_tx);
|
||||
@@ -2006,10 +2037,10 @@ NCR_ProcessTxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
||||
if (log_index < 0)
|
||||
return;
|
||||
|
||||
CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
|
||||
if (SMT_IsEnabled() && NTP_LVM_TO_MODE(message->lvm) == MODE_SERVER)
|
||||
UTI_AddDoubleToTimespec(&tx_ts->ts, SMT_GetOffset(&tx_ts->ts), &tx_ts->ts);
|
||||
|
||||
if (UTI_IsZeroNtp64(local_ntp_tx))
|
||||
return;
|
||||
CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
|
||||
|
||||
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
|
||||
update_tx_timestamp(&local_tx, tx_ts, local_ntp_rx, NULL, message);
|
||||
@@ -2081,7 +2112,7 @@ NCR_TakeSourceOffline(NCR_Instance inst)
|
||||
void
|
||||
NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
|
||||
{
|
||||
if (new_minpoll < MIN_POLL || new_minpoll > MAX_POLL)
|
||||
if (new_minpoll < MIN_MINPOLL || new_minpoll > MAX_POLL)
|
||||
return;
|
||||
inst->minpoll = new_minpoll;
|
||||
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new minpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_minpoll);
|
||||
@@ -2094,7 +2125,7 @@ NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
|
||||
void
|
||||
NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll)
|
||||
{
|
||||
if (new_maxpoll < MIN_POLL || new_maxpoll > MAX_POLL)
|
||||
if (new_maxpoll < MIN_MAXPOLL || new_maxpoll > MAX_POLL)
|
||||
return;
|
||||
inst->maxpoll = new_maxpoll;
|
||||
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new maxpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_maxpoll);
|
||||
@@ -2107,9 +2138,9 @@ NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll)
|
||||
void
|
||||
NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay)
|
||||
{
|
||||
inst->max_delay = new_max_delay;
|
||||
inst->max_delay = CLAMP(0.0, new_max_delay, MAX_MAXDELAY);
|
||||
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay %f",
|
||||
UTI_IPToString(&inst->remote_addr.ip_addr), new_max_delay);
|
||||
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -2117,9 +2148,9 @@ NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay)
|
||||
void
|
||||
NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio)
|
||||
{
|
||||
inst->max_delay_ratio = new_max_delay_ratio;
|
||||
inst->max_delay_ratio = CLAMP(0.0, new_max_delay_ratio, MAX_MAXDELAYRATIO);
|
||||
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay ratio %f",
|
||||
UTI_IPToString(&inst->remote_addr.ip_addr), new_max_delay_ratio);
|
||||
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_ratio);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -2127,9 +2158,9 @@ NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio)
|
||||
void
|
||||
NCR_ModifyMaxdelaydevratio(NCR_Instance inst, double new_max_delay_dev_ratio)
|
||||
{
|
||||
inst->max_delay_dev_ratio = new_max_delay_dev_ratio;
|
||||
inst->max_delay_dev_ratio = CLAMP(0.0, new_max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
|
||||
LOG(LOGS_INFO, LOGF_NtpCore, "Source %s new max delay dev ratio %f",
|
||||
UTI_IPToString(&inst->remote_addr.ip_addr), new_max_delay_dev_ratio);
|
||||
UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_dev_ratio);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -2333,20 +2364,21 @@ broadcast_timeout(void *arg)
|
||||
BroadcastDestination *destination;
|
||||
NTP_int64 orig_ts;
|
||||
NTP_Local_Timestamp recv_ts;
|
||||
int poll;
|
||||
|
||||
destination = ARR_GetElement(broadcasts, (long)arg);
|
||||
poll = log(destination->interval) / log(2.0) + 0.5;
|
||||
|
||||
UTI_ZeroNtp64(&orig_ts);
|
||||
UTI_ZeroTimespec(&recv_ts.ts);
|
||||
recv_ts.source = NTP_TS_DAEMON;
|
||||
recv_ts.err = 0.0;
|
||||
|
||||
transmit_packet(MODE_BROADCAST, 0, log(destination->interval) / log(2.0) + 0.5,
|
||||
NTP_VERSION, 0, 0, &orig_ts, &orig_ts, &recv_ts, NULL, NULL, NULL,
|
||||
&destination->addr, &destination->local_addr);
|
||||
transmit_packet(MODE_BROADCAST, 0, poll, NTP_VERSION, 0, 0, &orig_ts, &orig_ts, &recv_ts,
|
||||
NULL, NULL, NULL, &destination->addr, &destination->local_addr);
|
||||
|
||||
/* Requeue timeout. We don't care if interval drifts gradually. */
|
||||
SCH_AddTimeoutInClass(destination->interval, SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
|
||||
SCH_AddTimeoutInClass(destination->interval, get_separation(poll), SAMPLING_RANDOMNESS,
|
||||
SCH_NtpBroadcastClass, broadcast_timeout, arg);
|
||||
}
|
||||
|
||||
@@ -2362,10 +2394,11 @@ NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval)
|
||||
destination->addr.ip_addr = *addr;
|
||||
destination->addr.port = port;
|
||||
destination->local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
destination->local_addr.if_index = INVALID_IF_INDEX;
|
||||
destination->local_addr.sock_fd = NIO_OpenServerSocket(&destination->addr);
|
||||
destination->interval = CLAMP(1 << MIN_POLL, interval, 1 << MAX_POLL);
|
||||
destination->interval = CLAMP(1, interval, 1 << MAX_POLL);
|
||||
|
||||
SCH_AddTimeoutInClass(destination->interval, SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
|
||||
SCH_AddTimeoutInClass(destination->interval, MAX_SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
|
||||
SCH_NtpBroadcastClass, broadcast_timeout,
|
||||
(void *)(long)(ARR_GetSize(broadcasts) - 1));
|
||||
}
|
||||
|
||||
21
ntp_io.c
21
ntp_io.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Timo Teras 2009
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2013-2015
|
||||
* Copyright (C) Miroslav Lichvar 2009, 2013-2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -364,8 +364,11 @@ NIO_Initialise(int family)
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
NIO_Linux_Initialise();
|
||||
#else
|
||||
if (ARR_GetSize(CNF_GetHwTsInterfaces()))
|
||||
LOG_FATAL(LOGF_NtpIO, "HW timestamping not supported");
|
||||
if (1) {
|
||||
CNF_HwTsInterface *conf_iface;
|
||||
if (CNF_GetHwTsInterface(0, &conf_iface))
|
||||
LOG_FATAL(LOGF_NtpIO, "HW timestamping not supported");
|
||||
}
|
||||
#endif
|
||||
|
||||
recv_messages = ARR_CreateInstance(sizeof (struct Message));
|
||||
@@ -575,7 +578,6 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
||||
NTP_Local_Timestamp local_ts;
|
||||
struct timespec sched_ts;
|
||||
struct cmsghdr *cmsg;
|
||||
int if_index;
|
||||
|
||||
SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL);
|
||||
local_ts.source = NTP_TS_DAEMON;
|
||||
@@ -595,8 +597,8 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
||||
}
|
||||
|
||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
local_addr.if_index = INVALID_IF_INDEX;
|
||||
local_addr.sock_fd = sock_fd;
|
||||
if_index = -1;
|
||||
|
||||
if (hdr->msg_flags & MSG_TRUNC) {
|
||||
DEBUG_LOG(LOGF_NtpIO, "Received truncated message from %s:%d",
|
||||
@@ -617,7 +619,7 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
||||
memcpy(&ipi, CMSG_DATA(cmsg), sizeof(ipi));
|
||||
local_addr.ip_addr.addr.in4 = ntohl(ipi.ipi_addr.s_addr);
|
||||
local_addr.ip_addr.family = IPADDR_INET4;
|
||||
if_index = ipi.ipi_ifindex;
|
||||
local_addr.if_index = ipi.ipi_ifindex;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -629,7 +631,7 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
||||
memcpy(&local_addr.ip_addr.addr.in6, &ipi.ipi6_addr.s6_addr,
|
||||
sizeof (local_addr.ip_addr.addr.in6));
|
||||
local_addr.ip_addr.family = IPADDR_INET6;
|
||||
if_index = ipi.ipi6_ifindex;
|
||||
local_addr.if_index = ipi.ipi6_ifindex;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -657,14 +659,13 @@ process_message(struct msghdr *hdr, int length, int sock_fd)
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
if (NIO_Linux_ProcessMessage(&remote_addr, &local_addr, &local_ts,
|
||||
hdr, length, sock_fd, if_index))
|
||||
if (NIO_Linux_ProcessMessage(&remote_addr, &local_addr, &local_ts, hdr, length))
|
||||
return;
|
||||
#endif
|
||||
|
||||
DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd=%d if=%d tss=%d delay=%.9f",
|
||||
length, UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
|
||||
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd, if_index,
|
||||
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd, local_addr.if_index,
|
||||
local_ts.source, UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts));
|
||||
|
||||
/* Just ignore the packet if it's not of a recognized length */
|
||||
|
||||
224
ntp_io_linux.c
224
ntp_io_linux.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016
|
||||
* Copyright (C) Miroslav Lichvar 2016-2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <linux/errqueue.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
@@ -60,17 +61,30 @@ struct Interface {
|
||||
char name[IF_NAMESIZE];
|
||||
int if_index;
|
||||
int phc_fd;
|
||||
int phc_mode;
|
||||
int phc_nocrossts;
|
||||
/* Link speed in mbit/s */
|
||||
int link_speed;
|
||||
/* Start of UDP data at layer 2 for IPv4 and IPv6 */
|
||||
int l2_udp4_ntp_start;
|
||||
int l2_udp6_ntp_start;
|
||||
/* Precision of PHC readings */
|
||||
double precision;
|
||||
/* Compensation of errors in TX and RX timestamping */
|
||||
double tx_comp;
|
||||
double rx_comp;
|
||||
HCL_Instance clock;
|
||||
};
|
||||
|
||||
/* Number of PHC readings per HW clock sample */
|
||||
#define PHC_READINGS 10
|
||||
|
||||
/* Minimum interval between PHC readings */
|
||||
#define MIN_PHC_POLL -6
|
||||
|
||||
/* Maximum acceptable offset between HW and daemon/kernel timestamp */
|
||||
#define MAX_TS_DELAY 1.0
|
||||
|
||||
/* Array of Interfaces */
|
||||
static ARR_Instance interfaces;
|
||||
|
||||
@@ -84,14 +98,20 @@ static int permanent_ts_options;
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
add_interface(const char *name)
|
||||
add_interface(CNF_HwTsInterface *conf_iface)
|
||||
{
|
||||
struct ethtool_ts_info ts_info;
|
||||
struct hwtstamp_config ts_config;
|
||||
struct ifreq req;
|
||||
int sock_fd, if_index, phc_index, phc_fd;
|
||||
int sock_fd, if_index, phc_fd, req_hwts_flags;
|
||||
unsigned int i;
|
||||
struct Interface *iface;
|
||||
char phc_path[64];
|
||||
|
||||
/* Check if the interface was not already added */
|
||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||
if (!strcmp(conf_iface->name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
|
||||
return 1;
|
||||
}
|
||||
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock_fd < 0)
|
||||
@@ -100,7 +120,8 @@ add_interface(const char *name)
|
||||
memset(&req, 0, sizeof (req));
|
||||
memset(&ts_info, 0, sizeof (ts_info));
|
||||
|
||||
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", name) >= sizeof (req.ifr_name)) {
|
||||
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", conf_iface->name) >=
|
||||
sizeof (req.ifr_name)) {
|
||||
close(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -122,6 +143,14 @@ add_interface(const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
req_hwts_flags = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_TX_HARDWARE |
|
||||
SOF_TIMESTAMPING_RAW_HARDWARE;
|
||||
if ((ts_info.so_timestamping & req_hwts_flags) != req_hwts_flags) {
|
||||
DEBUG_LOG(LOGF_NtpIOLinux, "HW timestamping not supported on %s", req.ifr_name);
|
||||
close(sock_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ts_config.flags = 0;
|
||||
ts_config.tx_type = HWTSTAMP_TX_ON;
|
||||
ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
|
||||
@@ -134,37 +163,65 @@ add_interface(const char *name)
|
||||
}
|
||||
|
||||
close(sock_fd);
|
||||
phc_index = ts_info.phc_index;
|
||||
|
||||
if (snprintf(phc_path, sizeof (phc_path), "/dev/ptp%d", phc_index) >= sizeof (phc_path))
|
||||
phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index);
|
||||
if (phc_fd < 0)
|
||||
return 0;
|
||||
|
||||
phc_fd = open(phc_path, O_RDONLY);
|
||||
if (phc_fd < 0) {
|
||||
LOG(LOGS_ERR, LOGF_NtpIOLinux, "Could not open %s : %s", phc_path, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTI_FdSetCloexec(phc_fd);
|
||||
|
||||
iface = ARR_GetNewElement(interfaces);
|
||||
|
||||
snprintf(iface->name, sizeof (iface->name), "%s", name);
|
||||
snprintf(iface->name, sizeof (iface->name), "%s", conf_iface->name);
|
||||
iface->if_index = if_index;
|
||||
iface->phc_fd = phc_fd;
|
||||
iface->phc_mode = 0;
|
||||
iface->phc_nocrossts = conf_iface->nocrossts;
|
||||
|
||||
/* Start with 1 gbit and no VLANs or IPv4/IPv6 options */
|
||||
iface->link_speed = 1000;
|
||||
iface->l2_udp4_ntp_start = 42;
|
||||
iface->l2_udp6_ntp_start = 62;
|
||||
|
||||
iface->clock = HCL_CreateInstance();
|
||||
iface->precision = conf_iface->precision;
|
||||
iface->tx_comp = conf_iface->tx_comp;
|
||||
iface->rx_comp = conf_iface->rx_comp;
|
||||
|
||||
iface->clock = HCL_CreateInstance(UTI_Log2ToDouble(MAX(conf_iface->minpoll, MIN_PHC_POLL)));
|
||||
|
||||
LOG(LOGS_INFO, LOGF_NtpIOLinux, "Enabled HW timestamping on %s", iface->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
add_all_interfaces(CNF_HwTsInterface *conf_iface_all)
|
||||
{
|
||||
CNF_HwTsInterface conf_iface;
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
int r;
|
||||
|
||||
conf_iface = *conf_iface_all;
|
||||
|
||||
if (getifaddrs(&ifaddr)) {
|
||||
DEBUG_LOG(LOGF_NtpIOLinux, "getifaddrs() failed : %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (r = 0, ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||
conf_iface.name = ifa->ifa_name;
|
||||
if (add_interface(&conf_iface))
|
||||
r = 1;
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
|
||||
/* Return success if at least one interface was added */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
update_interface_speed(struct Interface *iface)
|
||||
{
|
||||
@@ -199,22 +256,32 @@ update_interface_speed(struct Interface *iface)
|
||||
void
|
||||
NIO_Linux_Initialise(void)
|
||||
{
|
||||
ARR_Instance config_hwts_ifaces;
|
||||
char *if_name;
|
||||
CNF_HwTsInterface *conf_iface;
|
||||
unsigned int i;
|
||||
int hwts;
|
||||
|
||||
interfaces = ARR_CreateInstance(sizeof (struct Interface));
|
||||
|
||||
config_hwts_ifaces = CNF_GetHwTsInterfaces();
|
||||
/* Enable HW timestamping on specified interfaces. If "*" was specified, try
|
||||
all interfaces. If no interface was specified, enable SW timestamping. */
|
||||
|
||||
/* Enable HW timestamping on all specified interfaces. If no interface was
|
||||
specified, use SW timestamping. */
|
||||
if (ARR_GetSize(config_hwts_ifaces)) {
|
||||
for (i = 0; i < ARR_GetSize(config_hwts_ifaces); i++) {
|
||||
if_name = *(char **)ARR_GetElement(config_hwts_ifaces, i);
|
||||
if (!add_interface(if_name))
|
||||
LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", if_name);
|
||||
}
|
||||
for (i = hwts = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
|
||||
if (!strcmp("*", conf_iface->name))
|
||||
continue;
|
||||
if (!add_interface(conf_iface))
|
||||
LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", conf_iface->name);
|
||||
hwts = 1;
|
||||
}
|
||||
|
||||
for (i = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
|
||||
if (strcmp("*", conf_iface->name))
|
||||
continue;
|
||||
if (add_all_interfaces(conf_iface))
|
||||
hwts = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hwts) {
|
||||
ts_flags = SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE;
|
||||
ts_tx_flags = SOF_TIMESTAMPING_TX_HARDWARE;
|
||||
} else {
|
||||
@@ -283,68 +350,6 @@ NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
get_phc_sample(int phc_fd, struct timespec *phc_ts, struct timespec *local_ts, double *p_delay)
|
||||
{
|
||||
struct ptp_sys_offset sys_off;
|
||||
struct timespec ts1, ts2, ts3, phc_tss[PHC_READINGS], sys_tss[PHC_READINGS];
|
||||
double min_delay = 0.0, delays[PHC_READINGS], phc_sum, local_sum, local_prec;
|
||||
int i, n;
|
||||
|
||||
/* Silence valgrind */
|
||||
memset(&sys_off, 0, sizeof (sys_off));
|
||||
|
||||
sys_off.n_samples = PHC_READINGS;
|
||||
|
||||
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
|
||||
DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < PHC_READINGS; i++) {
|
||||
ts1.tv_sec = sys_off.ts[i * 2].sec;
|
||||
ts1.tv_nsec = sys_off.ts[i * 2].nsec;
|
||||
ts2.tv_sec = sys_off.ts[i * 2 + 1].sec;
|
||||
ts2.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
|
||||
ts3.tv_sec = sys_off.ts[i * 2 + 2].sec;
|
||||
ts3.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
|
||||
|
||||
sys_tss[i] = ts1;
|
||||
phc_tss[i] = ts2;
|
||||
delays[i] = UTI_DiffTimespecsToDouble(&ts3, &ts1);
|
||||
|
||||
if (delays[i] <= 0.0)
|
||||
/* Step in the middle of a PHC reading? */
|
||||
return 0;
|
||||
|
||||
if (!i || delays[i] < min_delay)
|
||||
min_delay = delays[i];
|
||||
}
|
||||
|
||||
local_prec = LCL_GetSysPrecisionAsQuantum();
|
||||
|
||||
/* Combine best readings */
|
||||
for (i = n = 0, phc_sum = local_sum = 0.0; i < PHC_READINGS; i++) {
|
||||
if (delays[i] > min_delay + local_prec)
|
||||
continue;
|
||||
|
||||
phc_sum += UTI_DiffTimespecsToDouble(&phc_tss[i], &phc_tss[0]);
|
||||
local_sum += UTI_DiffTimespecsToDouble(&sys_tss[i], &sys_tss[0]) + delays[i] / 2.0;
|
||||
n++;
|
||||
}
|
||||
|
||||
assert(n);
|
||||
|
||||
UTI_AddDoubleToTimespec(&phc_tss[0], phc_sum / n, phc_ts);
|
||||
UTI_AddDoubleToTimespec(&sys_tss[0], local_sum / n, &ts1);
|
||||
LCL_CookTime(&ts1, local_ts, NULL);
|
||||
*p_delay = min_delay;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static struct Interface *
|
||||
get_interface(int if_index)
|
||||
{
|
||||
@@ -368,16 +373,17 @@ static void
|
||||
process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
|
||||
NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family)
|
||||
{
|
||||
struct timespec sample_phc_ts, sample_local_ts;
|
||||
double sample_delay, rx_correction;
|
||||
struct timespec sample_phc_ts, sample_sys_ts, sample_local_ts, ts;
|
||||
double rx_correction, ts_delay, err;
|
||||
int l2_length;
|
||||
|
||||
if (HCL_NeedsNewSample(iface->clock, &local_ts->ts)) {
|
||||
if (!get_phc_sample(iface->phc_fd, &sample_phc_ts, &sample_local_ts, &sample_delay))
|
||||
if (!SYS_Linux_GetPHCSample(iface->phc_fd, iface->phc_nocrossts, iface->precision,
|
||||
&iface->phc_mode, &sample_phc_ts, &sample_sys_ts, &err))
|
||||
return;
|
||||
|
||||
HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts,
|
||||
sample_delay / 2.0);
|
||||
LCL_CookTime(&sample_sys_ts, &sample_local_ts, NULL);
|
||||
HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts, err);
|
||||
|
||||
update_interface_speed(iface);
|
||||
}
|
||||
@@ -395,9 +401,23 @@ process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
|
||||
UTI_AddDoubleToTimespec(hw_ts, rx_correction, hw_ts);
|
||||
}
|
||||
|
||||
if (!HCL_CookTime(iface->clock, hw_ts, &local_ts->ts, &local_ts->err))
|
||||
if (!rx_ntp_length && iface->tx_comp)
|
||||
UTI_AddDoubleToTimespec(hw_ts, iface->tx_comp, hw_ts);
|
||||
else if (rx_ntp_length && iface->rx_comp)
|
||||
UTI_AddDoubleToTimespec(hw_ts, -iface->rx_comp, hw_ts);
|
||||
|
||||
if (!HCL_CookTime(iface->clock, hw_ts, &ts, &err))
|
||||
return;
|
||||
|
||||
ts_delay = UTI_DiffTimespecsToDouble(&local_ts->ts, &ts);
|
||||
|
||||
if (fabs(ts_delay) > MAX_TS_DELAY) {
|
||||
DEBUG_LOG(LOGF_NtpIOLinux, "Unacceptable timestamp delay %.9f", ts_delay);
|
||||
return;
|
||||
}
|
||||
|
||||
local_ts->ts = ts;
|
||||
local_ts->err = err;
|
||||
local_ts->source = NTP_TS_HARDWARE;
|
||||
}
|
||||
|
||||
@@ -468,8 +488,7 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
|
||||
|
||||
int
|
||||
NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr,
|
||||
int length, int sock_fd, int if_index)
|
||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length)
|
||||
{
|
||||
struct Interface *iface;
|
||||
struct cmsghdr *cmsg;
|
||||
@@ -487,13 +506,14 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
|
||||
if (!UTI_IsZeroTimespec(&ts3.ts[0])) {
|
||||
LCL_CookTime(&ts3.ts[0], &local_ts->ts, &local_ts->err);
|
||||
local_ts->source = NTP_TS_KERNEL;
|
||||
} else {
|
||||
iface = get_interface(if_index);
|
||||
} else if (!UTI_IsZeroTimespec(&ts3.ts[2])) {
|
||||
iface = get_interface(local_addr->if_index);
|
||||
if (iface) {
|
||||
process_hw_timestamp(iface, &ts3.ts[2], local_ts, !is_tx ? length : 0,
|
||||
remote_addr->ip_addr.family);
|
||||
} else {
|
||||
DEBUG_LOG(LOGF_NtpIOLinux, "HW clock not found for interface %d", if_index);
|
||||
DEBUG_LOG(LOGF_NtpIOLinux, "HW clock not found for interface %d",
|
||||
local_addr->if_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -525,7 +545,7 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
|
||||
|
||||
DEBUG_LOG(LOGF_NtpIOLinux, "Received %d (%d) bytes from error queue for %s:%d fd=%d if=%d tss=%d",
|
||||
l2_length, length, UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
|
||||
sock_fd, if_index, local_ts->source);
|
||||
local_addr->sock_fd, local_addr->if_index, local_ts->source);
|
||||
|
||||
/* Update assumed position of UDP data at layer 2 for next received packet */
|
||||
if (iface && length) {
|
||||
|
||||
@@ -31,7 +31,6 @@ extern void NIO_Linux_Finalise(void);
|
||||
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
|
||||
|
||||
extern int NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length,
|
||||
int sock_fd, int if_index);
|
||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length);
|
||||
|
||||
extern int NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014
|
||||
* Copyright (C) Miroslav Lichvar 2009-2011, 2013-2014, 2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -505,6 +505,12 @@ RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second)
|
||||
return 1;
|
||||
}
|
||||
|
||||
double
|
||||
RCL_GetPrecision(RCL_Instance instance)
|
||||
{
|
||||
return instance->precision;
|
||||
}
|
||||
|
||||
static int
|
||||
valid_sample_time(RCL_Instance instance, struct timespec *raw, struct timespec *cooked)
|
||||
{
|
||||
|
||||
@@ -71,5 +71,6 @@ extern char *RCL_GetDriverParameter(RCL_Instance instance);
|
||||
extern char *RCL_GetDriverOption(RCL_Instance instance, char *name);
|
||||
extern int RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap);
|
||||
extern int RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second);
|
||||
extern double RCL_GetPrecision(RCL_Instance instance);
|
||||
|
||||
#endif
|
||||
|
||||
137
refclock_phc.c
137
refclock_phc.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2013
|
||||
* Copyright (C) Miroslav Lichvar 2013, 2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -33,144 +33,67 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <linux/ptp_clock.h>
|
||||
|
||||
#include "refclock.h"
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "sys_linux.h"
|
||||
|
||||
/* From linux/include/linux/posix-timers.h */
|
||||
#define CPUCLOCK_MAX 3
|
||||
#define CLOCKFD CPUCLOCK_MAX
|
||||
#define CLOCKFD_MASK (CPUCLOCK_PERTHREAD_MASK|CPUCLOCK_CLOCK_MASK)
|
||||
|
||||
#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
|
||||
|
||||
#define NUM_READINGS 10
|
||||
|
||||
static int no_sys_offset_ioctl = 0;
|
||||
|
||||
struct phc_reading {
|
||||
struct timespec sys_ts1;
|
||||
struct timespec phc_ts;;
|
||||
struct timespec sys_ts2;
|
||||
struct phc_instance {
|
||||
int fd;
|
||||
int mode;
|
||||
int nocrossts;
|
||||
};
|
||||
|
||||
static int read_phc_ioctl(struct phc_reading *readings, int phc_fd, int n)
|
||||
{
|
||||
#if defined(PTP_SYS_OFFSET) && NUM_READINGS <= PTP_MAX_SAMPLES
|
||||
struct ptp_sys_offset sys_off;
|
||||
int i;
|
||||
|
||||
/* Silence valgrind */
|
||||
memset(&sys_off, 0, sizeof (sys_off));
|
||||
|
||||
sys_off.n_samples = n;
|
||||
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
|
||||
LOG(LOGS_ERR, LOGF_Refclock, "ioctl(PTP_SYS_OFFSET) failed : %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
readings[i].sys_ts1.tv_sec = sys_off.ts[i * 2].sec;
|
||||
readings[i].sys_ts1.tv_nsec = sys_off.ts[i * 2].nsec;
|
||||
readings[i].phc_ts.tv_sec = sys_off.ts[i * 2 + 1].sec;
|
||||
readings[i].phc_ts.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
|
||||
readings[i].sys_ts2.tv_sec = sys_off.ts[i * 2 + 2].sec;
|
||||
readings[i].sys_ts2.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
|
||||
}
|
||||
|
||||
return 1;
|
||||
#else
|
||||
/* Not available */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int read_phc_user(struct phc_reading *readings, int phc_fd, int n)
|
||||
{
|
||||
clockid_t phc_id;
|
||||
int i;
|
||||
|
||||
phc_id = FD_TO_CLOCKID(phc_fd);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (clock_gettime(CLOCK_REALTIME, &readings[i].sys_ts1) ||
|
||||
clock_gettime(phc_id, &readings[i].phc_ts) ||
|
||||
clock_gettime(CLOCK_REALTIME, &readings[i].sys_ts2)) {
|
||||
LOG(LOGS_ERR, LOGF_Refclock, "clock_gettime() failed : %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int phc_initialise(RCL_Instance instance)
|
||||
{
|
||||
struct ptp_clock_caps caps;
|
||||
struct phc_instance *phc;
|
||||
int phc_fd;
|
||||
char *path;
|
||||
|
||||
path = RCL_GetDriverParameter(instance);
|
||||
|
||||
phc_fd = open(path, O_RDONLY);
|
||||
phc_fd = SYS_Linux_OpenPHC(path, 0);
|
||||
if (phc_fd < 0) {
|
||||
LOG_FATAL(LOGF_Refclock, "open() failed on %s", path);
|
||||
LOG_FATAL(LOGF_Refclock, "Could not open PHC");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure it is a PHC */
|
||||
if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) {
|
||||
LOG_FATAL(LOGF_Refclock, "ioctl(PTP_CLOCK_GETCAPS) failed : %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
phc = MallocNew(struct phc_instance);
|
||||
phc->fd = phc_fd;
|
||||
phc->mode = 0;
|
||||
phc->nocrossts = RCL_GetDriverOption(instance, "nocrossts") ? 1 : 0;
|
||||
|
||||
UTI_FdSetCloexec(phc_fd);
|
||||
|
||||
RCL_SetDriverData(instance, (void *)(long)phc_fd);
|
||||
RCL_SetDriverData(instance, phc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void phc_finalise(RCL_Instance instance)
|
||||
{
|
||||
close((long)RCL_GetDriverData(instance));
|
||||
struct phc_instance *phc;
|
||||
|
||||
phc = (struct phc_instance *)RCL_GetDriverData(instance);
|
||||
close(phc->fd);
|
||||
Free(phc);
|
||||
}
|
||||
|
||||
static int phc_poll(RCL_Instance instance)
|
||||
{
|
||||
struct phc_reading readings[NUM_READINGS];
|
||||
double offset = 0.0, delay, best_delay = 0.0;
|
||||
int i, phc_fd, best;
|
||||
|
||||
phc_fd = (long)RCL_GetDriverData(instance);
|
||||
struct phc_instance *phc;
|
||||
struct timespec phc_ts, sys_ts;
|
||||
double offset, err;
|
||||
|
||||
if (!no_sys_offset_ioctl) {
|
||||
if (!read_phc_ioctl(readings, phc_fd, NUM_READINGS)) {
|
||||
no_sys_offset_ioctl = 1;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!read_phc_user(readings, phc_fd, NUM_READINGS))
|
||||
return 0;
|
||||
}
|
||||
phc = (struct phc_instance *)RCL_GetDriverData(instance);
|
||||
|
||||
/* Find the fastest reading */
|
||||
for (i = 0; i < NUM_READINGS; i++) {
|
||||
delay = UTI_DiffTimespecsToDouble(&readings[i].sys_ts2, &readings[i].sys_ts1);
|
||||
if (!SYS_Linux_GetPHCSample(phc->fd, phc->nocrossts, RCL_GetPrecision(instance),
|
||||
&phc->mode, &phc_ts, &sys_ts, &err))
|
||||
return 0;
|
||||
|
||||
if (!i || best_delay > delay) {
|
||||
best = i;
|
||||
best_delay = delay;
|
||||
}
|
||||
}
|
||||
offset = UTI_DiffTimespecsToDouble(&phc_ts, &sys_ts);
|
||||
|
||||
offset = UTI_DiffTimespecsToDouble(&readings[best].phc_ts, &readings[best].sys_ts2) +
|
||||
best_delay / 2.0;
|
||||
DEBUG_LOG(LOGF_Refclock, "PHC offset: %+.9f err: %.9f", offset, err);
|
||||
|
||||
DEBUG_LOG(LOGF_Refclock, "PHC offset: %+.9f delay: %.9f", offset, best_delay);
|
||||
|
||||
return RCL_AddSample(instance, &readings[best].sys_ts2, offset, LEAP_Normal);
|
||||
return RCL_AddSample(instance, &sys_ts, offset, LEAP_Normal);
|
||||
}
|
||||
|
||||
RefclockDriver RCL_PHC_driver = {
|
||||
|
||||
@@ -1214,7 +1214,7 @@ REF_GetReferenceParams
|
||||
*leap_status = LEAP_Normal;
|
||||
|
||||
*root_delay = 0.0;
|
||||
*root_dispersion = LCL_GetSysPrecisionAsQuantum();
|
||||
*root_dispersion = 0.0;
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2011
|
||||
* Copyright (C) Miroslav Lichvar 2011, 2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
||||
@@ -187,6 +187,11 @@ accumulate_sample(time_t rtc, struct timespec *sys)
|
||||
discard_samples(NEW_FIRST_WHEN_FULL);
|
||||
}
|
||||
|
||||
/* Discard all samples if the RTC was stepped back (not our trim) */
|
||||
if (n_samples > 0 && rtc_sec[n_samples - 1] - rtc >= rtc_trim[n_samples - 1]) {
|
||||
DEBUG_LOG(LOGF_RtcLinux, "RTC samples discarded");
|
||||
n_samples = 0;
|
||||
}
|
||||
|
||||
/* Always use most recent sample as reference */
|
||||
/* use sample only if n_sample is not negative*/
|
||||
|
||||
2
sched.c
2
sched.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2011, 2013-2015
|
||||
* Copyright (C) Miroslav Lichvar 2011, 2013-2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
||||
@@ -425,10 +425,11 @@ SRC_UpdateReachability(SRC_Instance inst, int reachable)
|
||||
}
|
||||
|
||||
/* Try to replace NTP sources that are unreachable, falsetickers, or
|
||||
have root distance larger than the allowed maximum */
|
||||
have root distance or jitter larger than the allowed maximums */
|
||||
if (inst->type == SRC_NTP &&
|
||||
((!inst->reachability && inst->reachability_size == SOURCE_REACH_BITS) ||
|
||||
inst->status == SRC_FALSETICKER || inst->status == SRC_BAD_DISTANCE)) {
|
||||
inst->status == SRC_BAD_DISTANCE || inst->status == SRC_JITTERY ||
|
||||
inst->status == SRC_FALSETICKER)) {
|
||||
NSR_HandleBadSource(inst->ip_addr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2011-2014
|
||||
* Copyright (C) Miroslav Lichvar 2011-2014, 2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -47,8 +47,12 @@
|
||||
2000ppm, which would be pretty bad */
|
||||
#define WORST_CASE_FREQ_BOUND (2000.0/1.0e6)
|
||||
|
||||
/* The minimum allowed skew */
|
||||
/* The minimum and maximum assumed skew */
|
||||
#define MIN_SKEW 1.0e-12
|
||||
#define MAX_SKEW 1.0e+02
|
||||
|
||||
/* The minimum assumed std dev for weighting */
|
||||
#define MIN_WEIGHT_SD 1.0e-9
|
||||
|
||||
/* The asymmetry of network jitter when all jitter is in one direction */
|
||||
#define MAX_ASYMMETRY 0.5
|
||||
@@ -507,8 +511,7 @@ SST_DoNewRegression(SST_Stats inst)
|
||||
/* And now, work out the weight vector */
|
||||
|
||||
sd = mean_distance - min_distance;
|
||||
if (sd > min_distance || sd <= 0.0)
|
||||
sd = min_distance;
|
||||
sd = CLAMP(MIN_WEIGHT_SD, sd, min_distance);
|
||||
|
||||
for (i=0; i<inst->n_samples; i++) {
|
||||
sd_weight = 1.0 + SD_TO_DIST_RATIO * (peer_distances[i] - min_distance) / sd;
|
||||
@@ -539,9 +542,7 @@ SST_DoNewRegression(SST_Stats inst)
|
||||
inst->std_dev = sqrt(est_var);
|
||||
inst->nruns = nruns;
|
||||
|
||||
if (inst->skew < MIN_SKEW)
|
||||
inst->skew = MIN_SKEW;
|
||||
|
||||
inst->skew = CLAMP(MIN_SKEW, inst->skew, MAX_SKEW);
|
||||
stress = fabs(old_freq - inst->estimated_frequency) / old_skew;
|
||||
|
||||
DEBUG_LOG(LOGF_SourceStats, "off=%e freq=%e skew=%e n=%d bs=%d runs=%d asym=%f arun=%d",
|
||||
@@ -844,6 +845,8 @@ SST_SaveToFile(SST_Stats inst, FILE *out)
|
||||
inst->strata[j]);
|
||||
|
||||
}
|
||||
|
||||
fprintf(out, "%d\n", inst->asymmetry_run);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -898,6 +901,10 @@ SST_LoadFromFile(SST_Stats inst, FILE *in)
|
||||
UTI_NormaliseTimespec(&inst->sample_times[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* This field was not saved in older versions */
|
||||
if (!fgets(line, sizeof(line), in) || sscanf(line, "%d\n", &inst->asymmetry_run) != 1)
|
||||
inst->asymmetry_run = 0;
|
||||
} else {
|
||||
inst->n_samples = 0; /* Load abandoned if any sign of corruption */
|
||||
return 0;
|
||||
@@ -921,7 +928,7 @@ void
|
||||
SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timespec *now)
|
||||
{
|
||||
int i, j;
|
||||
struct timespec ago;
|
||||
struct timespec last_sample_time;
|
||||
|
||||
if (inst->n_samples > 0) {
|
||||
i = get_runsbuf_index(inst, inst->n_samples - 1);
|
||||
@@ -931,8 +938,10 @@ SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timespec *no
|
||||
report->latest_meas_err = 0.5*inst->root_delays[j] + inst->root_dispersions[j];
|
||||
report->stratum = inst->strata[j];
|
||||
|
||||
UTI_DiffTimespecs(&ago, now, &inst->sample_times[i]);
|
||||
report->latest_meas_ago = ago.tv_sec;
|
||||
/* Align the sample time to reduce the leak of the receive timestamp */
|
||||
last_sample_time = inst->sample_times[i];
|
||||
last_sample_time.tv_nsec = 0;
|
||||
report->latest_meas_ago = UTI_DiffTimespecsToDouble(now, &last_sample_time);
|
||||
} else {
|
||||
report->latest_meas_ago = (uint32_t)-1;
|
||||
report->orig_latest_meas = 0;
|
||||
|
||||
22
stubs.c
22
stubs.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2014-2015
|
||||
* Copyright (C) Miroslav Lichvar 2014-2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "privops.h"
|
||||
#include "refclock.h"
|
||||
#include "sched.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifndef FEAT_ASYNCDNS
|
||||
|
||||
@@ -51,10 +52,11 @@ struct DNS_Async_Instance {
|
||||
const char *name;
|
||||
DNS_NameResolveHandler handler;
|
||||
void *arg;
|
||||
int pipe[2];
|
||||
};
|
||||
|
||||
static void
|
||||
resolve_name(void *anything)
|
||||
resolve_name(int fd, int event, void *anything)
|
||||
{
|
||||
struct DNS_Async_Instance *inst;
|
||||
IPAddr addrs[DNS_MAX_ADDRESSES];
|
||||
@@ -62,6 +64,11 @@ resolve_name(void *anything)
|
||||
int i;
|
||||
|
||||
inst = (struct DNS_Async_Instance *)anything;
|
||||
|
||||
SCH_RemoveFileHandler(inst->pipe[0]);
|
||||
close(inst->pipe[0]);
|
||||
close(inst->pipe[1]);
|
||||
|
||||
status = PRV_Name2IPAddress(inst->name, addrs, DNS_MAX_ADDRESSES);
|
||||
|
||||
for (i = 0; status == DNS_Success && i < DNS_MAX_ADDRESSES &&
|
||||
@@ -83,7 +90,16 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
|
||||
inst->handler = handler;
|
||||
inst->arg = anything;
|
||||
|
||||
SCH_AddTimeoutByDelay(0.0, resolve_name, inst);
|
||||
if (pipe(inst->pipe))
|
||||
LOG_FATAL(LOGF_Nameserv, "pipe() failed");
|
||||
|
||||
UTI_FdSetCloexec(inst->pipe[0]);
|
||||
UTI_FdSetCloexec(inst->pipe[1]);
|
||||
|
||||
SCH_AddFileHandler(inst->pipe[0], SCH_FILE_INPUT, resolve_name, inst);
|
||||
|
||||
if (write(inst->pipe[1], "", 1) < 0)
|
||||
;
|
||||
}
|
||||
|
||||
#endif /* !FEAT_ASYNCDNS */
|
||||
|
||||
161
sys_linux.c
161
sys_linux.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) John G. Hasler 2009
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2015
|
||||
* Copyright (C) Miroslav Lichvar 2009-2012, 2014-2016
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -47,13 +47,14 @@
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
|
||||
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||
#include <linux/ptp_clock.h>
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_SCFILTER
|
||||
#include <sys/prctl.h>
|
||||
#include <seccomp.h>
|
||||
#include <termios.h>
|
||||
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||
#include <linux/ptp_clock.h>
|
||||
#endif
|
||||
#ifdef FEAT_PPS
|
||||
#include <linux/pps.h>
|
||||
#endif
|
||||
@@ -68,6 +69,7 @@
|
||||
#include "sys_linux.h"
|
||||
#include "sys_timex.h"
|
||||
#include "conf.h"
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "privops.h"
|
||||
#include "util.h"
|
||||
@@ -515,6 +517,9 @@ SYS_Linux_EnableSystemCallFilter(int level)
|
||||
FIONREAD, TCGETS,
|
||||
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||
PTP_SYS_OFFSET,
|
||||
#ifdef PTP_SYS_OFFSET_PRECISE
|
||||
PTP_SYS_OFFSET_PRECISE,
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FEAT_PPS
|
||||
PPS_FETCH,
|
||||
@@ -661,3 +666,151 @@ SYS_Linux_CheckKernelVersion(int req_major, int req_minor)
|
||||
|
||||
return kernelvercmp(req_major, req_minor, 0, major, minor, patch) <= 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(FEAT_PHC) || defined(HAVE_LINUX_TIMESTAMPING)
|
||||
|
||||
#define PHC_READINGS 10
|
||||
|
||||
static int
|
||||
get_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
|
||||
struct timespec *sys_ts, double *err)
|
||||
{
|
||||
struct ptp_sys_offset sys_off;
|
||||
struct timespec ts1, ts2, ts3, phc_tss[PHC_READINGS], sys_tss[PHC_READINGS];
|
||||
double min_delay = 0.0, delays[PHC_READINGS], phc_sum, sys_sum, sys_prec;
|
||||
int i, n;
|
||||
|
||||
/* Silence valgrind */
|
||||
memset(&sys_off, 0, sizeof (sys_off));
|
||||
|
||||
sys_off.n_samples = PHC_READINGS;
|
||||
|
||||
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
|
||||
DEBUG_LOG(LOGF_SysLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < PHC_READINGS; i++) {
|
||||
ts1.tv_sec = sys_off.ts[i * 2].sec;
|
||||
ts1.tv_nsec = sys_off.ts[i * 2].nsec;
|
||||
ts2.tv_sec = sys_off.ts[i * 2 + 1].sec;
|
||||
ts2.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
|
||||
ts3.tv_sec = sys_off.ts[i * 2 + 2].sec;
|
||||
ts3.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
|
||||
|
||||
sys_tss[i] = ts1;
|
||||
phc_tss[i] = ts2;
|
||||
delays[i] = UTI_DiffTimespecsToDouble(&ts3, &ts1);
|
||||
|
||||
if (delays[i] <= 0.0)
|
||||
/* Step in the middle of a PHC reading? */
|
||||
return 0;
|
||||
|
||||
if (!i || delays[i] < min_delay)
|
||||
min_delay = delays[i];
|
||||
}
|
||||
|
||||
sys_prec = LCL_GetSysPrecisionAsQuantum();
|
||||
|
||||
/* Combine best readings */
|
||||
for (i = n = 0, phc_sum = sys_sum = 0.0; i < PHC_READINGS; i++) {
|
||||
if (delays[i] > min_delay + MAX(sys_prec, precision))
|
||||
continue;
|
||||
|
||||
phc_sum += UTI_DiffTimespecsToDouble(&phc_tss[i], &phc_tss[0]);
|
||||
sys_sum += UTI_DiffTimespecsToDouble(&sys_tss[i], &sys_tss[0]) + delays[i] / 2.0;
|
||||
n++;
|
||||
}
|
||||
|
||||
assert(n);
|
||||
|
||||
UTI_AddDoubleToTimespec(&phc_tss[0], phc_sum / n, phc_ts);
|
||||
UTI_AddDoubleToTimespec(&sys_tss[0], sys_sum / n, sys_ts);
|
||||
*err = MAX(min_delay / 2.0, precision);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
get_precise_phc_sample(int phc_fd, double precision, struct timespec *phc_ts,
|
||||
struct timespec *sys_ts, double *err)
|
||||
{
|
||||
#ifdef PTP_SYS_OFFSET_PRECISE
|
||||
struct ptp_sys_offset_precise sys_off;
|
||||
|
||||
/* Silence valgrind */
|
||||
memset(&sys_off, 0, sizeof (sys_off));
|
||||
|
||||
if (ioctl(phc_fd, PTP_SYS_OFFSET_PRECISE, &sys_off)) {
|
||||
DEBUG_LOG(LOGF_SysLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET_PRECISE",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
phc_ts->tv_sec = sys_off.device.sec;
|
||||
phc_ts->tv_nsec = sys_off.device.nsec;
|
||||
sys_ts->tv_sec = sys_off.sys_realtime.sec;
|
||||
sys_ts->tv_nsec = sys_off.sys_realtime.nsec;
|
||||
*err = MAX(LCL_GetSysPrecisionAsQuantum(), precision);
|
||||
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SYS_Linux_OpenPHC(const char *path, int phc_index)
|
||||
{
|
||||
struct ptp_clock_caps caps;
|
||||
char phc_path[64];
|
||||
int phc_fd;
|
||||
|
||||
if (!path) {
|
||||
if (snprintf(phc_path, sizeof (phc_path), "/dev/ptp%d", phc_index) >= sizeof (phc_path))
|
||||
return -1;
|
||||
path = phc_path;
|
||||
}
|
||||
|
||||
phc_fd = open(path, O_RDONLY);
|
||||
if (phc_fd < 0) {
|
||||
LOG(LOGS_ERR, LOGF_SysLinux, "Could not open %s : %s", path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make sure it is a PHC */
|
||||
if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) {
|
||||
LOG(LOGS_ERR, LOGF_SysLinux, "ioctl(%s) failed : %s", "PTP_CLOCK_GETCAPS", strerror(errno));
|
||||
close(phc_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
UTI_FdSetCloexec(phc_fd);
|
||||
|
||||
return phc_fd;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SYS_Linux_GetPHCSample(int fd, int nocrossts, double precision, int *reading_mode,
|
||||
struct timespec *phc_ts, struct timespec *sys_ts, double *err)
|
||||
{
|
||||
if ((*reading_mode == 2 || !*reading_mode) && !nocrossts &&
|
||||
get_precise_phc_sample(fd, precision, phc_ts, sys_ts, err)) {
|
||||
*reading_mode = 2;
|
||||
return 1;
|
||||
} else if ((*reading_mode == 1 || !*reading_mode) &&
|
||||
get_phc_sample(fd, precision, phc_ts, sys_ts, err)) {
|
||||
*reading_mode = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,4 +41,9 @@ extern void SYS_Linux_SetScheduler(int SchedPriority);
|
||||
|
||||
extern int SYS_Linux_CheckKernelVersion(int req_major, int req_minor);
|
||||
|
||||
extern int SYS_Linux_OpenPHC(const char *path, int phc_index);
|
||||
|
||||
extern int SYS_Linux_GetPHCSample(int fd, int nocrossts, double precision, int *reading_mode,
|
||||
struct timespec *phc_ts, struct timespec *sys_ts, double *err);
|
||||
|
||||
#endif /* GOT_SYS_LINUX_H */
|
||||
|
||||
@@ -158,7 +158,8 @@ set_sync_status(int synchronised, double est_error, double max_error)
|
||||
txc.esterror = est_error * 1.0e6;
|
||||
txc.maxerror = max_error * 1.0e6;
|
||||
|
||||
SYS_Timex_Adjust(&txc, 1);
|
||||
if (SYS_Timex_Adjust(&txc, 1) < 0)
|
||||
;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -20,8 +20,8 @@ RMS offset : 0\.000...... seconds
|
||||
Frequency : (99|100)\.... ppm fast
|
||||
Residual freq : [+-][0-9]\.... ppm
|
||||
Skew : [0-9]\.... ppm
|
||||
Root delay : 0\.000... seconds
|
||||
Root dispersion : 0\.000... seconds
|
||||
Root delay : 0\.000...... seconds
|
||||
Root dispersion : 0\.000...... seconds
|
||||
Update interval : [0-9]+\.. seconds
|
||||
Leap status : Normal
|
||||
210 Number of sources = 1
|
||||
|
||||
@@ -25,13 +25,21 @@ time_offset=-10
|
||||
client_server_options="minpoll 6 maxpoll 6"
|
||||
client_conf="corrtimeratio 100"
|
||||
min_sync_time=8000
|
||||
max_sync_time=8500
|
||||
max_sync_time=9000
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
client_server_options="minpoll 6 maxpoll 6 xleave maxdelay 1e-1"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
client_server_options="minpoll 6 maxpoll 6"
|
||||
min_sync_time=$default_min_sync_time
|
||||
max_sync_time=$default_max_sync_time
|
||||
time_max_limit=11
|
||||
|
||||
@@ -31,7 +31,7 @@ test_unit(void)
|
||||
|
||||
LCL_Initialise();
|
||||
|
||||
clock = HCL_CreateInstance();
|
||||
clock = HCL_CreateInstance(1.0);
|
||||
|
||||
for (i = 0; i < 2000; i++) {
|
||||
UTI_ZeroTimespec(&start_hw_ts);
|
||||
@@ -43,7 +43,7 @@ test_unit(void)
|
||||
|
||||
freq = TST_GetRandomDouble(0.9, 1.1);
|
||||
jitter = TST_GetRandomDouble(10.0e-9, 1000.0e-9);
|
||||
interval = TST_GetRandomDouble(MIN_SAMPLE_SEPARATION / 10, MIN_SAMPLE_SEPARATION * 10.0);
|
||||
interval = TST_GetRandomDouble(0.1, 10.0);
|
||||
|
||||
clock->n_samples = 0;
|
||||
clock->valid_coefs = 0;
|
||||
@@ -68,5 +68,7 @@ test_unit(void)
|
||||
}
|
||||
}
|
||||
|
||||
HCL_DestroyInstance(clock);
|
||||
|
||||
LCL_Finalise();
|
||||
}
|
||||
|
||||
147
test/unit/keys.c
Normal file
147
test/unit/keys.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#include <keys.c>
|
||||
#include "test.h"
|
||||
|
||||
#define KEYS 100
|
||||
#define KEYFILE "keys.test-keys"
|
||||
|
||||
static
|
||||
uint32_t write_random_key(FILE *f)
|
||||
{
|
||||
const char *hash_name;
|
||||
char key[128];
|
||||
uint32_t id;
|
||||
int i, length;
|
||||
|
||||
length = random() % sizeof (key) + 1;
|
||||
length = MAX(length, 4);
|
||||
UTI_GetRandomBytes(&id, sizeof (id));
|
||||
UTI_GetRandomBytes(key, length);
|
||||
|
||||
switch (random() % 6) {
|
||||
#ifdef FEAT_SECHASH
|
||||
case 0:
|
||||
hash_name = "SHA1";
|
||||
break;
|
||||
case 1:
|
||||
hash_name = "SHA256";
|
||||
break;
|
||||
case 2:
|
||||
hash_name = "SHA384";
|
||||
break;
|
||||
case 3:
|
||||
hash_name = "SHA512";
|
||||
break;
|
||||
#endif
|
||||
case 4:
|
||||
hash_name = "MD5";
|
||||
break;
|
||||
default:
|
||||
hash_name = "";
|
||||
}
|
||||
|
||||
fprintf(f, "%u %s %s", id, hash_name, random() % 2 ? "HEX:" : "");
|
||||
for (i = 0; i < length; i++)
|
||||
fprintf(f, "%02hhX", key[i]);
|
||||
fprintf(f, "\n");
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void
|
||||
generate_key_file(const char *name, uint32_t *keys)
|
||||
{
|
||||
FILE *f;
|
||||
int i;
|
||||
|
||||
f = fopen(name, "w");
|
||||
TEST_CHECK(f);
|
||||
for (i = 0; i < KEYS; i++)
|
||||
keys[i] = write_random_key(f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
int i, j, data_len, auth_len;
|
||||
uint32_t keys[KEYS], key;
|
||||
unsigned char data[100], auth[MAX_HASH_LENGTH];
|
||||
char conf[][100] = {
|
||||
"keyfile "KEYFILE
|
||||
};
|
||||
|
||||
CNF_Initialise(0);
|
||||
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
|
||||
CNF_ParseLine(NULL, i + 1, conf[i]);
|
||||
|
||||
generate_key_file(KEYFILE, keys);
|
||||
KEY_Initialise();
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
DEBUG_LOG(0, "iteration %d", i);
|
||||
|
||||
if (i) {
|
||||
generate_key_file(KEYFILE, keys);
|
||||
KEY_Reload();
|
||||
}
|
||||
|
||||
UTI_GetRandomBytes(data, sizeof (data));
|
||||
|
||||
for (j = 0; j < KEYS; j++) {
|
||||
TEST_CHECK(KEY_KeyKnown(keys[j]));
|
||||
TEST_CHECK(KEY_GetAuthDelay(keys[j]) >= 0);
|
||||
TEST_CHECK(KEY_GetAuthLength(keys[j]) >= 16);
|
||||
|
||||
data_len = random() % (sizeof (data) + 1);
|
||||
auth_len = KEY_GenerateAuth(keys[j], data, data_len, auth, sizeof (auth));
|
||||
TEST_CHECK(auth_len >= 16);
|
||||
|
||||
TEST_CHECK(KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
|
||||
|
||||
if (j > 0 && keys[j - 1] != keys[j])
|
||||
TEST_CHECK(!KEY_CheckAuth(keys[j - 1], data, data_len, auth, auth_len, auth_len));
|
||||
|
||||
auth_len = random() % auth_len + 1;
|
||||
if (auth_len < MAX_HASH_LENGTH)
|
||||
auth[auth_len]++;
|
||||
TEST_CHECK(KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
|
||||
|
||||
auth[auth_len - 1]++;
|
||||
TEST_CHECK(!KEY_CheckAuth(keys[j], data, data_len, auth, auth_len, auth_len));
|
||||
}
|
||||
|
||||
for (j = 0; j < 1000; j++) {
|
||||
UTI_GetRandomBytes(&key, sizeof (key));
|
||||
if (KEY_KeyKnown(key))
|
||||
continue;
|
||||
TEST_CHECK(!KEY_GenerateAuth(j, data, data_len, auth, sizeof (auth)));
|
||||
TEST_CHECK(!KEY_CheckAuth(j, data, data_len, auth, auth_len, auth_len));
|
||||
}
|
||||
}
|
||||
|
||||
unlink(KEYFILE);
|
||||
|
||||
KEY_Finalise();
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
}
|
||||
299
test/unit/ntp_core.c
Normal file
299
test/unit/ntp_core.c
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2017
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <sysincl.h>
|
||||
#include <cmdparse.h>
|
||||
#include <conf.h>
|
||||
#include <keys.h>
|
||||
#include <ntp_io.h>
|
||||
#include <sched.h>
|
||||
#include <local.h>
|
||||
#include "test.h"
|
||||
|
||||
static struct timespec current_time;
|
||||
static NTP_Receive_Buffer req_buffer, res_buffer;
|
||||
static int req_length, res_length;
|
||||
|
||||
#define NIO_OpenServerSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 100 : 0)
|
||||
#define NIO_CloseServerSocket(fd) assert(fd == 100)
|
||||
#define NIO_OpenClientSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 101 : 0)
|
||||
#define NIO_CloseClientSocket(fd) assert(fd == 101)
|
||||
#define NIO_SendPacket(msg, to, from, len, process_tx) (memcpy(&req_buffer, msg, len), req_length = len, 1)
|
||||
#define SCH_AddTimeoutByDelay(delay, handler, arg) (1 ? 102 : (handler(arg), 1))
|
||||
#define SCH_AddTimeoutInClass(delay, separation, randomness, class, handler, arg) \
|
||||
add_timeout_in_class(delay, separation, randomness, class, handler, arg)
|
||||
#define SCH_RemoveTimeout(id) assert(!id || id == 102)
|
||||
#define LCL_ReadRawTime(ts) (*ts = current_time)
|
||||
#define LCL_ReadCookedTime(ts, err) do {double *p = err; *ts = current_time; if (p) *p = 0.0;} while (0)
|
||||
#define SRC_UpdateReachability(inst, reach)
|
||||
#define SRC_ResetReachability(inst)
|
||||
|
||||
static SCH_TimeoutID
|
||||
add_timeout_in_class(double min_delay, double separation, double randomness,
|
||||
SCH_TimeoutClass class, SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg)
|
||||
{
|
||||
return 102;
|
||||
}
|
||||
|
||||
#include <ntp_core.c>
|
||||
|
||||
static NCR_Instance inst;
|
||||
|
||||
static void
|
||||
advance_time(double x)
|
||||
{
|
||||
UTI_AddDoubleToTimespec(¤t_time, x, ¤t_time);
|
||||
}
|
||||
|
||||
static void
|
||||
send_request(void)
|
||||
{
|
||||
NTP_Local_Address local_addr;
|
||||
NTP_Local_Timestamp local_ts;
|
||||
uint32_t prev_tx_count;
|
||||
|
||||
prev_tx_count = inst->report.total_tx_count;
|
||||
|
||||
transmit_timeout(inst);
|
||||
TEST_CHECK(!inst->valid_rx);
|
||||
TEST_CHECK(!inst->updated_timestamps);
|
||||
TEST_CHECK(prev_tx_count + 1 == inst->report.total_tx_count);
|
||||
|
||||
advance_time(1e-4);
|
||||
|
||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
local_addr.if_index = INVALID_IF_INDEX;
|
||||
local_addr.sock_fd = 101;
|
||||
local_ts.ts = current_time;
|
||||
local_ts.err = 0.0;
|
||||
local_ts.source = NTP_TS_DAEMON;
|
||||
|
||||
NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer.ntp_pkt, req_length);
|
||||
}
|
||||
|
||||
static void
|
||||
send_response(int interleaved, int authenticated, int allow_update, int valid_ts, int valid_auth)
|
||||
{
|
||||
NTP_Packet *req, *res;
|
||||
|
||||
req = &req_buffer.ntp_pkt;
|
||||
res = &res_buffer.ntp_pkt;
|
||||
|
||||
TEST_CHECK(req_length >= NTP_NORMAL_PACKET_LENGTH);
|
||||
|
||||
res->lvm = NTP_LVM(LEAP_Normal, NTP_LVM_TO_VERSION(req->lvm),
|
||||
NTP_LVM_TO_MODE(req->lvm) == MODE_CLIENT ? MODE_SERVER : MODE_ACTIVE);
|
||||
res->stratum = 1;
|
||||
res->poll = req->poll;
|
||||
res->precision = -20;
|
||||
res->root_delay = UTI_DoubleToNtp32(0.1);
|
||||
res->root_dispersion = UTI_DoubleToNtp32(0.1);
|
||||
res->reference_id = 0;
|
||||
UTI_ZeroNtp64(&res->reference_ts);
|
||||
res->originate_ts = interleaved ? req->receive_ts : req->transmit_ts;
|
||||
|
||||
advance_time(TST_GetRandomDouble(1e-4, 1e-2));
|
||||
UTI_TimespecToNtp64(¤t_time, &res->receive_ts, NULL);
|
||||
advance_time(TST_GetRandomDouble(-1e-4, 1e-3));
|
||||
UTI_TimespecToNtp64(¤t_time, &res->transmit_ts, NULL);
|
||||
advance_time(TST_GetRandomDouble(1e-4, 1e-2));
|
||||
|
||||
if (!valid_ts) {
|
||||
switch (random() % (allow_update ? 4 : 5)) {
|
||||
case 0:
|
||||
res->originate_ts.hi = random();
|
||||
break;
|
||||
case 1:
|
||||
res->originate_ts.lo = random();
|
||||
break;
|
||||
case 2:
|
||||
UTI_ZeroNtp64(&res->originate_ts);
|
||||
break;
|
||||
case 3:
|
||||
UTI_ZeroNtp64(&res->receive_ts);
|
||||
break;
|
||||
case 4:
|
||||
UTI_ZeroNtp64(&res->transmit_ts);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (authenticated) {
|
||||
res->auth_keyid = req->auth_keyid;
|
||||
KEY_GenerateAuth(ntohl(res->auth_keyid), (unsigned char *)res, NTP_NORMAL_PACKET_LENGTH,
|
||||
res->auth_data, 16);
|
||||
res_length = NTP_NORMAL_PACKET_LENGTH + 4 + 16;
|
||||
} else {
|
||||
res_length = NTP_NORMAL_PACKET_LENGTH;
|
||||
}
|
||||
|
||||
if (!valid_auth) {
|
||||
switch (random() % 3) {
|
||||
case 0:
|
||||
res->auth_keyid++;
|
||||
break;
|
||||
case 1:
|
||||
res->auth_data[random() % 16]++;
|
||||
break;
|
||||
case 2:
|
||||
res_length = NTP_NORMAL_PACKET_LENGTH;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
process_response(int valid, int updated)
|
||||
{
|
||||
NTP_Local_Address local_addr;
|
||||
NTP_Local_Timestamp local_ts;
|
||||
NTP_Packet *res;
|
||||
uint32_t prev_rx_count, prev_valid_count;
|
||||
struct timespec prev_rx_ts;
|
||||
int prev_open_socket;
|
||||
|
||||
res = &res_buffer.ntp_pkt;
|
||||
|
||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
local_addr.if_index = INVALID_IF_INDEX;
|
||||
local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) == MODE_ACTIVE ? 100 : 101;
|
||||
local_ts.ts = current_time;
|
||||
local_ts.err = 0.0;
|
||||
local_ts.source = NTP_TS_DAEMON;
|
||||
|
||||
prev_rx_count = inst->report.total_rx_count;
|
||||
prev_valid_count = inst->report.total_valid_count;
|
||||
prev_rx_ts = inst->local_rx.ts;
|
||||
prev_open_socket = inst->local_addr.sock_fd != INVALID_SOCK_FD;
|
||||
|
||||
NCR_ProcessRxKnown(inst, &local_addr, &local_ts, res, res_length);
|
||||
|
||||
if (prev_open_socket)
|
||||
TEST_CHECK(prev_rx_count + 1 == inst->report.total_rx_count);
|
||||
else
|
||||
TEST_CHECK(prev_rx_count == inst->report.total_rx_count);
|
||||
|
||||
if (valid)
|
||||
TEST_CHECK(prev_valid_count + 1 == inst->report.total_valid_count);
|
||||
else
|
||||
TEST_CHECK(prev_valid_count == inst->report.total_valid_count);
|
||||
|
||||
if (updated)
|
||||
TEST_CHECK(UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
|
||||
else
|
||||
TEST_CHECK(!UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
|
||||
}
|
||||
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
char source_line[] = "127.0.0.1";
|
||||
char conf[][100] = {
|
||||
"port 0",
|
||||
"keyfile ntp_core.keys"
|
||||
};
|
||||
int i, j, interleaved, authenticated, valid, updated, has_updated;
|
||||
CPS_NTP_Source source;
|
||||
NTP_Remote_Address remote_addr;
|
||||
|
||||
CNF_Initialise(0);
|
||||
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
|
||||
CNF_ParseLine(NULL, i + 1, conf[i]);
|
||||
|
||||
LCL_Initialise();
|
||||
TST_RegisterDummyDrivers();
|
||||
SCH_Initialise();
|
||||
SRC_Initialise();
|
||||
NIO_Initialise(IPADDR_UNSPEC);
|
||||
NCR_Initialise();
|
||||
REF_Initialise();
|
||||
KEY_Initialise();
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
CPS_ParseNTPSourceAdd(source_line, &source);
|
||||
if (random() % 2)
|
||||
source.params.interleaved = 1;
|
||||
if (random() % 2)
|
||||
source.params.authkey = 1;
|
||||
|
||||
UTI_ZeroTimespec(¤t_time);
|
||||
advance_time(TST_GetRandomDouble(1.0, 1e9));
|
||||
|
||||
TST_GetRandomAddress(&remote_addr.ip_addr, IPADDR_UNSPEC, -1);
|
||||
remote_addr.port = 123;
|
||||
|
||||
inst = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
|
||||
NCR_StartInstance(inst);
|
||||
has_updated = 0;
|
||||
|
||||
for (j = 0; j < 50; j++) {
|
||||
DEBUG_LOG(0, "iteration %d, %d", i, j);
|
||||
|
||||
interleaved = random() % 2;
|
||||
authenticated = random() % 2;
|
||||
valid = (!interleaved || (source.params.interleaved && has_updated)) &&
|
||||
(!source.params.authkey || authenticated);
|
||||
updated = (valid || inst->mode == MODE_ACTIVE) &&
|
||||
(!source.params.authkey || authenticated);
|
||||
has_updated = has_updated || updated;
|
||||
|
||||
send_request();
|
||||
|
||||
send_response(interleaved, authenticated, 1, 0, 1);
|
||||
process_response(0, inst->mode == MODE_CLIENT ? 0 : updated);
|
||||
|
||||
if (source.params.authkey) {
|
||||
send_response(interleaved, authenticated, 1, 1, 0);
|
||||
process_response(0, 0);
|
||||
}
|
||||
|
||||
send_response(interleaved, authenticated, 1, 1, 1);
|
||||
process_response(valid, updated);
|
||||
process_response(0, 0);
|
||||
|
||||
advance_time(-1.0);
|
||||
|
||||
send_response(interleaved, authenticated, 1, 1, 1);
|
||||
process_response(0, 0);
|
||||
|
||||
advance_time(1.0);
|
||||
|
||||
send_response(interleaved, authenticated, 1, 1, 1);
|
||||
process_response(0, inst->mode == MODE_CLIENT ? 0 : updated);
|
||||
}
|
||||
|
||||
NCR_DestroyInstance(inst);
|
||||
}
|
||||
|
||||
KEY_Finalise();
|
||||
REF_Finalise();
|
||||
NCR_Finalise();
|
||||
NIO_Finalise();
|
||||
SRC_Finalise();
|
||||
SCH_Finalise();
|
||||
LCL_Finalise();
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
}
|
||||
2
test/unit/ntp_core.keys
Normal file
2
test/unit/ntp_core.keys
Normal file
@@ -0,0 +1,2 @@
|
||||
1 MD5 HEX:38979C567358C0896F4D9D459A3C8B8478654579
|
||||
2 MD5 HEX:38979C567358C0896F4D9D459A3C8B8478654579
|
||||
@@ -96,4 +96,5 @@ test_unit(void)
|
||||
SCH_Finalise();
|
||||
LCL_Finalise();
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
}
|
||||
|
||||
@@ -134,4 +134,5 @@ test_unit(void)
|
||||
SCH_Finalise();
|
||||
LCL_Finalise();
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
}
|
||||
|
||||
@@ -74,6 +74,14 @@ void test_unit(void) {
|
||||
TEST_CHECK(!UTI_IsZeroTimespec(&ts));
|
||||
TEST_CHECK(!UTI_IsZeroNtp64(&ntp_ts));
|
||||
|
||||
ntp_ts.hi = 0;
|
||||
ntp_ts.lo = 0;
|
||||
|
||||
UTI_Ntp64ToTimespec(&ntp_ts, &ts);
|
||||
TEST_CHECK(UTI_IsZeroTimespec(&ts));
|
||||
UTI_TimespecToNtp64(&ts, &ntp_ts, NULL);
|
||||
TEST_CHECK(UTI_IsZeroNtp64(&ntp_ts));
|
||||
|
||||
ntp_fuzz.hi = htonl(1);
|
||||
ntp_fuzz.lo = htonl(3);
|
||||
ntp_ts.hi = htonl(1);
|
||||
|
||||
11
util.c
11
util.c
@@ -329,12 +329,14 @@ UTI_StringToIP(const char *addr, IPAddr *ip)
|
||||
|
||||
if (inet_pton(AF_INET, addr, &in4) > 0) {
|
||||
ip->family = IPADDR_INET4;
|
||||
ip->_pad = 0;
|
||||
ip->addr.in4 = ntohl(in4.s_addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET6, addr, &in6) > 0) {
|
||||
ip->family = IPADDR_INET6;
|
||||
ip->_pad = 0;
|
||||
memcpy(ip->addr.in6, in6.s6_addr, sizeof (ip->addr.in6));
|
||||
return 1;
|
||||
}
|
||||
@@ -344,6 +346,7 @@ UTI_StringToIP(const char *addr, IPAddr *ip)
|
||||
n = sscanf(addr, "%lu.%lu.%lu.%lu", &a, &b, &c, &d);
|
||||
if (n == 4) {
|
||||
ip->family = IPADDR_INET4;
|
||||
ip->_pad = 0;
|
||||
ip->addr.in4 = ((a & 0xff) << 24) | ((b & 0xff) << 16) |
|
||||
((c & 0xff) << 8) | (d & 0xff);
|
||||
return 1;
|
||||
@@ -442,6 +445,7 @@ void
|
||||
UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest)
|
||||
{
|
||||
dest->family = ntohs(src->family);
|
||||
dest->_pad = 0;
|
||||
|
||||
switch (dest->family) {
|
||||
case IPADDR_INET4:
|
||||
@@ -754,8 +758,11 @@ UTI_Ntp64ToTimespec(NTP_int64 *src, struct timespec *dest)
|
||||
{
|
||||
uint32_t ntp_sec, ntp_frac;
|
||||
|
||||
/* As yet, there is no need to check for zero - all processing that
|
||||
has to detect that case is in the NTP layer */
|
||||
/* Zero is a special value */
|
||||
if (UTI_IsZeroNtp64(src)) {
|
||||
UTI_ZeroTimespec(dest);
|
||||
return;
|
||||
}
|
||||
|
||||
ntp_sec = ntohl(src->hi);
|
||||
ntp_frac = ntohl(src->lo);
|
||||
|
||||
Reference in New Issue
Block a user