ntp: replace non-pool sources when unreachable or falsetickers

Sources that are not specified as a pool and have a name (i.e. not
specified by an IP address or added from chronyc) will be replaced with
a newly resolved address of the name when they become unreachable or
falseticker too.
This commit is contained in:
Miroslav Lichvar 2015-05-15 18:38:03 +02:00
parent 4eeaf34295
commit e949cf5967
3 changed files with 35 additions and 37 deletions

View file

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

View file

@ -581,9 +581,8 @@ rtcsync
When using a pool of NTP servers (one name is used for multiple servers which When using a pool of NTP servers (one name is used for multiple servers which
may change over time), it's better to specify them with the @code{pool} may change over time), it's better to specify them with the @code{pool}
directive instead of multiple @code{server} directives in order to allow directive instead of multiple @code{server} directives. The configuration file
@code{chronyd} to replace unreachable or bad servers automatically. The could in this case look like
configuration file could in this case look like
@example @example
pool pool.ntp.org iburst pool pool.ntp.org iburst

View file

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