mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 17:35:06 -05:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fe4a60a1d | ||
|
|
2da8fbc4c3 | ||
|
|
c252e52ee2 | ||
|
|
c8a9ca4cf0 | ||
|
|
4659b574bf | ||
|
|
5436618c05 | ||
|
|
a0f460569e | ||
|
|
3c39afa13c | ||
|
|
03875f1ea5 | ||
|
|
2e29935c54 | ||
|
|
8084961011 | ||
|
|
120bf44989 | ||
|
|
9e8541e3c4 | ||
|
|
e95d5a161d | ||
|
|
2c63dfee34 | ||
|
|
42e6b5577a | ||
|
|
830c8bb18a | ||
|
|
0289442998 |
6
client.c
6
client.c
@@ -270,7 +270,7 @@ open_unix_socket(char *server_path)
|
||||
if (snprintf(sock_dir1, sizeof (sock_dir1),
|
||||
"%s/chronyc.%d", sock_dir0, (int)getpid()) >= sizeof (sock_dir1) ||
|
||||
snprintf(sock_dir2, sizeof (sock_dir2),
|
||||
"%s/%s", sock_dir1, rand_dir) >= sizeof (sock_dir1) ||
|
||||
"%s/%s", sock_dir1, rand_dir) >= sizeof (sock_dir2) ||
|
||||
snprintf(sock_path, sizeof (sock_path),
|
||||
"%s/sock", sock_dir2) >= sizeof (sock_path)) {
|
||||
LOG(LOGS_ERR, "Server socket path %s is too long", server_path);
|
||||
@@ -2576,10 +2576,10 @@ process_cmd_selectdata(char *line)
|
||||
n_sources = ntohl(reply.data.n_sources.n_sources);
|
||||
|
||||
if (verbose) {
|
||||
printf( " . State: N - noselect, s - unsynchronised, M - missing samples,\n");
|
||||
printf( " . State: N - noselect, s - unsynchronised, M - missing samples, r - stratum\n");
|
||||
printf( " / d/D - large distance, ~ - jittery, w/W - waits for others,\n");
|
||||
printf( "| S - stale, O - orphan, T - not trusted, P - not preferred,\n");
|
||||
printf( "| U - waits for update,, x - falseticker, + - combined, * - best.\n");
|
||||
printf( "| U - waits for update, x - falseticker, + - combined, * - best.\n");
|
||||
printf( "| Effective options ---------. (N - noselect, P - prefer\n");
|
||||
printf( "| Configured options ----. \\ T - trust, R - require)\n");
|
||||
printf( "| Auth. enabled (Y/N) -. \\ \\ Offset interval --.\n");
|
||||
|
||||
22
conf.c
22
conf.c
@@ -115,6 +115,8 @@ static double clock_precision = 0.0; /* in seconds */
|
||||
static SRC_AuthSelectMode authselect_mode = SRC_AUTHSELECT_MIX;
|
||||
static double max_distance = 3.0;
|
||||
static double max_jitter = 1.0;
|
||||
static int max_stratum = NTP_MAX_STRATUM - 1;
|
||||
static int min_stratum = 0;
|
||||
static double reselect_distance = 1e-4;
|
||||
static double stratum_weight = 1e-3;
|
||||
static double combine_limit = 3.0;
|
||||
@@ -702,12 +704,16 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
parse_int(p, &max_samples, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "maxslewrate")) {
|
||||
parse_double(p, &max_slew_rate);
|
||||
} else if (!strcasecmp(command, "maxstratum")) {
|
||||
parse_int(p, &max_stratum, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "maxupdateskew")) {
|
||||
parse_double(p, &max_update_skew);
|
||||
} else if (!strcasecmp(command, "minsamples")) {
|
||||
parse_int(p, &min_samples, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "minsources")) {
|
||||
parse_int(p, &min_sources, 1, INT_MAX);
|
||||
} else if (!strcasecmp(command, "minstratum")) {
|
||||
parse_int(p, &min_stratum, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "nocerttimecheck")) {
|
||||
parse_int(p, &no_cert_time_check, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "noclientlog")) {
|
||||
@@ -2311,6 +2317,22 @@ CNF_GetMaxJitter(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetMaxStratum(void)
|
||||
{
|
||||
return max_stratum;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetMinStratum(void)
|
||||
{
|
||||
return min_stratum;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
CNF_GetReselectDistance(void)
|
||||
{
|
||||
|
||||
2
conf.h
2
conf.h
@@ -106,6 +106,8 @@ extern double CNF_GetClockPrecision(void);
|
||||
extern SRC_AuthSelectMode CNF_GetAuthSelectMode(void);
|
||||
extern double CNF_GetMaxDistance(void);
|
||||
extern double CNF_GetMaxJitter(void);
|
||||
extern int CNF_GetMaxStratum(void);
|
||||
extern int CNF_GetMinStratum(void);
|
||||
extern double CNF_GetReselectDistance(void);
|
||||
extern double CNF_GetStratumWeight(void);
|
||||
extern double CNF_GetCombineLimit(void);
|
||||
|
||||
1
configure
vendored
1
configure
vendored
@@ -808,6 +808,7 @@ then
|
||||
# a time and the async resolver would block the main thread
|
||||
priv_ops="NAME2IPADDRESS RELOADDNS"
|
||||
EXTRA_LIBS="$EXTRA_LIBS -lseccomp"
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS sys_linux_scmp.o"
|
||||
fi
|
||||
|
||||
if [ "x$priv_ops" != "x" ]; then
|
||||
|
||||
@@ -71,8 +71,10 @@ also when the <<chronyc.adoc#online,*online*>> command is issued in *chronyc*.
|
||||
The DNS record can change over time. The used address will be replaced with a
|
||||
newly resolved address when the server becomes unreachable (i.e. no valid
|
||||
response to the last 8 requests), unsynchronised, a falseticker (i.e. does not
|
||||
agree with a majority of other sources), or the root distance is too large (the
|
||||
limit can be configured by the <<maxdistance,*maxdistance*>> directive). The
|
||||
agree with a majority of other sources), the root distance is too large (the
|
||||
limit can be configured by the <<maxdistance,*maxdistance*>> directive), or
|
||||
the stratum is too small or too large (the limits can be configured by the
|
||||
<<minstratum,*minstratum*>> and <<maxstratum,*maxstratum*>> directives). The
|
||||
automatic replacement happens at most once per 30 minutes and only one
|
||||
server can be replaced at a time. The address is also refreshed periodically
|
||||
when the server is working normally (the interval can be configured by the
|
||||
@@ -318,7 +320,8 @@ with lower stratum are normally slightly preferred. This option can be used to
|
||||
increase stratum of the source to the specified minimum, so *chronyd* will
|
||||
avoid selecting that source. This is useful with low-stratum sources that are
|
||||
known to be unreliable or inaccurate and that should be used only when other
|
||||
sources are unreachable.
|
||||
sources are unreachable. Note that the <<minstratum,*minstratum*>> directive
|
||||
is distinct from this option.
|
||||
*version* _version_:::
|
||||
This option sets the NTP version of packets sent to the server. This can be
|
||||
useful when the server runs an old NTP implementation that does not respond to
|
||||
@@ -1102,6 +1105,16 @@ with sources that have a small root distance, but their time is too variable.
|
||||
+
|
||||
By default, the maximum jitter is 1 second.
|
||||
|
||||
[[maxstratum]]*maxstratum* _stratum_::
|
||||
The *maxstratum* directive sets the maximum allowed stratum of the sources to
|
||||
be selected for synchronisation. The default value is 15. The useful range is 0
|
||||
to 15.
|
||||
|
||||
[[minstratum]]*minstratum* _stratum_::
|
||||
The *minstratum* directive sets the minimum allowed stratum of the sources to
|
||||
be selected for synchronisation. The default value is 0. The useful range is 0
|
||||
to 15.
|
||||
|
||||
[[minsources]]*minsources* _sources_::
|
||||
The *minsources* directive sets the minimum number of sources that need to be
|
||||
considered as selectable in the source selection algorithm before the local
|
||||
@@ -1133,23 +1146,29 @@ distances are in milliseconds.
|
||||
|
||||
[[clockprecision]]*clockprecision* _precision_::
|
||||
The *clockprecision* directive specifies the precision of the system clock (in
|
||||
seconds). It is used by *chronyd* to estimate the minimum noise in NTP
|
||||
measurements and randomise low-order bits of timestamps in NTP responses. By
|
||||
default, the precision is measured on start-up as the minimum time to read the
|
||||
clock.
|
||||
seconds). This value is used by *chronyd* as the minimum expected error and
|
||||
amount of noise in NTP and refclock measurements, and to randomise low-order
|
||||
bits of timestamps in NTP responses to make them less predictable. The minimum
|
||||
value is 1 nanosecond and the maximum value is 1 second.
|
||||
+
|
||||
The measured value works well in most cases. It generally overestimates the
|
||||
precision and it can be sensitive to the CPU speed, however, which can
|
||||
change over time to save power. In some cases with a high-precision clocksource
|
||||
(e.g. the Time Stamp Counter of the CPU) and hardware timestamping, setting the
|
||||
precision on the server to a smaller value can improve stability of clients'
|
||||
NTP measurements. The server's precision is reported on clients by the
|
||||
By default, *chronyd* tries to determine the precision on start-up as the
|
||||
resolution of the clock. On Linux, it tries to measure the resolution by
|
||||
observing the minimum change in differences between consecutive readings of the
|
||||
clock. On other systems it relies on the *clock_getres(2)* system function.
|
||||
+
|
||||
If the measurement fails, or the value provided by the system is too large, the
|
||||
minimum measured time needed to read the clock will be used instead. This value
|
||||
is typically larger than the resolution, and it is sensitive to the CPU speed,
|
||||
however, which can change over time to save power.
|
||||
+
|
||||
The server's precision is reported on clients by the
|
||||
<<chronyc.adoc#ntpdata,*ntpdata*>> command.
|
||||
+
|
||||
An example setting the precision to 8 nanoseconds is:
|
||||
An example setting the precision to 1 nanosecond (e.g. when the system clock is
|
||||
using a Time Stamp Counter (TSC) updated at a rate of at least 1 GHz) is:
|
||||
+
|
||||
----
|
||||
clockprecision 8e-9
|
||||
clockprecision 1e-9
|
||||
----
|
||||
|
||||
[[corrtimeratio]]*corrtimeratio* _ratio_::
|
||||
@@ -2444,6 +2463,9 @@ Not considered selectable for synchronisation:
|
||||
* _N_ - has the *noselect* option.
|
||||
* _s_ - is not synchronised.
|
||||
* _M_ - does not have enough measurements.
|
||||
* _r_ - has a stratum outside of the allowed range (configured by the
|
||||
<<minstratum,*minstratum*>> and <<maxstratum,*maxstratum*>>
|
||||
directives).
|
||||
* _d_ - has a root distance larger than the maximum distance (configured by the
|
||||
<<maxdistance,*maxdistance*>> directive).
|
||||
* _~_ - has a jitter larger than the maximum jitter (configured by the
|
||||
|
||||
@@ -474,6 +474,9 @@ synchronisation:
|
||||
* _N_ - has the *noselect* option.
|
||||
* _M_ - does not have enough measurements.
|
||||
* _s_ - is not synchronised.
|
||||
* _r_ - has a stratum outside of the allowed range (configured by the
|
||||
<<chrony.conf.adoc#minstratum,*minstratum*>> and
|
||||
<<chrony.conf.adoc#maxstratum,*maxstratum*>> directives).
|
||||
* _d_ - has a root distance larger than the maximum distance (configured by the
|
||||
<<chrony.conf.adoc#maxdistance,*maxdistance*>> directive).
|
||||
* _~_ - has a jitter larger than the maximum jitter (configured by the
|
||||
|
||||
2
leapdb.c
2
leapdb.c
@@ -130,7 +130,7 @@ get_list_leap(time_t when, int *tai_offset)
|
||||
char *p;
|
||||
|
||||
/* Ignore blank lines */
|
||||
for (p = line; *p && isspace(*p); ++p)
|
||||
for (p = line; *p && isspace((unsigned char)*p); ++p)
|
||||
;
|
||||
if (!*p)
|
||||
continue;
|
||||
|
||||
163
local.c
163
local.c
@@ -97,8 +97,142 @@ static double precision_quantum;
|
||||
|
||||
static double max_clock_error;
|
||||
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Ask the system for the resolution of the system clock. The Linux
|
||||
clock_getres() is not usable, because it reports the internal timer
|
||||
resolution, which is 1 ns when high-resolution timers are enabled,
|
||||
even when using a lower-resolution clocksource. */
|
||||
|
||||
static int
|
||||
get_clock_resolution(void)
|
||||
{
|
||||
#if defined(HAVE_CLOCK_GETTIME) && !defined(LINUX)
|
||||
struct timespec res;
|
||||
|
||||
if (clock_getres(CLOCK_REALTIME, &res) < 0)
|
||||
return 0;
|
||||
|
||||
return NSEC_PER_SEC * res.tv_sec + res.tv_nsec;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(LINUX) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC_RAW)
|
||||
|
||||
static int
|
||||
compare_ints(const void *a, const void *b)
|
||||
{
|
||||
return *(const int *)a - *(const int *)b;
|
||||
}
|
||||
|
||||
#define READINGS 64
|
||||
|
||||
/* On Linux, try to measure the actual resolution of the system
|
||||
clock by performing a varying amount of busy work between clock
|
||||
readings and finding the minimum change in the measured interval.
|
||||
Require a change of at least two nanoseconds to ignore errors
|
||||
caused by conversion to timespec. Use the raw monotonic clock
|
||||
to avoid the impact of potential frequency changes due to NTP
|
||||
adjustments made by other processes, and the kernel dithering of
|
||||
the 32-bit multiplier. */
|
||||
|
||||
static int
|
||||
measure_clock_resolution(void)
|
||||
{
|
||||
int i, j, b, busy, diffs[READINGS - 1], diff2, min;
|
||||
struct timespec start_ts, ts[READINGS];
|
||||
uint32_t acc;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_ts) < 0)
|
||||
return 0;
|
||||
|
||||
for (acc = 0, busy = 1; busy < 100000; busy = busy * 3 / 2 + 1) {
|
||||
for (i = 0, b = busy * READINGS; i < READINGS; i++, b -= busy) {
|
||||
if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts[i]) < 0)
|
||||
return 0;
|
||||
|
||||
for (j = b; j > 0; j--)
|
||||
acc += (acc & 1) + (uint32_t)ts[i].tv_nsec;
|
||||
}
|
||||
|
||||
/* Give up after 0.1 seconds */
|
||||
if (UTI_DiffTimespecsToDouble(&ts[READINGS - 1], &start_ts) > 0.1) {
|
||||
DEBUG_LOG("Measurement too slow");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < READINGS - 1; i++) {
|
||||
diffs[i] = NSEC_PER_SEC * (ts[i + 1].tv_sec - ts[i].tv_sec) +
|
||||
(ts[i + 1].tv_nsec - ts[i].tv_nsec);
|
||||
|
||||
/* Make sure the differences are sane. A resolution larger than the
|
||||
reading time will be measured in measure_clock_read_delay(). */
|
||||
if (diffs[i] <= 0 || diffs[i] > NSEC_PER_SEC)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sort the differences and keep values unique within 1 ns from the
|
||||
first half of the array, which are less likely to be impacted by CPU
|
||||
interruptions */
|
||||
qsort(diffs, READINGS - 1, sizeof (diffs[0]), compare_ints);
|
||||
for (i = 1, j = 0; i < READINGS / 2; i++) {
|
||||
if (diffs[j] + 1 < diffs[i])
|
||||
diffs[++j] = diffs[i];
|
||||
}
|
||||
j++;
|
||||
|
||||
#if 0
|
||||
for (i = 0; i < j; i++)
|
||||
DEBUG_LOG("busy %d diff %d %d", busy, i, diffs[i]);
|
||||
#endif
|
||||
|
||||
/* Require at least three unique differences to be more confident
|
||||
with the result */
|
||||
if (j < 3)
|
||||
continue;
|
||||
|
||||
/* Find the smallest difference between the unique differences */
|
||||
for (i = 1, min = 0; i < j; i++) {
|
||||
diff2 = diffs[i] - diffs[i - 1];
|
||||
if (min == 0 || min > diff2)
|
||||
min = diff2;
|
||||
}
|
||||
|
||||
if (min == 0)
|
||||
continue;
|
||||
|
||||
/* Prevent the compiler from optimising the busy work out */
|
||||
if (acc == 0)
|
||||
min += 1;
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static int
|
||||
measure_clock_resolution(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* As a fallback, measure how long it takes to read the clock. It
|
||||
typically takes longer than the resolution of the clock (and it
|
||||
depends on the CPU speed), i.e. every reading gives a different
|
||||
value, but handle also low-resolution clocks that might give
|
||||
the same reading multiple times. */
|
||||
|
||||
/* Define the number of increments of the system clock that we want
|
||||
to see to be fairly sure that we've got something approaching
|
||||
the minimum increment. Even on a crummy implementation that can't
|
||||
@@ -106,10 +240,8 @@ static double max_clock_error;
|
||||
under 1s of busy waiting. */
|
||||
#define NITERS 100
|
||||
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
|
||||
static double
|
||||
measure_clock_precision(void)
|
||||
static int
|
||||
measure_clock_read_delay(void)
|
||||
{
|
||||
struct timespec ts, old_ts;
|
||||
int iters, diff, best;
|
||||
@@ -135,7 +267,28 @@ measure_clock_precision(void)
|
||||
|
||||
assert(best > 0);
|
||||
|
||||
return 1.0e-9 * best;
|
||||
return best;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static double
|
||||
measure_clock_precision(void)
|
||||
{
|
||||
int res, delay, prec;
|
||||
|
||||
res = get_clock_resolution();
|
||||
if (res <= 0)
|
||||
res = measure_clock_resolution();
|
||||
|
||||
delay = measure_clock_read_delay();
|
||||
|
||||
if (res > 0)
|
||||
prec = MIN(res, delay);
|
||||
else
|
||||
prec = delay;
|
||||
|
||||
return prec / 1.0e9;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
45
sources.c
45
sources.c
@@ -54,7 +54,6 @@ static int initialised = 0;
|
||||
/* ================================================== */
|
||||
/* Structure used to hold info for selecting between sources */
|
||||
struct SelectInfo {
|
||||
int select_ok;
|
||||
double std_dev;
|
||||
double root_distance;
|
||||
double lo_limit;
|
||||
@@ -70,6 +69,7 @@ typedef enum {
|
||||
SRC_UNSELECTABLE, /* Has noselect option set */
|
||||
SRC_BAD_STATS, /* Doesn't have valid stats data */
|
||||
SRC_UNSYNCHRONISED, /* Provides samples, but not synchronised */
|
||||
SRC_BAD_STRATUM, /* Has stratum outside of allowed range */
|
||||
SRC_BAD_DISTANCE, /* Has root distance longer than allowed maximum */
|
||||
SRC_JITTERY, /* Had std dev larger than allowed maximum */
|
||||
SRC_WAITS_STATS, /* Others have bad stats, selection postponed */
|
||||
@@ -198,6 +198,8 @@ static int forced_first_report; /* Flag to allow one failed selection to be
|
||||
|
||||
static double max_distance;
|
||||
static double max_jitter;
|
||||
static int max_stratum;
|
||||
static int min_stratum;
|
||||
static double reselect_distance;
|
||||
static double stratum_weight;
|
||||
static double combine_limit;
|
||||
@@ -231,6 +233,8 @@ void SRC_Initialise(void) {
|
||||
selected_source_index = INVALID_SOURCE;
|
||||
max_distance = CNF_GetMaxDistance();
|
||||
max_jitter = CNF_GetMaxJitter();
|
||||
max_stratum = CNF_GetMaxStratum();
|
||||
min_stratum = CNF_GetMinStratum();
|
||||
reselect_distance = CNF_GetReselectDistance();
|
||||
stratum_weight = CNF_GetStratumWeight();
|
||||
combine_limit = CNF_GetCombineLimit();
|
||||
@@ -739,7 +743,8 @@ set_source_status(SRC_Instance inst, SRC_Status status)
|
||||
distance or jitter larger than the allowed maximums */
|
||||
if (inst == last_updated_inst) {
|
||||
if (inst->bad < INT_MAX &&
|
||||
(status == SRC_FALSETICKER || status == SRC_BAD_DISTANCE || status == SRC_JITTERY))
|
||||
(status == SRC_FALSETICKER || status == SRC_BAD_DISTANCE ||
|
||||
status == SRC_BAD_STRATUM || status == SRC_JITTERY))
|
||||
inst->bad++;
|
||||
else
|
||||
inst->bad = 0;
|
||||
@@ -783,6 +788,14 @@ mark_source(SRC_Instance inst, SRC_Status status)
|
||||
|
||||
if (!inst->reported_status[status]) {
|
||||
switch (status) {
|
||||
case SRC_BAD_STRATUM:
|
||||
if (inst->bad < BAD_HANDLE_THRESHOLD)
|
||||
break;
|
||||
log_selection_source(LOGS_WARN, inst,
|
||||
"Stratum of ## %sstratum of %d",
|
||||
inst->stratum < min_stratum ? "below min" : "above max",
|
||||
inst->stratum < min_stratum ? min_stratum : max_stratum);
|
||||
break;
|
||||
case SRC_BAD_DISTANCE:
|
||||
if (inst->bad < BAD_HANDLE_THRESHOLD)
|
||||
break;
|
||||
@@ -955,7 +968,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
int max_badstat_reach, max_badstat_reach_size, n_badstats_sources;
|
||||
int max_sel_reach, max_sel_reach_size, n_unreach_sources;
|
||||
int depth, best_depth, trust_depth, best_trust_depth, n_sel_trust_sources;
|
||||
int combined, stratum, min_stratum, max_score_index;
|
||||
int combined, stratum, min_sel_stratum, max_score_index;
|
||||
int orphan_stratum, orphan_source;
|
||||
double src_offset, src_offset_sd, src_frequency, src_frequency_sd, src_skew;
|
||||
double src_root_delay, src_root_dispersion;
|
||||
@@ -1010,12 +1023,10 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
n_unreach_sources++;
|
||||
|
||||
si = &sources[i]->sel_info;
|
||||
SST_GetSelectionData(sources[i]->stats, &now,
|
||||
&si->lo_limit, &si->hi_limit, &si->root_distance,
|
||||
&si->std_dev, &first_sample_ago,
|
||||
&si->last_sample_ago, &si->select_ok);
|
||||
|
||||
if (!si->select_ok) {
|
||||
if (!SST_GetSelectionData(sources[i]->stats, &now, &si->lo_limit, &si->hi_limit,
|
||||
&si->root_distance, &si->std_dev, &first_sample_ago,
|
||||
&si->last_sample_ago)) {
|
||||
++n_badstats_sources;
|
||||
mark_source(sources[i], SRC_BAD_STATS);
|
||||
if (max_badstat_reach < sources[i]->reachability)
|
||||
@@ -1031,6 +1042,12 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Require the stratum to be in the allowed range */
|
||||
if (sources[i]->stratum < min_stratum || sources[i]->stratum > max_stratum) {
|
||||
mark_source(sources[i], SRC_BAD_STRATUM);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Include extra dispersion in the root distance of sources that don't
|
||||
have new samples (the last sample is older than span of all samples) */
|
||||
if (first_sample_ago < 2.0 * si->last_sample_ago) {
|
||||
@@ -1364,12 +1381,12 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
/* Find minimum stratum */
|
||||
|
||||
index = sel_sources[0];
|
||||
min_stratum = sources[index]->stratum;
|
||||
min_sel_stratum = sources[index]->stratum;
|
||||
for (i = 1; i < n_sel_sources; i++) {
|
||||
index = sel_sources[i];
|
||||
stratum = sources[index]->stratum;
|
||||
if (stratum < min_stratum)
|
||||
min_stratum = stratum;
|
||||
if (min_sel_stratum > stratum)
|
||||
min_sel_stratum = stratum;
|
||||
}
|
||||
|
||||
/* Update scores and find the source with maximum score */
|
||||
@@ -1380,7 +1397,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
|
||||
if (selected_source_index != INVALID_SOURCE)
|
||||
sel_src_distance = sources[selected_source_index]->sel_info.root_distance +
|
||||
(sources[selected_source_index]->stratum - min_stratum) * stratum_weight;
|
||||
(sources[selected_source_index]->stratum - min_sel_stratum) * stratum_weight;
|
||||
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
/* Reset score for non-selectable sources */
|
||||
@@ -1392,7 +1409,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
}
|
||||
|
||||
distance = sources[i]->sel_info.root_distance +
|
||||
(sources[i]->stratum - min_stratum) * stratum_weight;
|
||||
(sources[i]->stratum - min_sel_stratum) * stratum_weight;
|
||||
if (sources[i]->type == SRC_NTP)
|
||||
distance += reselect_distance;
|
||||
|
||||
@@ -1917,6 +1934,8 @@ get_status_char(SRC_Status status)
|
||||
return 'M';
|
||||
case SRC_UNSYNCHRONISED:
|
||||
return 's';
|
||||
case SRC_BAD_STRATUM:
|
||||
return 'r';
|
||||
case SRC_BAD_DISTANCE:
|
||||
return 'd';
|
||||
case SRC_JITTERY:
|
||||
|
||||
@@ -644,22 +644,16 @@ SST_GetFrequencyRange(SST_Stats inst,
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SST_GetSelectionData(SST_Stats inst, struct timespec *now,
|
||||
double *offset_lo_limit,
|
||||
double *offset_hi_limit,
|
||||
double *root_distance,
|
||||
double *std_dev,
|
||||
double *first_sample_ago,
|
||||
double *last_sample_ago,
|
||||
int *select_ok)
|
||||
int
|
||||
SST_GetSelectionData(SST_Stats inst, struct timespec *now, double *offset_lo_limit,
|
||||
double *offset_hi_limit, double *root_distance, double *std_dev,
|
||||
double *first_sample_ago, double *last_sample_ago)
|
||||
{
|
||||
double offset, sample_elapsed;
|
||||
int i, j;
|
||||
|
||||
if (!inst->n_samples) {
|
||||
*select_ok = 0;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
i = get_runsbuf_index(inst, inst->best_single_sample);
|
||||
@@ -675,38 +669,25 @@ SST_GetSelectionData(SST_Stats inst, struct timespec *now,
|
||||
*offset_lo_limit = offset - *root_distance;
|
||||
*offset_hi_limit = offset + *root_distance;
|
||||
|
||||
#if 0
|
||||
double average_offset, elapsed;
|
||||
int average_ok;
|
||||
/* average_ok ignored for now */
|
||||
elapsed = UTI_DiffTimespecsToDouble(now, &inst->offset_time);
|
||||
average_offset = inst->estimated_offset + inst->estimated_frequency * elapsed;
|
||||
if (fabs(average_offset - offset) <=
|
||||
inst->peer_dispersions[j] + 0.5 * inst->peer_delays[i]) {
|
||||
average_ok = 1;
|
||||
} else {
|
||||
average_ok = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
i = get_runsbuf_index(inst, 0);
|
||||
*first_sample_ago = UTI_DiffTimespecsToDouble(now, &inst->sample_times[i]);
|
||||
i = get_runsbuf_index(inst, inst->n_samples - 1);
|
||||
*last_sample_ago = UTI_DiffTimespecsToDouble(now, &inst->sample_times[i]);
|
||||
|
||||
*select_ok = inst->regression_ok;
|
||||
|
||||
/* If maxsamples is too small to have a successful regression, enable the
|
||||
selection as a special case for a fast update/print-once reference mode */
|
||||
if (!*select_ok && inst->n_samples < MIN_SAMPLES_FOR_REGRESS &&
|
||||
if (!inst->regression_ok && inst->n_samples < MIN_SAMPLES_FOR_REGRESS &&
|
||||
inst->n_samples == inst->max_samples) {
|
||||
*std_dev = CNF_GetMaxJitter();
|
||||
*select_ok = 1;
|
||||
} else if (!inst->regression_ok) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_LOG("n=%d off=%f dist=%f sd=%f first_ago=%f last_ago=%f selok=%d",
|
||||
DEBUG_LOG("n=%d off=%f dist=%f sd=%f first_ago=%f last_ago=%f",
|
||||
inst->n_samples, offset, *root_distance, *std_dev,
|
||||
*first_sample_ago, *last_sample_ago, *select_ok);
|
||||
*first_sample_ago, *last_sample_ago);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -67,15 +67,10 @@ extern void SST_DoNewRegression(SST_Stats inst);
|
||||
extern void SST_GetFrequencyRange(SST_Stats inst, double *lo, double *hi);
|
||||
|
||||
/* Get data needed for selection */
|
||||
extern void
|
||||
SST_GetSelectionData(SST_Stats inst, struct timespec *now,
|
||||
double *offset_lo_limit,
|
||||
double *offset_hi_limit,
|
||||
double *root_distance,
|
||||
double *variance,
|
||||
double *first_sample_ago,
|
||||
double *last_sample_ago,
|
||||
int *select_ok);
|
||||
extern int SST_GetSelectionData(SST_Stats inst, struct timespec *now,
|
||||
double *offset_lo_limit, double *offset_hi_limit,
|
||||
double *root_distance, double *variance,
|
||||
double *first_sample_ago, double *last_sample_ago);
|
||||
|
||||
/* Get data needed when setting up tracking on this source */
|
||||
extern void
|
||||
|
||||
12
sys_linux.c
12
sys_linux.c
@@ -63,6 +63,7 @@
|
||||
#endif
|
||||
|
||||
#include "sys_linux.h"
|
||||
#include "sys_linux_scmp.h"
|
||||
#include "sys_timex.h"
|
||||
#include "conf.h"
|
||||
#include "local.h"
|
||||
@@ -728,6 +729,14 @@ SYS_Linux_EnableSystemCallFilter(int level, SYS_ProcessContext context)
|
||||
SCMP_A1(SCMP_CMP_EQ, ioctls[i])) < 0)
|
||||
goto add_failed;
|
||||
}
|
||||
|
||||
/* Allow selected ioctls that need to be specified in a separate
|
||||
file to avoid conflicting headers (e.g. TCGETS2) */
|
||||
for (i = 0; SYS_Linux_GetExtraScmpIoctl(i) != 0; i++) {
|
||||
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, SYS_Linux_GetExtraScmpIoctl(i))) < 0)
|
||||
goto add_failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (seccomp_load(ctx) < 0)
|
||||
@@ -944,8 +953,7 @@ SYS_Linux_OpenPHC(const char *device, int flags)
|
||||
if (phc_fd < 0) {
|
||||
phc_fd = open_phc_by_iface_name(device, flags);
|
||||
if (phc_fd < 0) {
|
||||
LOG(LOGS_ERR, "Could not open PHC of iface %s : %s",
|
||||
device, strerror(errno));
|
||||
LOG(LOGS_ERR, "Could not open PHC (of) %s", device);
|
||||
return -1;
|
||||
}
|
||||
phc_fd = verify_fd_is_phc(phc_fd);
|
||||
|
||||
44
sys_linux_scmp.c
Normal file
44
sys_linux_scmp.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2025
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Lists of values that are needed in seccomp filters but need to
|
||||
be compiled separately from sys_linux.c due to conflicting headers.
|
||||
*/
|
||||
|
||||
#include <linux/termios.h>
|
||||
|
||||
#include "sys_linux_scmp.h"
|
||||
|
||||
unsigned long
|
||||
SYS_Linux_GetExtraScmpIoctl(int index)
|
||||
{
|
||||
const unsigned long ioctls[] = {
|
||||
#ifdef TCGETS2
|
||||
/* Conflict between <linux/termios.h> and <sys/ioctl.h> */
|
||||
TCGETS2,
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
return ioctls[index];
|
||||
}
|
||||
28
sys_linux_scmp.h
Normal file
28
sys_linux_scmp.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2025
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for lists that are needed in seccomp filters but need to
|
||||
be compiled separately from sys_linux.c due to conflicting headers.
|
||||
*/
|
||||
|
||||
extern unsigned long SYS_Linux_GetExtraScmpIoctl(int index);
|
||||
38
test/simulation/151-stratumlimit
Executable file
38
test/simulation/151-stratumlimit
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. ./test.common
|
||||
|
||||
test_start "minstratum and maxstratum options"
|
||||
|
||||
client_conf="
|
||||
minstratum 3
|
||||
maxstratum 5"
|
||||
|
||||
for s in 3 5; do
|
||||
server_conf="local stratum $s"
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
check_log_messages "Stratum of .* stratum" 0 0 || test_fail
|
||||
done
|
||||
|
||||
for s in 2 6; do
|
||||
server_conf="local stratum $s"
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection && test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync && test_fail
|
||||
|
||||
check_log_messages "Stratum of .* stratum" 0 0 || test_fail
|
||||
if [ $s -lt 3 ]; then
|
||||
check_log_messages "Stratum of .* below minstratum of 3" 1 1 || test_fail
|
||||
else
|
||||
check_log_messages "Stratum of .* above maxstratum of 5" 1 1 || test_fail
|
||||
fi
|
||||
done
|
||||
|
||||
test_pass
|
||||
@@ -1,7 +1,7 @@
|
||||
This is a collection of simulation tests using the clknetsim simulator
|
||||
(supported on Linux only).
|
||||
|
||||
https://github.com/mlichvar/clknetsim
|
||||
https://gitlab.com/chrony/clknetsim
|
||||
|
||||
The CLKNETSIM_PATH environment variable should point to the directory where
|
||||
clknetsim was downloaded and compiled. If the variable is not set, the tests
|
||||
|
||||
@@ -68,7 +68,7 @@ check_chronyc_output "^Name/IP address Mode KeyID Type KLen Last Atm
|
||||
run_chronyc "clients" || test_fail
|
||||
check_chronyc_output "^Hostname NTP Drop Int IntL Last Cmd Drop Int Last
|
||||
===============================================================================
|
||||
.*127\.0\.0\.1 [0-9 ]+ 0 [-0-9 ]+ - [ 0-9]+ 0 0 - -.*$" \
|
||||
.*127\.0\.0\.1 [0-9 ]+ 0 [-0-9 ]+ - [-0-9 ]+ 0 0 - -.*$" \
|
||||
|| test_fail
|
||||
|
||||
run_chronyc "ntpdata $server" || test_fail
|
||||
|
||||
@@ -213,7 +213,10 @@ generate_chrony_conf() {
|
||||
|
||||
user=$(get_user)
|
||||
ntpport=$(get_free_port)
|
||||
cmdport=$(get_free_port)
|
||||
while true; do
|
||||
cmdport=$(get_free_port)
|
||||
[ "$ntpport" -ne "$cmdport" ] && break
|
||||
done
|
||||
|
||||
echo "0.0 10000" > "$TEST_LIBDIR/driftfile"
|
||||
echo "1 MD5 abcdefghijklmnopq" > "$TEST_DIR/keys"
|
||||
|
||||
@@ -193,6 +193,8 @@ test_unit(void)
|
||||
|
||||
server_cred = NKSN_CreateServerCertCredentials(&cert, &key, 1);
|
||||
client_cred = NKSN_CreateClientCertCredentials(&cert, &cert_id, 1, 0);
|
||||
TEST_CHECK(server_cred);
|
||||
TEST_CHECK(client_cred);
|
||||
|
||||
TEST_CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds) == 0);
|
||||
TEST_CHECK(fcntl(sock_fds[0], F_SETFL, O_NONBLOCK) == 0);
|
||||
|
||||
@@ -191,6 +191,7 @@ test_unit(void)
|
||||
s3 = SCK_AcceptConnection(s1, &sa2);
|
||||
TEST_CHECK(UTI_CompareIPs(&sa1.ip_addr, &sa2.ip_addr, NULL) == 0);
|
||||
|
||||
fcntl(s3, F_SETFL, fcntl(s3, F_GETFL) & ~O_NONBLOCK);
|
||||
send_and_recv(SCK_ADDR_IP, 1, 1, s3, s2);
|
||||
|
||||
SCK_ShutdownConnection(s2);
|
||||
@@ -227,6 +228,7 @@ test_unit(void)
|
||||
s3 = SCK_AcceptConnection(s1, &sa2);
|
||||
TEST_CHECK(sa2.ip_addr.family == IPADDR_UNSPEC);
|
||||
|
||||
fcntl(s3, F_SETFL, fcntl(s3, F_GETFL) & ~O_NONBLOCK);
|
||||
send_and_recv(SCK_ADDR_UNIX, 1, i % 2, s3, s2);
|
||||
|
||||
if (i % 4)
|
||||
|
||||
2
util.c
2
util.c
@@ -1203,7 +1203,7 @@ create_dir(char *p, mode_t mode, uid_t uid, gid_t gid)
|
||||
}
|
||||
|
||||
/* Set its owner */
|
||||
if (chown(p, uid, gid) < 0) {
|
||||
if (lchown(p, uid, gid) < 0) {
|
||||
LOG(LOGS_ERR, "Could not change ownership of %s : %s", p, strerror(errno));
|
||||
/* Don't leave it there with incorrect ownership */
|
||||
rmdir(p);
|
||||
|
||||
Reference in New Issue
Block a user