diff --git a/chrony.texi b/chrony.texi index b4681ae..f203769 100644 --- a/chrony.texi +++ b/chrony.texi @@ -2387,6 +2387,10 @@ nanosecond). @item precision Refclock precision (in seconds). The default is 1e-6 (1 microsecond) for SHM refclock, and 1e-9 (1 nanosecond) for SOCK and PPS refclocks. +@item prefer +Prefer this source over sources without prefer option. +@item noselect +Never select this source. This is particularly useful for monitoring. @end table @c }}} @@ -2625,6 +2629,12 @@ selecting that source. This is useful with low stratum sources that are known to be unrealiable or inaccurate and which should be used only when other sources are unreachable. +@item prefer +Prefer this source over sources without prefer option. + +@item noselect +Never select this source. This is particularly useful for monitoring. + @end table @c }}} @c {{{ tempcomp diff --git a/client.c b/client.c index cfe518d..1e44031 100644 --- a/client.c +++ b/client.c @@ -934,6 +934,9 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line) if (data.params.min_stratum) { fprintf(stderr, "Option minstratum not supported\n"); break; + } else if (data.params.sel_option != SRC_SelectNormal) { + fprintf(stderr, "Options noselect and prefer not supported\n"); + break; } msg->data.ntp_source.port = htonl((unsigned long) data.port); diff --git a/cmdmon.c b/cmdmon.c index e382e10..f230bbc 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -1246,7 +1246,11 @@ handle_add_server(CMD_Request *rx_message, CMD_Reply *tx_message) params.iburst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_IBURST ? 1 : 0; params.max_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay); params.max_delay_ratio = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio); - params.min_stratum = 0; /* not transmitted in cmdmon protocol yet */ + + /* not transmitted in cmdmon protocol yet */ + params.min_stratum = 0; + params.sel_option = SRC_SelectNormal; + status = NSR_AddSource(&rem_addr, NTP_SERVER, ¶ms); switch (status) { case NSR_Success: @@ -1288,7 +1292,11 @@ handle_add_peer(CMD_Request *rx_message, CMD_Reply *tx_message) params.iburst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_IBURST ? 1 : 0; params.max_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay); params.max_delay_ratio = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio); - params.min_stratum = 0; /* not transmitted in cmdmon protocol yet */ + + /* not transmitted in cmdmon protocol yet */ + params.min_stratum = 0; + params.sel_option = SRC_SelectNormal; + status = NSR_AddSource(&rem_addr, NTP_PEER, ¶ms); switch (status) { case NSR_Success: diff --git a/cmdparse.c b/cmdparse.c index 9f514c1..2d7c543 100644 --- a/cmdparse.c +++ b/cmdparse.c @@ -60,6 +60,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src) src->params.auto_offline = 0; src->params.iburst = 0; src->params.min_stratum = 0; + src->params.sel_option = SRC_SelectNormal; result = CPS_Success; @@ -163,6 +164,12 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src) } else { line += n; } + + } else if (!strncasecmp(cmd, "noselect", 8)) { + src->params.sel_option = SRC_SelectNoselect; + + } else if (!strncasecmp(cmd, "prefer", 6)) { + src->params.sel_option = SRC_SelectPrefer; } else { result = CPS_BadOption; diff --git a/conf.c b/conf.c index f1c4914..552a5fd 100644 --- a/conf.c +++ b/conf.c @@ -448,6 +448,7 @@ parse_refclock(const char *line) const char *tmp; char name[5], cmd[10 + 1], *param; unsigned char ref[5]; + SRC_SelectOption sel_option; i = n_refclock_sources; if (i >= MAX_RCL_SOURCES) @@ -462,6 +463,7 @@ parse_refclock(const char *line) precision = 0.0; ref_id = 0; lock_ref_id = 0; + sel_option = SRC_SelectNormal; if (sscanf(line, "%4s%n", name, &n) != 1) { LOG(LOGS_WARN, LOGF_Configure, "Could not read refclock driver name at line %d", line_number); @@ -518,6 +520,12 @@ parse_refclock(const char *line) } else if (!strncasecmp(cmd, "precision", 9)) { if (sscanf(line, "%lf%n", &precision, &n) != 1) break; + } else if (!strncasecmp(cmd, "noselect", 8)) { + n = 0; + sel_option = SRC_SelectNoselect; + } else if (!strncasecmp(cmd, "prefer", 6)) { + n = 0; + sel_option = SRC_SelectPrefer; } else { LOG(LOGS_WARN, LOGF_Configure, "Unknown refclock parameter %s at line %d", cmd, line_number); break; @@ -534,6 +542,7 @@ parse_refclock(const char *line) refclock_sources[i].offset = offset; refclock_sources[i].delay = delay; refclock_sources[i].precision = precision; + refclock_sources[i].sel_option = sel_option; refclock_sources[i].ref_id = ref_id; refclock_sources[i].lock_ref_id = lock_ref_id; diff --git a/ntp_core.c b/ntp_core.c index c00c462..7f8d3ca 100644 --- a/ntp_core.c +++ b/ntp_core.c @@ -312,7 +312,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar result->local_poll = params->minpoll; /* Create a source instance for this NTP source */ - result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr), SRC_NTP, &result->remote_addr.ip_addr); + result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr), SRC_NTP, params->sel_option, &result->remote_addr.ip_addr); result->local_rx.tv_sec = 0; result->local_rx.tv_usec = 0; diff --git a/refclock.c b/refclock.c index 635faab..8aed917 100644 --- a/refclock.c +++ b/refclock.c @@ -236,7 +236,7 @@ RCL_AddRefclock(RefclockParameters *params) filter_init(&inst->filter, params->filter_length); - inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, NULL); + inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_option, NULL); #if 0 LOG(LOGS_INFO, LOGF_Refclock, "refclock added poll=%d dpoll=%d filter=%d", diff --git a/refclock.h b/refclock.h index 1e08a68..438f1dd 100644 --- a/refclock.h +++ b/refclock.h @@ -43,6 +43,7 @@ typedef struct { double offset; double delay; double precision; + SRC_SelectOption sel_option; } RefclockParameters; typedef struct RCL_Instance_Record *RCL_Instance; diff --git a/sources.c b/sources.c index 98e4dc7..a019890 100644 --- a/sources.c +++ b/sources.c @@ -100,6 +100,9 @@ struct SRC_Instance_Record { /* Type of the source */ SRC_Type type; + /* Options used when selecting sources */ + SRC_SelectOption sel_option; + struct SelectInfo sel_info; }; @@ -165,7 +168,7 @@ void SRC_Finalise(void) /* Function to create a new instance. This would be called by one of the individual source-type instance creation routines. */ -SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, IPAddr *addr) +SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr) { SRC_Instance result; @@ -196,6 +199,7 @@ SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, IPAddr * result->reachable = 0; result->status = SRC_BAD_STATS; result->type = type; + result->sel_option = sel_option; n_sources++; @@ -414,7 +418,7 @@ SRC_SelectSource(unsigned long match_addr) n_reachable_sources = 0; for (i=0; ireachable) { + if (sources[i]->reachable && sources[i]->sel_option != SRC_SelectNoselect) { ++n_reachable_sources; @@ -638,11 +642,39 @@ SRC_SelectSource(unsigned long match_addr) } n_sel_sources = j; - /* Now find minimum stratum. If none are left now, - tough. RFC1305 is not so harsh on pruning sources due to - excess variance, which prevents this from happening */ - if (n_sel_sources > 0) { + /* Accept leap second status if more than half of selectable sources agree */ + + for (i=j1=j2=0; ileap_status == LEAP_InsertSecond) { + j1++; + } else if (sources[index]->leap_status == LEAP_DeleteSecond) { + j2++; + } + } + + if (j1 > n_sel_sources / 2) { + leap_status = LEAP_InsertSecond; + } else if (j2 > n_sel_sources / 2) { + leap_status = LEAP_DeleteSecond; + } + + /* If there are any sources with prefer option, reduce the list again + only to the prefer sources */ + for (i=j=0; isel_option == SRC_SelectPrefer) { + sel_sources[j++] = sel_sources[i]; + } + } + if (j > 0) { + n_sel_sources = j; + } + + /* Now find minimum stratum. If none are left now, + tough. RFC1305 is not so harsh on pruning sources due to + excess variance, which prevents this from happening */ + index = sel_sources[0]; min_stratum = sources[index]->sel_info.stratum; for (i=1; isel_info.root_dispersion); - /* Accept leap second status if more than half of selectable sources agree */ - - for (i=j1=j2=0; ileap_status == LEAP_InsertSecond) { - j1++; - } else if (sources[index]->leap_status == LEAP_DeleteSecond) { - j2++; - } - } - - if (j1 > n_sel_sources / 2) { - leap_status = LEAP_InsertSecond; - } else if (j2 > n_sel_sources / 2) { - leap_status = LEAP_DeleteSecond; - } - if ((match_addr == 0) || (match_addr == sources[selected_source_index]->ref_id)) { diff --git a/sources.h b/sources.h index c1cfffc..aff800a 100644 --- a/sources.h +++ b/sources.h @@ -55,10 +55,17 @@ typedef enum { SRC_REFCLOCK /* Rerefence clock */ } SRC_Type; +/* Options used when selecting sources */ +typedef enum { + SRC_SelectNormal, + SRC_SelectNoselect, + SRC_SelectPrefer +} SRC_SelectOption; + /* Function to create a new instance. This would be called by one of the individual source-type instance creation routines. */ -extern SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, IPAddr *addr); +extern SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr); /* Function to get rid of a source when it is being unconfigured. This may cause the current reference source to be reselected, if this diff --git a/srcparams.h b/srcparams.h index 1fb93e7..1b52369 100644 --- a/srcparams.h +++ b/srcparams.h @@ -31,6 +31,8 @@ #ifndef GOT_SRCPARAMS_H #define GOT_SRCPARAMS_H +#include "sources.h" + typedef struct { int minpoll; int maxpoll; @@ -42,6 +44,7 @@ typedef struct { unsigned long authkey; double max_delay; double max_delay_ratio; + SRC_SelectOption sel_option; } SourceParameters; #define INACTIVE_AUTHKEY 0UL