diff --git a/ntp_core.c b/ntp_core.c index 8fede91..f981953 100644 --- a/ntp_core.c +++ b/ntp_core.c @@ -586,7 +586,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar SRC_NTP, params->sel_options, &result->remote_addr.ip_addr, params->min_samples, params->max_samples, - 0.0); + 0.0, 1.0); result->rx_timeout_id = 0; result->tx_timeout_id = 0; diff --git a/refclock.c b/refclock.c index 754fee6..01e877c 100644 --- a/refclock.c +++ b/refclock.c @@ -260,7 +260,7 @@ RCL_AddRefclock(RefclockParameters *params) filter_init(&inst->filter, params->filter_length, params->max_dispersion); inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_options, NULL, - params->min_samples, params->max_samples, 0.0); + params->min_samples, params->max_samples, 0.0, 0.0); DEBUG_LOG("refclock %s refid=%s poll=%d dpoll=%d filter=%d", params->driver_name, UTI_RefidToString(inst->ref_id), diff --git a/sources.c b/sources.c index 120bb9c..67b61e7 100644 --- a/sources.c +++ b/sources.c @@ -213,8 +213,9 @@ 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(uint32_t ref_id, SRC_Type type, int sel_options, IPAddr *addr, - int min_samples, int max_samples, double min_delay) +SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options, + IPAddr *addr, int min_samples, int max_samples, + double min_delay, double asymmetry) { SRC_Instance result; @@ -226,7 +227,8 @@ SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_optio max_samples = CNF_GetMaxSamples(); result = MallocNew(struct SRC_Instance_Record); - result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples, min_delay); + result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples, + min_delay, asymmetry); if (n_sources == max_n_sources) { /* Reallocate memory */ diff --git a/sources.h b/sources.h index 118d8bd..60d28fd 100644 --- a/sources.h +++ b/sources.h @@ -59,8 +59,9 @@ typedef enum { /* 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(uint32_t ref_id, SRC_Type type, int sel_options, IPAddr *addr, - int min_samples, int max_samples, double min_delay); +extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, int sel_options, + IPAddr *addr, int min_samples, int max_samples, + double min_delay, double asymmetry); /* 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/sourcestats.c b/sourcestats.c index 512648d..a4a9802 100644 --- a/sourcestats.c +++ b/sourcestats.c @@ -85,6 +85,9 @@ struct SST_Stats_Record { /* User defined minimum delay */ double fixed_min_delay; + /* User defined asymmetry of network jitter */ + double fixed_asymmetry; + /* Number of samples currently stored. The samples are stored in circular buffer. */ int n_samples; @@ -200,7 +203,8 @@ SST_Finalise(void) /* This function creates a new instance of the statistics handler */ SST_Stats -SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples, double min_delay) +SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples, + double min_delay, double asymmetry) { SST_Stats inst; inst = MallocNew(struct SST_Stats_Record); @@ -208,6 +212,7 @@ SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_sample inst->min_samples = min_samples; inst->max_samples = max_samples; inst->fixed_min_delay = min_delay; + inst->fixed_asymmetry = asymmetry; SST_SetRefid(inst, refid, addr); SST_ResetInstance(inst); @@ -422,14 +427,43 @@ find_min_delay_sample(SST_Stats inst) minimum network delay. This can significantly improve the accuracy and stability of the estimated offset and frequency. */ +static int +estimate_asymmetry(double *times_back, double *offsets, double *delays, int n, + double *asymmetry, int *asymmetry_run) +{ + double a; + + /* Reset the counter when the regression fails or the sign changes */ + if (!RGR_MultipleRegress(times_back, delays, offsets, n, &a) || + a * *asymmetry_run < 0.0) { + *asymmetry = 0; + *asymmetry_run = 0.0; + return 0; + } + + if (a <= -MIN_ASYMMETRY && *asymmetry_run > -MAX_ASYMMETRY_RUN) + (*asymmetry_run)--; + else if (a >= MIN_ASYMMETRY && *asymmetry_run < MAX_ASYMMETRY_RUN) + (*asymmetry_run)++; + + if (abs(*asymmetry_run) < MIN_ASYMMETRY_RUN) + return 0; + + *asymmetry = CLAMP(-MAX_ASYMMETRY, a, MAX_ASYMMETRY); + + return 1; +} + +/* ================================================== */ + static void correct_asymmetry(SST_Stats inst, double *times_back, double *offsets) { - double asymmetry, min_delay, delays[MAX_SAMPLES * REGRESS_RUNS_RATIO]; + double min_delay, delays[MAX_SAMPLES * REGRESS_RUNS_RATIO]; int i, n; - /* Don't try to estimate the asymmetry with reference clocks */ - if (!inst->ip_addr) + /* Check if the asymmetry was not specified to be zero */ + if (inst->fixed_asymmetry == 0.0) return; min_delay = SST_MinRoundTripDelay(inst); @@ -439,29 +473,17 @@ correct_asymmetry(SST_Stats inst, double *times_back, double *offsets) delays[i] = inst->peer_delays[get_runsbuf_index(inst, i - inst->runs_samples)] - min_delay; - /* Reset the counter when the regression fails or the sign changes */ - if (!RGR_MultipleRegress(times_back, delays, offsets, n, &asymmetry) || - asymmetry * inst->asymmetry_run < 0.0) { - inst->asymmetry_run = 0; - inst->asymmetry = 0.0; - return; + if (fabs(inst->fixed_asymmetry) <= MAX_ASYMMETRY) { + inst->asymmetry = inst->fixed_asymmetry; + } else { + if (!estimate_asymmetry(times_back, offsets, delays, n, + &inst->asymmetry, &inst->asymmetry_run)) + return; } - asymmetry = CLAMP(-MAX_ASYMMETRY, asymmetry, MAX_ASYMMETRY); - - if (asymmetry <= -MIN_ASYMMETRY && inst->asymmetry_run > -MAX_ASYMMETRY_RUN) - inst->asymmetry_run--; - else if (asymmetry >= MIN_ASYMMETRY && inst->asymmetry_run < MAX_ASYMMETRY_RUN) - inst->asymmetry_run++; - - if (abs(inst->asymmetry_run) < MIN_ASYMMETRY_RUN) - return; - /* Correct the offsets */ for (i = 0; i < n; i++) - offsets[i] -= asymmetry * delays[i]; - - inst->asymmetry = asymmetry; + offsets[i] -= inst->asymmetry * delays[i]; } /* ================================================== */ diff --git a/sourcestats.h b/sourcestats.h index dfd93a3..9b34cc6 100644 --- a/sourcestats.h +++ b/sourcestats.h @@ -39,7 +39,8 @@ extern void SST_Finalise(void); /* This function creates a new instance of the statistics handler */ extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr, - int min_samples, int max_samples, double min_delay); + int min_samples, int max_samples, + double min_delay, double asymmetry); /* This function deletes an instance of the statistics handler. */ extern void SST_DeleteInstance(SST_Stats inst); diff --git a/test/unit/sources.c b/test/unit/sources.c index 31a1c03..341e22e 100644 --- a/test/unit/sources.c +++ b/test/unit/sources.c @@ -53,7 +53,8 @@ test_unit(void) DEBUG_LOG("added source %d options %d", j, sel_options); srcs[j] = SRC_CreateNewInstance(UTI_IPToRefid(&addr), SRC_NTP, sel_options, &addr, - SRC_DEFAULT_MINSAMPLES, SRC_DEFAULT_MAXSAMPLES, 0.0); + SRC_DEFAULT_MINSAMPLES, SRC_DEFAULT_MAXSAMPLES, + 0.0, 1.0); SRC_UpdateReachability(srcs[j], 1); samples = (i + j) % 5 + 3;