]> git.ipfire.org Git - thirdparty/chrony.git/blame - sources.c
ntp: fix log message for replaced source
[thirdparty/chrony.git] / sources.c
CommitLineData
88840341 1/*
88840341
RC
2 chronyd/chronyc - Programs for keeping computer clocks accurate.
3
4 **********************************************************************
6672f045 5 * Copyright (C) Richard P. Curnow 1997-2003
5dc86c23 6 * Copyright (C) Miroslav Lichvar 2011-2016, 2018
88840341
RC
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of version 2 of the GNU General Public License as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
8e23110a 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
88840341
RC
20 *
21 **********************************************************************
22
23 =======================================================================
24
25 The routines in this file manage the complete pool of sources that
26 we might be synchronizing to. This includes NTP sources and others
27 (e.g. local reference clocks, eyeball + wristwatch etc).
28
29 */
30
da2c8d90
ML
31#include "config.h"
32
88840341
RC
33#include "sysincl.h"
34
35#include "sources.h"
36#include "sourcestats.h"
37#include "memory.h"
38#include "ntp.h" /* For NTP_Leap */
c743ecbf 39#include "ntp_sources.h"
88840341
RC
40#include "local.h"
41#include "reference.h"
42#include "util.h"
43#include "conf.h"
44#include "logging.h"
45#include "reports.h"
46#include "nameserv.h"
8aa9eb19 47#include "sched.h"
3888b9dc 48#include "regress.h"
88840341
RC
49
50/* ================================================== */
51/* Flag indicating that we are initialised */
52static int initialised = 0;
53
54/* ================================================== */
55/* Structure used to hold info for selecting between sources */
56struct SelectInfo {
57 int stratum;
58 int select_ok;
68039e0d 59 double std_dev;
88840341 60 double root_distance;
88840341
RC
61 double lo_limit;
62 double hi_limit;
8f062454 63 double last_sample_ago;
88840341
RC
64};
65
66/* ================================================== */
67/* This enum contains the flag values that are used to label
68 each source */
69typedef enum {
0f8368bc 70 SRC_OK, /* OK so far, not a final status! */
8f062454 71 SRC_UNSELECTABLE, /* Has noselect option set */
0f8368bc 72 SRC_BAD_STATS, /* Doesn't have valid stats data */
5039f959 73 SRC_BAD_DISTANCE, /* Has root distance longer than allowed maximum */
8bbb8fa0 74 SRC_JITTERY, /* Had std dev larger than allowed maximum */
0f8368bc 75 SRC_WAITS_STATS, /* Others have bad stats, selection postponed */
8f062454 76 SRC_STALE, /* Has older samples than others */
5a92dbe7 77 SRC_ORPHAN, /* Has stratum equal or larger than orphan stratum */
6e9bfac0 78 SRC_UNTRUSTED, /* Overlaps trusted sources */
0f8368bc 79 SRC_FALSETICKER, /* Doesn't agree with others */
1bb27320 80 SRC_WAITS_SOURCES, /* Not enough sources, selection postponed */
0f8368bc
ML
81 SRC_NONPREFERRED, /* Others have prefer option */
82 SRC_WAITS_UPDATE, /* No updates, selection postponed */
83 SRC_DISTANT, /* Others have shorter root distance */
84 SRC_OUTLIER, /* Outlier in clustering (not used yet) */
85 SRC_UNSELECTED, /* Used for synchronisation, not system peer */
86 SRC_SELECTED, /* Used for synchronisation, selected as system peer */
88840341
RC
87} SRC_Status;
88
89/* ================================================== */
90/* Define the instance structure used to hold information about each
91 source */
92struct SRC_Instance_Record {
93 SST_Stats stats;
88840341 94 int index; /* Index back into the array of source */
91279a0f
ML
95 uint32_t ref_id; /* The reference ID of this source
96 (i.e. from its IP address, NOT the
88840341 97 reference _it_ is sync'd to) */
8265ff28 98 IPAddr *ip_addr; /* Its IP address if NTP source */
88840341 99
8671002b
ML
100 /* Flag indicating that the source is updating reachability */
101 int active;
102
0c4968ec
ML
103 /* Reachability register */
104 int reachability;
88840341 105
4932f9d0
ML
106 /* Number of set bits in the reachability register */
107 int reachability_size;
1ad22e9a 108
e930d947
ML
109 /* Updates since last reference update */
110 int updates;
111
8d80ce44 112 /* Updates left before allowing combining */
0f8368bc 113 int distant;
52272f4d 114
88840341
RC
115 /* Flag indicating the status of the source */
116 SRC_Status status;
117
ac30bb06
ML
118 /* Type of the source */
119 SRC_Type type;
120
f924862e 121 /* Options used when selecting sources */
fa15fb3d 122 int sel_options;
f924862e 123
db510a95
ML
124 /* Score against currently selected source */
125 double sel_score;
126
88840341 127 struct SelectInfo sel_info;
ff930156
ML
128
129 /* Latest leap status */
130 NTP_Leap leap;
4883086f
ML
131
132 /* Flag indicating the source has a leap second vote */
133 int leap_vote;
88840341
RC
134};
135
136/* ================================================== */
137/* Structure used to build the sort list for finding falsetickers */
138struct Sort_Element {
139 int index;
140 double offset;
6f84d2fa
ML
141 enum {
142 LOW = -1,
143 HIGH = 1
144 } tag;
88840341
RC
145};
146
147/* ================================================== */
148/* Table of sources */
149static struct SRC_Instance_Record **sources;
150static struct Sort_Element *sort_list;
151static int *sel_sources;
152static int n_sources; /* Number of sources currently in the table */
153static int max_n_sources; /* Capacity of the table */
154
155#define INVALID_SOURCE (-1)
156static int selected_source_index; /* Which source index is currently
157 selected (set to INVALID_SOURCE
158 if no current valid reference) */
159
db510a95
ML
160/* Score needed to replace the currently selected source */
161#define SCORE_LIMIT 10.0
162
0f8368bc
ML
163/* Number of updates needed to reset the distant status */
164#define DISTANT_PENALTY 32
52272f4d 165
5039f959 166static double max_distance;
8bbb8fa0 167static double max_jitter;
db510a95 168static double reselect_distance;
9cf08fc7 169static double stratum_weight;
52272f4d 170static double combine_limit;
db510a95 171
88840341
RC
172/* ================================================== */
173/* Forward prototype */
174
175static void
d0dfa1de 176slew_sources(struct timespec *raw, struct timespec *cooked, double dfreq,
44c9744d 177 double doffset, LCL_ChangeType change_type, void *anything);
0f70959d
ML
178static void
179add_dispersion(double dispersion, void *anything);
ac30bb06
ML
180static char *
181source_to_string(SRC_Instance inst);
88840341
RC
182
183/* ================================================== */
184/* Initialisation function */
185void SRC_Initialise(void) {
186 sources = NULL;
187 sort_list = NULL;
f6ed7844 188 sel_sources = NULL;
88840341
RC
189 n_sources = 0;
190 max_n_sources = 0;
191 selected_source_index = INVALID_SOURCE;
5039f959 192 max_distance = CNF_GetMaxDistance();
8bbb8fa0 193 max_jitter = CNF_GetMaxJitter();
db510a95 194 reselect_distance = CNF_GetReselectDistance();
9cf08fc7 195 stratum_weight = CNF_GetStratumWeight();
52272f4d 196 combine_limit = CNF_GetCombineLimit();
88840341
RC
197 initialised = 1;
198
199 LCL_AddParameterChangeHandler(slew_sources, NULL);
0f70959d 200 LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
88840341
RC
201}
202
203/* ================================================== */
204/* Finalisation function */
205void SRC_Finalise(void)
206{
207 LCL_RemoveParameterChangeHandler(slew_sources, NULL);
0f70959d 208 LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL);
f6ed7844
ML
209
210 Free(sources);
211 Free(sort_list);
212 Free(sel_sources);
213
88840341 214 initialised = 0;
88840341
RC
215}
216
217/* ================================================== */
218/* Function to create a new instance. This would be called by one of
219 the individual source-type instance creation routines. */
220
b06d74ab
ML
221SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options,
222 IPAddr *addr, int min_samples, int max_samples,
223 double min_delay, double asymmetry)
88840341
RC
224{
225 SRC_Instance result;
226
6b0198c2 227 assert(initialised);
88840341 228
6688f403
ML
229 if (min_samples == SRC_DEFAULT_MINSAMPLES)
230 min_samples = CNF_GetMinSamples();
231 if (max_samples == SRC_DEFAULT_MAXSAMPLES)
232 max_samples = CNF_GetMaxSamples();
233
88840341 234 result = MallocNew(struct SRC_Instance_Record);
b06d74ab
ML
235 result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples,
236 min_delay, asymmetry);
88840341
RC
237
238 if (n_sources == max_n_sources) {
239 /* Reallocate memory */
b5a85bd2 240 max_n_sources = max_n_sources > 0 ? 2 * max_n_sources : 4;
88840341
RC
241 if (sources) {
242 sources = ReallocArray(struct SRC_Instance_Record *, max_n_sources, sources);
243 sort_list = ReallocArray(struct Sort_Element, 3*max_n_sources, sort_list);
244 sel_sources = ReallocArray(int, max_n_sources, sel_sources);
245 } else {
246 sources = MallocArray(struct SRC_Instance_Record *, max_n_sources);
247 sort_list = MallocArray(struct Sort_Element, 3*max_n_sources);
248 sel_sources = MallocArray(int, max_n_sources);
249 }
250 }
251
252 sources[n_sources] = result;
42dd5caa 253
88840341 254 result->index = n_sources;
ac30bb06 255 result->type = type;
fa15fb3d 256 result->sel_options = sel_options;
1e727c44 257 result->active = 0;
88840341 258
42dd5caa
ML
259 SRC_SetRefid(result, ref_id, addr);
260 SRC_ResetInstance(result);
261
88840341
RC
262 n_sources++;
263
264 return result;
265}
266
267/* ================================================== */
268/* Function to get rid of a source when it is being unconfigured.
269 This may cause the current reference source to be reselected, if this
270 was the reference source or contributed significantly to a
271 falseticker decision. */
272
273void SRC_DestroyInstance(SRC_Instance instance)
274{
275 int dead_index, i;
276
6b0198c2 277 assert(initialised);
88840341 278
88840341
RC
279 SST_DeleteInstance(instance->stats);
280 dead_index = instance->index;
281 for (i=dead_index; i<n_sources-1; i++) {
282 sources[i] = sources[i+1];
283 sources[i]->index = i;
284 }
285 --n_sources;
286 Free(instance);
287
63af4889
ML
288 /* If this was the previous reference source, we have to reselect! */
289 if (selected_source_index == dead_index)
290 SRC_ReselectSource();
291 else if (selected_source_index > dead_index)
88840341 292 --selected_source_index;
88840341
RC
293}
294
42dd5caa
ML
295/* ================================================== */
296
297void
298SRC_ResetInstance(SRC_Instance instance)
299{
42dd5caa
ML
300 instance->updates = 0;
301 instance->reachability = 0;
302 instance->reachability_size = 0;
303 instance->distant = 0;
304 instance->status = SRC_BAD_STATS;
305 instance->sel_score = 1.0;
ff930156 306 instance->leap = LEAP_Unsynchronised;
4883086f 307 instance->leap_vote = 0;
42dd5caa
ML
308
309 SST_ResetInstance(instance->stats);
310}
311
312/* ================================================== */
313
314void
315SRC_SetRefid(SRC_Instance instance, uint32_t ref_id, IPAddr *addr)
316{
317 instance->ref_id = ref_id;
318 instance->ip_addr = addr;
319 SST_SetRefid(instance->stats, ref_id, addr);
320}
321
88840341 322/* ================================================== */
1045adaa
ML
323
324SST_Stats
325SRC_GetSourcestats(SRC_Instance instance)
88840341 326{
6b0198c2 327 assert(initialised);
1045adaa 328 return instance->stats;
88840341
RC
329}
330
331/* ================================================== */
332
4883086f
ML
333static NTP_Leap
334get_leap_status(void)
335{
336 int i, leap_votes, leap_ins, leap_del;
337
338 /* Accept a leap second if more than half of the sources with a vote agree */
339
340 for (i = leap_ins = leap_del = leap_votes = 0; i < n_sources; i++) {
341 if (!sources[i]->leap_vote)
342 continue;
343
344 leap_votes++;
345 if (sources[i]->leap == LEAP_InsertSecond)
346 leap_ins++;
347 else if (sources[i]->leap == LEAP_DeleteSecond)
348 leap_del++;
349 }
350
351 if (leap_ins > leap_votes / 2)
352 return LEAP_InsertSecond;
353 else if (leap_del > leap_votes / 2)
354 return LEAP_DeleteSecond;
355 else
356 return LEAP_Normal;
357}
358
359/* ================================================== */
360
2582be87
ML
361void
362SRC_SetLeapStatus(SRC_Instance inst, NTP_Leap leap)
363{
c687224a 364 if (REF_IsLeapSecondClose(NULL, 0.0))
2582be87
ML
365 return;
366
367 inst->leap = leap;
4883086f
ML
368
369 if (inst->leap_vote)
370 REF_UpdateLeapStatus(get_leap_status());
2582be87
ML
371}
372
373/* ================================================== */
374
88840341
RC
375/* This function is called by one of the source drivers when it has
376 a new sample that is to be accumulated.
377
378 This function causes the frequency estimation to be re-run for the
379 designated source, and the clock selection procedure to be re-run
380 afterwards.
88840341
RC
381 */
382
6bef8aa0
ML
383void
384SRC_AccumulateSample(SRC_Instance inst, NTP_Sample *sample)
88840341
RC
385{
386
6b0198c2 387 assert(initialised);
88840341 388
f282856c 389 DEBUG_LOG("ip=[%s] t=%s ofs=%f del=%f disp=%f str=%d",
6bef8aa0
ML
390 source_to_string(inst), UTI_TimespecToString(&sample->time), -sample->offset,
391 sample->root_delay, sample->root_dispersion, sample->stratum);
88840341 392
c687224a 393 if (REF_IsLeapSecondClose(&sample->time, sample->offset)) {
f282856c 394 LOG(LOGS_INFO, "Dropping sample around leap second");
0e786f59
ML
395 return;
396 }
397
6bef8aa0 398 SST_AccumulateSample(inst->stats, sample);
88840341 399 SST_DoNewRegression(inst->stats);
88840341
RC
400}
401
402/* ================================================== */
403
8671002b
ML
404void
405SRC_SetActive(SRC_Instance inst)
406{
407 inst->active = 1;
408}
409
410/* ================================================== */
411
412void
413SRC_UnsetActive(SRC_Instance inst)
414{
415 inst->active = 0;
416}
417
418/* ================================================== */
419
3888b9dc
ML
420static int
421special_mode_end(void)
422{
423 int i;
424
425 for (i = 0; i < n_sources; i++) {
7fa22d4c
ML
426 /* No updates from inactive sources */
427 if (!sources[i]->active)
428 continue;
429
3888b9dc
ML
430 /* Don't expect more updates than from an offline iburst NTP source */
431 if (sources[i]->reachability_size >= SOURCE_REACH_BITS - 1)
432 continue;
433
434 /* Check if the source could still have enough samples to be selectable */
435 if (SOURCE_REACH_BITS - 1 - sources[i]->reachability_size +
1045adaa 436 SST_Samples(sources[i]->stats) >= MIN_SAMPLES_FOR_REGRESS)
3888b9dc
ML
437 return 0;
438 }
439
440 return 1;
441}
442
0c4968ec
ML
443void
444SRC_UpdateReachability(SRC_Instance inst, int reachable)
445{
446 inst->reachability <<= 1;
447 inst->reachability |= !!reachable;
8e71a461 448 inst->reachability %= 1U << SOURCE_REACH_BITS;
0c4968ec 449
70928dba 450 if (inst->reachability_size < SOURCE_REACH_BITS)
4932f9d0 451 inst->reachability_size++;
1ad22e9a 452
0c4968ec
ML
453 if (!reachable && inst->index == selected_source_index) {
454 /* Try to select a better source */
0094128c 455 SRC_SelectSource(NULL);
0c4968ec 456 }
7fda9c67 457
3888b9dc
ML
458 /* Check if special reference update mode failed */
459 if (REF_GetMode() != REF_ModeNormal && special_mode_end()) {
7fda9c67
ML
460 REF_SetUnsynchronised();
461 }
c743ecbf 462
d70e815e 463 /* Try to replace NTP sources that are unreachable, falsetickers, or
4432f29b 464 have root distance or jitter larger than the allowed maximums */
d70e815e
ML
465 if (inst->type == SRC_NTP &&
466 ((!inst->reachability && inst->reachability_size == SOURCE_REACH_BITS) ||
4432f29b
ML
467 inst->status == SRC_BAD_DISTANCE || inst->status == SRC_JITTERY ||
468 inst->status == SRC_FALSETICKER)) {
c743ecbf
ML
469 NSR_HandleBadSource(inst->ip_addr);
470 }
0c4968ec
ML
471}
472
473/* ================================================== */
474
475void
476SRC_ResetReachability(SRC_Instance inst)
477{
478 inst->reachability = 0;
4932f9d0 479 inst->reachability_size = 0;
0c4968ec
ML
480 SRC_UpdateReachability(inst, 0);
481}
482
483/* ================================================== */
484
610284dc
ML
485static void
486log_selection_message(char *format, char *arg)
487{
488 if (REF_GetMode() != REF_ModeNormal)
489 return;
f282856c 490 LOG(LOGS_INFO, format, arg);
610284dc
ML
491}
492
493/* ================================================== */
494
88840341
RC
495static int
496compare_sort_elements(const void *a, const void *b)
497{
498 const struct Sort_Element *u = (const struct Sort_Element *) a;
499 const struct Sort_Element *v = (const struct Sort_Element *) b;
500
501 if (u->offset < v->offset) {
502 return -1;
503 } else if (u->offset > v->offset) {
504 return +1;
505 } else if (u->tag < v->tag) {
506 return -1;
507 } else if (u->tag > v->tag) {
508 return +1;
509 } else {
510 return 0;
511 }
512}
513
ac30bb06
ML
514/* ================================================== */
515
516static char *
517source_to_string(SRC_Instance inst)
518{
519 switch (inst->type) {
520 case SRC_NTP:
8265ff28 521 return UTI_IPToString(inst->ip_addr);
ac30bb06
ML
522 case SRC_REFCLOCK:
523 return UTI_RefidToString(inst->ref_id);
524 default:
6b0198c2 525 assert(0);
ac30bb06
ML
526 }
527 return NULL;
528}
529
18a66a2b
ML
530/* ================================================== */
531
0f8368bc
ML
532static void
533mark_ok_sources(SRC_Status status)
534{
535 int i;
536
537 for (i = 0; i < n_sources; i++) {
538 if (sources[i]->status != SRC_OK)
539 continue;
540 sources[i]->status = status;
541 }
542}
543
544/* ================================================== */
545
6fa11a85 546static int
d0dfa1de 547combine_sources(int n_sel_sources, struct timespec *ref_time, double *offset,
ca73e34f 548 double *offset_sd, double *frequency, double *frequency_sd, double *skew)
18a66a2b 549{
d0dfa1de 550 struct timespec src_ref_time;
cca2ef46 551 double src_offset, src_offset_sd, src_frequency, src_frequency_sd, src_skew;
05278c3b 552 double src_root_delay, src_root_dispersion, sel_src_distance, elapsed;
707b857b 553 double offset_weight, sum_offset_weight, sum_offset, sum2_offset_sd;
ca73e34f
ML
554 double frequency_weight, sum_frequency_weight, sum_frequency;
555 double inv_sum2_frequency_sd, inv_sum2_skew;
6fa11a85
ML
556 int i, index, combined;
557
558 if (n_sel_sources == 1)
559 return 1;
18a66a2b 560
707b857b 561 sum_offset_weight = sum_offset = sum2_offset_sd = 0.0;
ca73e34f 562 sum_frequency_weight = sum_frequency = inv_sum2_frequency_sd = inv_sum2_skew = 0.0;
18a66a2b 563
05278c3b
ML
564 sel_src_distance = sources[selected_source_index]->sel_info.root_distance;
565 if (sources[selected_source_index]->type == SRC_NTP)
566 sel_src_distance += reselect_distance;
567
6fa11a85 568 for (i = combined = 0; i < n_sel_sources; i++) {
18a66a2b
ML
569 index = sel_sources[i];
570 SST_GetTrackingData(sources[index]->stats, &src_ref_time,
571 &src_offset, &src_offset_sd,
cca2ef46 572 &src_frequency, &src_frequency_sd, &src_skew,
18a66a2b
ML
573 &src_root_delay, &src_root_dispersion);
574
52272f4d
ML
575 /* Don't include this source if its distance is longer than the distance of
576 the selected source multiplied by the limit, their estimated frequencies
0f8368bc 577 are not close, or it was recently marked as distant */
52272f4d
ML
578
579 if (index != selected_source_index &&
05278c3b 580 (sources[index]->sel_info.root_distance > combine_limit * sel_src_distance ||
52272f4d
ML
581 fabs(*frequency - src_frequency) >
582 combine_limit * (*skew + src_skew + LCL_GetMaxClockError()))) {
4932f9d0 583 /* Use a smaller penalty in first few updates */
0f8368bc
ML
584 sources[index]->distant = sources[index]->reachability_size >= SOURCE_REACH_BITS ?
585 DISTANT_PENALTY : 1;
586 } else if (sources[index]->distant) {
587 sources[index]->distant--;
52272f4d
ML
588 }
589
0f8368bc
ML
590 if (sources[index]->distant) {
591 sources[index]->status = SRC_DISTANT;
52272f4d 592 continue;
0f8368bc
ML
593 }
594
595 if (sources[index]->status == SRC_OK)
596 sources[index]->status = SRC_UNSELECTED;
52272f4d 597
cfe706f0 598 elapsed = UTI_DiffTimespecsToDouble(ref_time, &src_ref_time);
18a66a2b 599 src_offset += elapsed * src_frequency;
2240eefb 600 src_offset_sd += elapsed * src_frequency_sd;
707b857b 601 offset_weight = 1.0 / sources[index]->sel_info.root_distance;
0b709ab1 602 frequency_weight = 1.0 / SQUARE(src_frequency_sd);
18a66a2b 603
ca73e34f
ML
604 DEBUG_LOG("combining index=%d oweight=%e offset=%e osd=%e fweight=%e freq=%e fsd=%e skew=%e",
605 index, offset_weight, src_offset, src_offset_sd,
606 frequency_weight, src_frequency, src_frequency_sd, src_skew);
18a66a2b 607
707b857b
ML
608 sum_offset_weight += offset_weight;
609 sum_offset += offset_weight * src_offset;
0b709ab1 610 sum2_offset_sd += offset_weight * (SQUARE(src_offset_sd) +
6045023a 611 SQUARE(src_offset - *offset));
707b857b
ML
612
613 sum_frequency_weight += frequency_weight;
614 sum_frequency += frequency_weight * src_frequency;
0b709ab1
ML
615 inv_sum2_frequency_sd += 1.0 / SQUARE(src_frequency_sd);
616 inv_sum2_skew += 1.0 / SQUARE(src_skew);
6fa11a85
ML
617
618 combined++;
18a66a2b
ML
619 }
620
707b857b
ML
621 assert(combined);
622 *offset = sum_offset / sum_offset_weight;
623 *offset_sd = sqrt(sum2_offset_sd / sum_offset_weight);
624 *frequency = sum_frequency / sum_frequency_weight;
ca73e34f 625 *frequency_sd = 1.0 / sqrt(inv_sum2_frequency_sd);
707b857b 626 *skew = 1.0 / sqrt(inv_sum2_skew);
18a66a2b 627
ca73e34f
ML
628 DEBUG_LOG("combined result offset=%e osd=%e freq=%e fsd=%e skew=%e",
629 *offset, *offset_sd, *frequency, *frequency_sd, *skew);
6fa11a85
ML
630
631 return combined;
18a66a2b
ML
632}
633
88840341
RC
634/* ================================================== */
635/* This function selects the current reference from amongst the pool
e930d947 636 of sources we are holding and updates the local reference */
88840341
RC
637
638void
0094128c 639SRC_SelectSource(SRC_Instance updated_inst)
88840341 640{
6f84d2fa 641 struct SelectInfo *si;
d0dfa1de 642 struct timespec now, ref_time;
5bc9c0d0
ML
643 int i, j, j1, j2, index, sel_prefer, n_endpoints, n_sel_sources, sel_req_source;
644 int n_badstats_sources, max_sel_reach, max_sel_reach_size, max_badstat_reach;
936f5cb0
ML
645 int depth, best_depth, trust_depth, best_trust_depth;
646 int combined, stratum, min_stratum, max_score_index;
4883086f 647 int orphan_stratum, orphan_source;
cca2ef46 648 double src_offset, src_offset_sd, src_frequency, src_frequency_sd, src_skew;
c5587b60 649 double src_root_delay, src_root_dispersion;
6f84d2fa 650 double best_lo, best_hi, distance, sel_src_distance, max_score;
8f062454 651 double first_sample_ago, max_reach_sample_ago;
6f84d2fa 652 NTP_Leap leap_status;
88840341 653
e930d947
ML
654 if (updated_inst)
655 updated_inst->updates++;
656
88840341
RC
657 if (n_sources == 0) {
658 /* In this case, we clearly cannot synchronise to anything */
659 if (selected_source_index != INVALID_SOURCE) {
610284dc 660 log_selection_message("Can't synchronise: no sources", NULL);
7f6ed731 661 selected_source_index = INVALID_SOURCE;
88840341 662 }
88840341
RC
663 return;
664 }
665
8aa9eb19
ML
666 /* This is accurate enough and cheaper than calling LCL_ReadCookedTime */
667 SCH_GetLastEventTime(&now, NULL, NULL);
88840341
RC
668
669 /* Step 1 - build intervals about each source */
6f84d2fa 670
88840341 671 n_endpoints = 0;
98f79404 672 n_sel_sources = 0;
05e002cd 673 n_badstats_sources = 0;
e98f76e0 674 sel_req_source = 0;
05e002cd 675 max_sel_reach = max_badstat_reach = 0;
5bc9c0d0 676 max_sel_reach_size = 0;
8f062454 677 max_reach_sample_ago = 0.0;
88840341 678
6f84d2fa 679 for (i = 0; i < n_sources; i++) {
0f8368bc
ML
680 assert(sources[i]->status != SRC_OK);
681
e98f76e0
ML
682 /* If some sources are specified with the require option, at least one
683 of them will have to be selectable in order to update the clock */
684 if (sources[i]->sel_options & SRC_SELECT_REQUIRE)
685 sel_req_source = 1;
686
8f062454 687 /* Ignore sources which were added with the noselect option */
fa15fb3d 688 if (sources[i]->sel_options & SRC_SELECT_NOSELECT) {
8f062454 689 sources[i]->status = SRC_UNSELECTABLE;
6f84d2fa
ML
690 continue;
691 }
88840341 692
6f84d2fa 693 si = &sources[i]->sel_info;
ff930156 694 SST_GetSelectionData(sources[i]->stats, &now, &si->stratum,
6f84d2fa 695 &si->lo_limit, &si->hi_limit, &si->root_distance,
68039e0d 696 &si->std_dev, &first_sample_ago,
8f062454 697 &si->last_sample_ago, &si->select_ok);
88840341 698
6f84d2fa
ML
699 if (!si->select_ok) {
700 ++n_badstats_sources;
701 sources[i]->status = SRC_BAD_STATS;
702 if (max_badstat_reach < sources[i]->reachability)
703 max_badstat_reach = sources[i]->reachability;
704 continue;
705 }
88840341 706
5308e0a2
ML
707 /* Include extra dispersion in the root distance of sources that don't
708 have new samples (the last sample is older than span of all samples) */
709 if (first_sample_ago < 2.0 * si->last_sample_ago) {
710 double extra_disp = LCL_GetMaxClockError() *
711 (2.0 * si->last_sample_ago - first_sample_ago);
712 si->root_distance += extra_disp;
713 si->lo_limit -= extra_disp;
714 si->hi_limit += extra_disp;
715 }
716
5039f959
ML
717 /* Require the root distance to be below the allowed maximum */
718 if (si->root_distance > max_distance) {
719 sources[i]->status = SRC_BAD_DISTANCE;
720 continue;
721 }
722
8bbb8fa0
ML
723 /* And the same applies for the estimated standard deviation */
724 if (si->std_dev > max_jitter) {
725 sources[i]->status = SRC_JITTERY;
726 continue;
727 }
728
6f84d2fa 729 sources[i]->status = SRC_OK; /* For now */
4883086f 730 sources[i]->leap_vote = 0;
88840341 731
8f062454
ML
732 if (sources[i]->reachability && max_reach_sample_ago < first_sample_ago)
733 max_reach_sample_ago = first_sample_ago;
734
735 if (max_sel_reach < sources[i]->reachability)
736 max_sel_reach = sources[i]->reachability;
5bc9c0d0
ML
737
738 if (max_sel_reach_size < sources[i]->reachability_size)
739 max_sel_reach_size = sources[i]->reachability_size;
8f062454
ML
740 }
741
5a92dbe7
ML
742 orphan_stratum = REF_GetOrphanStratum();
743 orphan_source = INVALID_SOURCE;
744
8f062454
ML
745 for (i = 0; i < n_sources; i++) {
746 if (sources[i]->status != SRC_OK)
747 continue;
748
749 si = &sources[i]->sel_info;
750
751 /* Reachability is not a requirement for selection. An unreachable source
752 can still be selected if its newest sample is not older than the oldest
753 sample from reachable sources. */
754 if (!sources[i]->reachability && max_reach_sample_ago < si->last_sample_ago) {
755 sources[i]->status = SRC_STALE;
756 continue;
757 }
758
5a92dbe7
ML
759 /* When the local reference is configured with the orphan option, NTP
760 sources that have stratum equal to the configured local stratum are
761 considered to be orphans (i.e. serving local time while not being
762 synchronised with real time) and are excluded from the normal source
763 selection. Sources with stratum larger than the local stratum are
764 considered to be directly on indirectly synchronised to an orphan and
765 are always ignored.
766
767 If no selectable source is available and all orphan sources have
768 reference IDs larger than the local ID, no source will be selected and
769 the local reference mode will be activated at some point, i.e. this host
770 will become an orphan. Otherwise, the orphan source with the smallest
771 reference ID will be selected. This ensures a group of servers polling
772 each other (with the same orphan configuration) which have no external
773 source can settle down to a state where only one server is serving its
774 local unsychronised time and others are synchronised to it. */
775
776 if (si->stratum >= orphan_stratum && sources[i]->type == SRC_NTP) {
777 sources[i]->status = SRC_ORPHAN;
778
26b87b84 779 if (si->stratum == orphan_stratum && sources[i]->reachability &&
5a92dbe7
ML
780 (orphan_source == INVALID_SOURCE ||
781 sources[i]->ref_id < sources[orphan_source]->ref_id))
782 orphan_source = i;
783
784 continue;
785 }
786
8f062454 787 ++n_sel_sources;
5a92dbe7
ML
788 }
789
790 /* If no selectable source is available, consider the orphan source */
6accd19e
ML
791 if (!n_sel_sources && orphan_source != INVALID_SOURCE) {
792 uint32_t local_ref_id = NSR_GetLocalRefid(sources[orphan_source]->ip_addr);
793
794 if (!local_ref_id) {
f282856c 795 LOG(LOGS_ERR, "Unknown local refid in orphan mode");
6accd19e
ML
796 } else if (sources[orphan_source]->ref_id < local_ref_id) {
797 sources[orphan_source]->status = SRC_OK;
798 n_sel_sources = 1;
f282856c 799 DEBUG_LOG("selecting orphan refid=%"PRIx32, sources[orphan_source]->ref_id);
6accd19e 800 }
5a92dbe7
ML
801 }
802
803 for (i = 0; i < n_sources; i++) {
804 if (sources[i]->status != SRC_OK)
805 continue;
806
807 si = &sources[i]->sel_info;
8f062454 808
6f84d2fa
ML
809 j1 = n_endpoints;
810 j2 = j1 + 1;
88840341 811
6f84d2fa
ML
812 sort_list[j1].index = i;
813 sort_list[j1].offset = si->lo_limit;
814 sort_list[j1].tag = LOW;
88840341 815
6f84d2fa
ML
816 sort_list[j2].index = i;
817 sort_list[j2].offset = si->hi_limit;
818 sort_list[j2].tag = HIGH;
88840341 819
6f84d2fa 820 n_endpoints += 2;
88840341
RC
821 }
822
5bc9c0d0 823 DEBUG_LOG("badstat=%d sel=%d badstat_reach=%x sel_reach=%x size=%d max_reach_ago=%f",
9bc774d6 824 n_badstats_sources, n_sel_sources, (unsigned int)max_badstat_reach,
5bc9c0d0 825 (unsigned int)max_sel_reach, max_sel_reach_size, max_reach_sample_ago);
05e002cd
ML
826
827 /* Wait for the next call if we have no source selected and there is
828 a source with bad stats (has less than 3 samples) with reachability
829 equal to shifted maximum reachability of sources with valid stats.
830 This delays selecting source on start with servers using the same
831 polling interval until they all have valid stats. */
5bc9c0d0
ML
832 if (n_badstats_sources && n_sel_sources && selected_source_index == INVALID_SOURCE &&
833 max_sel_reach_size < SOURCE_REACH_BITS && max_sel_reach >> 1 == max_badstat_reach) {
0f8368bc 834 mark_ok_sources(SRC_WAITS_STATS);
6f84d2fa 835 return;
0f8368bc 836 }
6f84d2fa
ML
837
838 if (n_endpoints == 0) {
839 /* No sources provided valid endpoints */
840 if (selected_source_index != INVALID_SOURCE) {
8f062454 841 log_selection_message("Can't synchronise: no selectable sources", NULL);
6f84d2fa
ML
842 selected_source_index = INVALID_SOURCE;
843 }
05e002cd
ML
844 return;
845 }
846
88840341 847 /* Now sort the endpoint list */
6f84d2fa
ML
848 qsort((void *) sort_list, n_endpoints, sizeof(struct Sort_Element), compare_sort_elements);
849
850 /* Now search for the interval which is contained in the most
851 individual source intervals. Any source which overlaps this
852 will be a candidate.
853
854 If we get a case like
855
856 <----------------------->
62d61de9
ML
857 <-->
858 <-->
859 <===========>
6f84d2fa
ML
860
861 we will build the interval as shown with '=', whereas with an extra source we get
62d61de9 862
6f84d2fa 863 <----------------------->
62d61de9
ML
864 <------->
865 <-->
866 <-->
867 <==>
6f84d2fa
ML
868
869 The first case is just bad luck - we need extra sources to
870 detect the falseticker, so just make an arbitrary choice based
871 on stratum & stability etc.
936f5cb0
ML
872
873 Intervals from sources specified with the trust option have higher
874 priority in the search.
6f84d2fa
ML
875 */
876
936f5cb0 877 trust_depth = best_trust_depth = 0;
6f84d2fa
ML
878 depth = best_depth = 0;
879 best_lo = best_hi = 0.0;
880
881 for (i = 0; i < n_endpoints; i++) {
882 switch (sort_list[i].tag) {
883 case LOW:
884 depth++;
936f5cb0
ML
885 if (sources[sort_list[i].index]->sel_options & SRC_SELECT_TRUST)
886 trust_depth++;
887 if (trust_depth > best_trust_depth ||
888 (trust_depth == best_trust_depth && depth > best_depth)) {
889 best_trust_depth = trust_depth;
6f84d2fa
ML
890 best_depth = depth;
891 best_lo = sort_list[i].offset;
892 }
893 break;
894 case HIGH:
936f5cb0 895 if (trust_depth == best_trust_depth && depth == best_depth)
6f84d2fa 896 best_hi = sort_list[i].offset;
936f5cb0
ML
897 if (sources[sort_list[i].index]->sel_options & SRC_SELECT_TRUST)
898 trust_depth--;
6f84d2fa
ML
899 depth--;
900 break;
901 default:
902 assert(0);
903 }
904 }
88840341 905
936f5cb0
ML
906 if (best_depth <= n_sel_sources / 2 && !best_trust_depth) {
907 /* Could not even get half the reachable sources to agree and there
908 are no trusted sources - clearly we can't synchronise */
6f84d2fa
ML
909
910 if (selected_source_index != INVALID_SOURCE) {
911 log_selection_message("Can't synchronise: no majority", NULL);
912 REF_SetUnsynchronised();
913 selected_source_index = INVALID_SOURCE;
88840341
RC
914 }
915
6f84d2fa
ML
916 /* .. and mark all sources as falsetickers (so they appear thus
917 on the outputs from the command client) */
0f8368bc 918 mark_ok_sources(SRC_FALSETICKER);
88840341 919
6f84d2fa
ML
920 return;
921 }
88840341 922
6f84d2fa
ML
923 /* We have our interval, now work out which source are in it,
924 i.e. build list of admissible sources. */
88840341 925
6f84d2fa 926 n_sel_sources = 0;
88840341 927
6f84d2fa 928 for (i = 0; i < n_sources; i++) {
936f5cb0
ML
929 /* This should be the same condition to get into the endpoint
930 list */
6f84d2fa
ML
931 if (sources[i]->status != SRC_OK)
932 continue;
933
936f5cb0
ML
934 /* Check if source's interval contains the best interval, or is wholly
935 contained within it. If there are any trusted sources the first
936 condition is applied only to them to not allow non-trusted sources to
937 move the final offset outside the interval. */
938 if (((!best_trust_depth || sources[i]->sel_options & SRC_SELECT_TRUST) &&
939 sources[i]->sel_info.lo_limit <= best_lo &&
6f84d2fa
ML
940 sources[i]->sel_info.hi_limit >= best_hi) ||
941 (sources[i]->sel_info.lo_limit >= best_lo &&
942 sources[i]->sel_info.hi_limit <= best_hi)) {
88840341 943
6f84d2fa 944 sel_sources[n_sel_sources++] = i;
e98f76e0
ML
945
946 if (sources[i]->sel_options & SRC_SELECT_REQUIRE)
947 sel_req_source = 0;
6e9bfac0
ML
948 } else if (sources[i]->sel_info.lo_limit <= best_lo &&
949 sources[i]->sel_info.hi_limit >= best_hi) {
950 sources[i]->status = SRC_UNTRUSTED;
88840341 951 } else {
6f84d2fa
ML
952 sources[i]->status = SRC_FALSETICKER;
953 }
954 }
88840341 955
e98f76e0 956 if (!n_sel_sources || sel_req_source || n_sel_sources < CNF_GetMinSources()) {
6f84d2fa 957 if (selected_source_index != INVALID_SOURCE) {
1bb27320 958 log_selection_message("Can't synchronise: %s selectable sources",
e98f76e0
ML
959 !n_sel_sources ? "no" :
960 sel_req_source ? "no required source in" : "not enough");
6f84d2fa
ML
961 selected_source_index = INVALID_SOURCE;
962 }
1bb27320 963 mark_ok_sources(SRC_WAITS_SOURCES);
6f84d2fa
ML
964 return;
965 }
f924862e 966
4883086f
ML
967 /* Enable the selectable sources (and trusted if there are any) to
968 vote on leap seconds */
969 for (i = 0; i < n_sel_sources; i++) {
6f84d2fa 970 index = sel_sources[i];
82c4bfe5
ML
971 if (best_trust_depth && !(sources[index]->sel_options & SRC_SELECT_TRUST))
972 continue;
4883086f 973 sources[index]->leap_vote = 1;
6f84d2fa 974 }
f924862e 975
6f84d2fa
ML
976 /* If there are any sources with prefer option, reduce the list again
977 only to the preferred sources */
4253075a 978 for (i = 0; i < n_sel_sources; i++) {
fa15fb3d 979 if (sources[sel_sources[i]]->sel_options & SRC_SELECT_PREFER)
4253075a 980 break;
6f84d2fa 981 }
4253075a
ML
982 if (i < n_sel_sources) {
983 for (i = j = 0; i < n_sel_sources; i++) {
fa15fb3d 984 if (!(sources[sel_sources[i]]->sel_options & SRC_SELECT_PREFER))
0f8368bc 985 sources[sel_sources[i]]->status = SRC_NONPREFERRED;
4253075a
ML
986 else
987 sel_sources[j++] = sel_sources[i];
0f8368bc 988 }
4253075a 989 assert(j > 0);
6f84d2fa
ML
990 n_sel_sources = j;
991 sel_prefer = 1;
992 } else {
993 sel_prefer = 0;
994 }
88840341 995
6f84d2fa 996 /* Find minimum stratum */
db510a95 997
6f84d2fa
ML
998 index = sel_sources[0];
999 min_stratum = sources[index]->sel_info.stratum;
1000 for (i = 1; i < n_sel_sources; i++) {
1001 index = sel_sources[i];
1002 stratum = sources[index]->sel_info.stratum;
1003 if (stratum < min_stratum)
1004 min_stratum = stratum;
1005 }
9cf08fc7 1006
6f84d2fa 1007 /* Update scores and find the source with maximum score */
db510a95 1008
6f84d2fa
ML
1009 max_score_index = INVALID_SOURCE;
1010 max_score = 0.0;
1011 sel_src_distance = 0.0;
db510a95 1012
6f84d2fa
ML
1013 if (selected_source_index != INVALID_SOURCE)
1014 sel_src_distance = sources[selected_source_index]->sel_info.root_distance +
1015 (sources[selected_source_index]->sel_info.stratum - min_stratum) * stratum_weight;
db510a95 1016
6f84d2fa
ML
1017 for (i = 0; i < n_sources; i++) {
1018 /* Reset score for non-selectable sources */
0f8368bc 1019 if (sources[i]->status != SRC_OK ||
fa15fb3d 1020 (sel_prefer && !(sources[i]->sel_options & SRC_SELECT_PREFER))) {
6f84d2fa 1021 sources[i]->sel_score = 1.0;
0f8368bc 1022 sources[i]->distant = DISTANT_PENALTY;
6f84d2fa
ML
1023 continue;
1024 }
db510a95 1025
6f84d2fa
ML
1026 distance = sources[i]->sel_info.root_distance +
1027 (sources[i]->sel_info.stratum - min_stratum) * stratum_weight;
1028 if (sources[i]->type == SRC_NTP)
1029 distance += reselect_distance;
db510a95 1030
6f84d2fa
ML
1031 if (selected_source_index != INVALID_SOURCE) {
1032 /* Update score, but only for source pairs where one source
1033 has a new sample */
1034 if (sources[i] == updated_inst ||
1035 sources[selected_source_index] == updated_inst) {
db510a95 1036
6f84d2fa 1037 sources[i]->sel_score *= sel_src_distance / distance;
db510a95 1038
6f84d2fa
ML
1039 if (sources[i]->sel_score < 1.0)
1040 sources[i]->sel_score = 1.0;
1041 }
1042 } else {
1043 /* When there is no selected source yet, assign scores so that the
1044 source with minimum distance will have maximum score. The scores
1045 will be reset when the source is selected later in this function. */
1046 sources[i]->sel_score = 1.0 / distance;
1047 }
db510a95 1048
9bc774d6 1049 DEBUG_LOG("select score=%f refid=%"PRIx32" match_refid=%"PRIx32" status=%u dist=%f",
6f84d2fa
ML
1050 sources[i]->sel_score, sources[i]->ref_id,
1051 updated_inst ? updated_inst->ref_id : 0,
1052 sources[i]->status, distance);
db510a95 1053
6f84d2fa
ML
1054 if (max_score < sources[i]->sel_score) {
1055 max_score = sources[i]->sel_score;
1056 max_score_index = i;
1057 }
1058 }
352f03d4 1059
6f84d2fa 1060 assert(max_score_index != INVALID_SOURCE);
db510a95 1061
6f84d2fa
ML
1062 /* Is the current source still a survivor and no other source has reached
1063 the score limit? */
1064 if (selected_source_index == INVALID_SOURCE ||
0f8368bc 1065 sources[selected_source_index]->status != SRC_OK ||
6f84d2fa 1066 (max_score_index != selected_source_index && max_score > SCORE_LIMIT)) {
88840341 1067
5f689412
ML
1068 /* Before selecting the new synchronisation source wait until the reference
1069 can be updated */
1070 if (sources[max_score_index]->updates == 0) {
1071 selected_source_index = INVALID_SOURCE;
0f8368bc 1072 mark_ok_sources(SRC_WAITS_UPDATE);
f282856c 1073 DEBUG_LOG("best source has no updates");
5f689412
ML
1074 return;
1075 }
88840341 1076
6f84d2fa
ML
1077 selected_source_index = max_score_index;
1078 log_selection_message("Selected source %s",
1079 source_to_string(sources[selected_source_index]));
88840341 1080
6f84d2fa
ML
1081 /* New source has been selected, reset all scores */
1082 for (i = 0; i < n_sources; i++) {
1083 sources[i]->sel_score = 1.0;
0f8368bc 1084 sources[i]->distant = 0;
88840341 1085 }
88840341 1086 }
6f84d2fa 1087
0f8368bc 1088 sources[selected_source_index]->status = SRC_SELECTED;
6f84d2fa
ML
1089
1090 /* Don't update reference when the selected source has no new samples */
1091
0f8368bc
ML
1092 if (sources[selected_source_index]->updates == 0) {
1093 /* Mark the remaining sources as last combine_sources() call */
1094
1095 for (i = 0; i < n_sel_sources; i++) {
1096 index = sel_sources[i];
1097 if (sources[index]->status == SRC_OK)
1098 sources[index]->status = sources[index]->distant ?
1099 SRC_DISTANT : SRC_UNSELECTED;
1100 }
6f84d2fa 1101 return;
0f8368bc 1102 }
6f84d2fa
ML
1103
1104 for (i = 0; i < n_sources; i++)
1105 sources[i]->updates = 0;
1106
4883086f
ML
1107 leap_status = get_leap_status();
1108
6f84d2fa
ML
1109 /* Now just use the statistics of the selected source combined with
1110 the other selectable sources for trimming the local clock */
1111
1112 SST_GetTrackingData(sources[selected_source_index]->stats, &ref_time,
1113 &src_offset, &src_offset_sd,
cca2ef46 1114 &src_frequency, &src_frequency_sd, &src_skew,
6f84d2fa
ML
1115 &src_root_delay, &src_root_dispersion);
1116
ca73e34f
ML
1117 combined = combine_sources(n_sel_sources, &ref_time, &src_offset, &src_offset_sd,
1118 &src_frequency, &src_frequency_sd, &src_skew);
6f84d2fa
ML
1119
1120 REF_SetReference(sources[selected_source_index]->sel_info.stratum,
1121 leap_status, combined,
1122 sources[selected_source_index]->ref_id,
1123 sources[selected_source_index]->ip_addr,
1124 &ref_time, src_offset, src_offset_sd,
ca73e34f 1125 src_frequency, src_frequency_sd, src_skew,
6f84d2fa 1126 src_root_delay, src_root_dispersion);
88840341
RC
1127}
1128
6e96b4ba
ML
1129/* ================================================== */
1130/* Force reselecting the best source */
1131
1132void
1133SRC_ReselectSource(void)
1134{
1135 selected_source_index = INVALID_SOURCE;
0094128c 1136 SRC_SelectSource(NULL);
6e96b4ba
ML
1137}
1138
88840341
RC
1139/* ================================================== */
1140
8d3d45ea
ML
1141void
1142SRC_SetReselectDistance(double distance)
1143{
1144 if (reselect_distance != distance) {
1145 reselect_distance = distance;
f282856c 1146 LOG(LOGS_INFO, "New reselect distance %f", distance);
8d3d45ea
ML
1147 }
1148}
1149
88840341
RC
1150/* ================================================== */
1151/* This routine is registered as a callback with the local clock
1152 module, to be called whenever the local clock changes frequency or
1153 is slewed. It runs through all the existing source statistics, and
1154 adjusts them to make them look as though they were sampled under
1155 the new regime. */
1156
1157static void
d0dfa1de
ML
1158slew_sources(struct timespec *raw, struct timespec *cooked, double dfreq,
1159 double doffset, LCL_ChangeType change_type, void *anything)
88840341
RC
1160{
1161 int i;
1162
1163 for (i=0; i<n_sources; i++) {
a33a9551
ML
1164 if (change_type == LCL_ChangeUnknownStep) {
1165 SST_ResetInstance(sources[i]->stats);
1166 } else {
1167 SST_SlewSamples(sources[i]->stats, cooked, dfreq, doffset);
1168 }
1169 }
1170
1171 if (change_type == LCL_ChangeUnknownStep) {
18d7ea62 1172 /* Update selection status */
a33a9551 1173 SRC_SelectSource(NULL);
88840341 1174 }
88840341
RC
1175}
1176
0f70959d
ML
1177/* ================================================== */
1178/* This routine is called when an indeterminate offset is introduced
1179 into the local time. */
1180
1181static void
1182add_dispersion(double dispersion, void *anything)
1183{
1184 int i;
1185
1186 for (i = 0; i < n_sources; i++) {
1187 SST_AddDispersion(sources[i]->stats, dispersion);
1188 }
1189}
1190
5c45e4cc
ML
1191/* ================================================== */
1192
1193static
e18903a6 1194FILE *open_dumpfile(SRC_Instance inst, char mode)
5c45e4cc 1195{
e18903a6 1196 char filename[64], *dumpdir;
fb5d4f1d
ML
1197
1198 dumpdir = CNF_GetDumpDir();
1199 if (dumpdir[0] == '\0') {
f282856c 1200 LOG(LOGS_WARN, "dumpdir not specified");
fb5d4f1d
ML
1201 return NULL;
1202 }
5c45e4cc
ML
1203
1204 /* Include IP address in the name for NTP sources, or reference ID in hex */
672b98dd 1205 if (inst->type == SRC_NTP && UTI_IsIPReal(inst->ip_addr))
e18903a6 1206 snprintf(filename, sizeof (filename), "%s", source_to_string(inst));
672b98dd 1207 else if (inst->type == SRC_REFCLOCK)
e18903a6 1208 snprintf(filename, sizeof (filename), "refid:%08"PRIx32, inst->ref_id);
672b98dd
ML
1209 else
1210 return NULL;
5c45e4cc 1211
e18903a6 1212 return UTI_OpenFile(dumpdir, filename, ".dat", mode, 0644);
5c45e4cc
ML
1213}
1214
88840341
RC
1215/* ================================================== */
1216/* This is called to dump out the source measurement registers */
1217
1218void
1219SRC_DumpSources(void)
1220{
1221 FILE *out;
88840341 1222 int i;
6d42dd86
ML
1223
1224 for (i = 0; i < n_sources; i++) {
e18903a6 1225 out = open_dumpfile(sources[i], 'w');
5c45e4cc
ML
1226 if (!out)
1227 continue;
1228 SST_SaveToFile(sources[i]->stats, out);
1229 fclose(out);
88840341 1230 }
88840341
RC
1231}
1232
1233/* ================================================== */
1234
1235void
1236SRC_ReloadSources(void)
1237{
1238 FILE *in;
88840341 1239 int i;
88840341 1240
5c45e4cc 1241 for (i = 0; i < n_sources; i++) {
e18903a6 1242 in = open_dumpfile(sources[i], 'r');
5c45e4cc
ML
1243 if (!in)
1244 continue;
1245 if (!SST_LoadFromFile(sources[i]->stats, in))
f282856c 1246 LOG(LOGS_WARN, "Could not load dump file for %s",
5c45e4cc 1247 source_to_string(sources[i]));
06f93e7b 1248 else
f282856c 1249 LOG(LOGS_INFO, "Loaded dump file for %s",
06f93e7b 1250 source_to_string(sources[i]));
5c45e4cc 1251 fclose(in);
88840341
RC
1252 }
1253}
1254
1255/* ================================================== */
1256
a06a5f1b
ML
1257void
1258SRC_RemoveDumpFiles(void)
1259{
2fc8edac 1260 char pattern[PATH_MAX], name[64], *dumpdir, *s;
a06a5f1b
ML
1261 IPAddr ip_addr;
1262 glob_t gl;
1263 size_t i;
1264
1265 dumpdir = CNF_GetDumpDir();
1266 if (dumpdir[0] == '\0' ||
1267 snprintf(pattern, sizeof (pattern), "%s/*.dat", dumpdir) >= sizeof (pattern))
1268 return;
1269
1270 if (glob(pattern, 0, NULL, &gl))
1271 return;
1272
1273 for (i = 0; i < gl.gl_pathc; i++) {
1274 s = strrchr(gl.gl_pathv[i], '/');
1275 if (!s || snprintf(name, sizeof (name), "%s", s + 1) >= sizeof (name))
1276 continue;
1277
1278 /* Remove .dat extension */
1279 if (strlen(name) < 4)
1280 continue;
1281 name[strlen(name) - 4] = '\0';
1282
1283 /* Check if it looks like name of an actual dump file */
1284 if (strncmp(name, "refid:", 6) && !UTI_StringToIP(name, &ip_addr))
1285 continue;
1286
e18903a6
ML
1287 if (!UTI_RemoveFile(NULL, gl.gl_pathv[i], NULL))
1288 ;
a06a5f1b
ML
1289 }
1290
1291 globfree(&gl);
1292}
1293
1294/* ================================================== */
1295
e7a25426
ML
1296void
1297SRC_ResetSources(void)
1298{
1299 int i;
1300
1301 for (i = 0; i < n_sources; i++)
1302 SRC_ResetInstance(sources[i]);
1303}
1304
1305/* ================================================== */
1306
88840341
RC
1307int
1308SRC_IsSyncPeer(SRC_Instance inst)
1309{
1310 if (inst->index == selected_source_index) {
1311 return 1;
1312 } else {
1313 return 0;
1314 }
1315
1316}
1317
1318/* ================================================== */
1319
4e66b5ce
ML
1320int
1321SRC_IsReachable(SRC_Instance inst)
1322{
1323 return inst->reachability != 0;
1324}
1325
1326/* ================================================== */
1327
88840341
RC
1328int
1329SRC_ReadNumberOfSources(void)
1330{
1331 return n_sources;
1332}
1333
1334/* ================================================== */
1335
8671002b
ML
1336int
1337SRC_ActiveSources(void)
1338{
1339 int i, r;
1340
1341 for (i = r = 0; i < n_sources; i++)
1342 if (sources[i]->active)
1343 r++;
1344
1345 return r;
1346}
1347
1348/* ================================================== */
1349
88840341 1350int
d0dfa1de 1351SRC_ReportSource(int index, RPT_SourceReport *report, struct timespec *now)
88840341
RC
1352{
1353 SRC_Instance src;
1354 if ((index >= n_sources) || (index < 0)) {
1355 return 0;
1356 } else {
1357 src = sources[index];
8265ff28 1358
8265ff28
ML
1359 if (src->ip_addr)
1360 report->ip_addr = *src->ip_addr;
1361 else {
1362 /* Use refid as an address */
1363 report->ip_addr.addr.in4 = src->ref_id;
1364 report->ip_addr.family = IPADDR_INET4;
1365 }
1366
88840341 1367 switch (src->status) {
88840341
RC
1368 case SRC_FALSETICKER:
1369 report->state = RPT_FALSETICKER;
1370 break;
0f8368bc
ML
1371 case SRC_JITTERY:
1372 report->state = RPT_JITTERY;
1373 break;
6e9bfac0 1374 case SRC_UNTRUSTED:
1bb27320 1375 case SRC_WAITS_SOURCES:
0f8368bc
ML
1376 case SRC_NONPREFERRED:
1377 case SRC_WAITS_UPDATE:
1378 case SRC_DISTANT:
1379 case SRC_OUTLIER:
1380 report->state = RPT_OUTLIER;
88840341 1381 break;
0f8368bc
ML
1382 case SRC_UNSELECTED:
1383 report->state = RPT_CANDIDATE;
1384 break;
1385 case SRC_SELECTED:
1386 report->state = RPT_SYNC;
1387 break;
2e74beeb 1388 default:
316d50d6 1389 report->state = RPT_UNREACH;
2e74beeb 1390 break;
88840341 1391 }
19b3c5be 1392
fa15fb3d 1393 report->sel_options = src->sel_options;
19b3c5be
ML
1394 report->reachability = src->reachability;
1395
88840341
RC
1396 /* Call stats module to fill out estimates */
1397 SST_DoSourceReport(src->stats, report, now);
1398
1399 return 1;
1400 }
1401
1402}
1403
1404/* ================================================== */
1405
1406int
d0dfa1de 1407SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report, struct timespec *now)
88840341
RC
1408{
1409 SRC_Instance src;
1410
1411 if ((index >= n_sources) || (index < 0)) {
1412 return 0;
1413 } else {
1414 src = sources[index];
1570f97e 1415 report->ref_id = src->ref_id;
8265ff28
ML
1416 if (src->ip_addr)
1417 report->ip_addr = *src->ip_addr;
1418 else
1419 report->ip_addr.family = IPADDR_UNSPEC;
b32432c2 1420 SST_DoSourcestatsReport(src->stats, report, now);
88840341
RC
1421 return 1;
1422 }
1423}
1424
1425/* ================================================== */
1426
ac30bb06
ML
1427SRC_Type
1428SRC_GetType(int index)
1429{
1430 if ((index >= n_sources) || (index < 0))
1431 return -1;
1432 return sources[index]->type;
1433}
1434
1435/* ================================================== */