@c {{{ pool
@node pool directive
@subsection pool
-The syntax of this directive is identical to that for the @code{server}
+The syntax of this directive is similar to that for the @code{server}
directive (@pxref{server directive}), except that it is used to specify a pool
of NTP servers rather than a single NTP server. The pool name is expected to
-resolve to multiple addresses which change over time.
+resolve to multiple addresses which may change over time.
+
+All options valid in the @code{server} directive can be used in this directive
+too. There is one option specific to @code{pool} directive: @code{maxsources}
+sets the maximum number of sources that can be used from the pool, the default
+value is 4.
-On start, a source will be added for each resolved address. When a source from
-the pool is unreachable or marked as falseticker, @code{chronyd} will try to
-replace the source with a newly resolved address of the pool.
+On start, when the pool name is resolved, @code{chronyd} will add up to 16
+sources, one for each resolved address. When the number of sources from which
+at least one valid reply was received reaches @code{maxsources}, the other
+sources will be removed. When a pool source is unreachable or marked as
+falseticker, @code{chronyd} will try to replace the source with a newly
+resolved address of the pool.
An example of the pool directive is
@example
-pool pool.ntp.org iburst
+pool pool.ntp.org iburst maxsources 3
@end example
-
@c }}}
@c {{{ port
@node port directive
NCR_Instance data; /* Data for the protocol engine for this source */
int pool; /* Number of the pool from which was this source
added or INVALID_POOL */
+ int tentative; /* Flag indicating there was no valid response
+ yet and the source may be removed if other
+ sources from the pool respond first */
} SourceRecord;
/* Hash table of SourceRecord, the size should be a power of two */
struct SourcePool {
char *name;
int port;
+ /* Number of sources added from this pool (ignoring tentative sources) */
+ int sources;
+ /* Maximum number of sources */
+ int max_sources;
};
/* Array of SourcePool */
record->data = NCR_GetInstance(remote_addr, type, params);
record->remote_addr = NCR_GetRemoteAddress(record->data);
record->pool = pool;
+ record->tentative = pool != INVALID_POOL ? 1 : 0;
if (auto_start_sources)
NCR_StartInstance(record->data);
sp = (struct SourcePool *)ARR_GetNewElement(pools);
sp->name = Strdup(name);
sp->port = port;
+ sp->sources = 0;
+ sp->max_sources = params->max_sources;
us->new_source.pool = ARR_GetSize(pools) - 1;
us->new_source.max_new_sources = MAX_POOL_SOURCES;
}
/* ================================================== */
+static void remove_tentative_pool_sources(int pool)
+{
+ SourceRecord *record;
+ unsigned int i, removed;
+
+ for (i = removed = 0; i < ARR_GetSize(records); i++) {
+ record = get_record(i);
+
+ if (!record->remote_addr || record->pool != pool || !record->tentative)
+ continue;
+
+ DEBUG_LOG(LOGF_NtpSources, "removing tentative source %s",
+ UTI_IPToString(&record->remote_addr->ip_addr));
+
+ clean_source_record(record);
+ removed++;
+ }
+
+ if (removed)
+ rehash_records();
+}
+
/* This routine is called by ntp_io when a new packet arrives off the network,
possibly with an authentication tail */
void
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length)
{
+ SourceRecord *record;
+ struct SourcePool *pool;
int slot, found;
assert(initialised);
find_slot(remote_addr, &slot, &found);
if (found == 2) { /* Must match IP address AND port number */
- NCR_ProcessKnown(message, now, now_err, get_record(slot)->data,
- local_addr, length);
+ record = get_record(slot);
+
+ if (!NCR_ProcessKnown(message, now, now_err, record->data, local_addr, length))
+ return;
+
+ if (record->tentative) {
+ /* First reply from a pool source */
+ record->tentative = 0;
+
+ assert(record->pool != INVALID_POOL);
+ pool = (struct SourcePool *)ARR_GetElement(pools, record->pool);
+ pool->sources++;
+
+ DEBUG_LOG(LOGF_NtpSources, "pool %s has %d confirmed sources",
+ pool->name, pool->sources);
+
+ /* If the number of sources reached the configured maximum, remove
+ the tentative sources added from this pool */
+ if (pool->sources >= pool->max_sources)
+ remove_tentative_pool_sources(record->pool);
+ }
} else {
NCR_ProcessUnknown(message, now, now_err, remote_addr, local_addr, length);
}