Add support for reference clocks

This commit is contained in:
Miroslav Lichvar 2009-05-05 09:14:13 +02:00
parent ef3669fe1b
commit ac30bb06ef
14 changed files with 453 additions and 16 deletions

View file

@ -41,7 +41,7 @@ OBJS = util.o sched.o regress.o local.o \
logging.o conf.o cmdmon.o md5.o keys.o \
nameserv.o acquire.o manual.o addrfilt.o \
cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
broadcast.o
broadcast.o refclock.o
EXTRA_OBJS=@EXTRA_OBJECTS@

View file

@ -92,6 +92,19 @@ time_to_log_form(time_t t)
/* ================================================== */
static char *
UTI_RefidToString(unsigned long ref_id)
{
unsigned int a, b, c, d;
static char result[64];
a = (ref_id>>24) & 0xff;
b = (ref_id>>16) & 0xff;
c = (ref_id>> 8) & 0xff;
d = (ref_id>> 0) & 0xff;
snprintf(result, sizeof(result), "%c%c%c%c", a, b, c, d);
return result;
}
static char *
UTI_IPToDottedQuad(unsigned long ip)
{
@ -1462,7 +1475,9 @@ process_cmd_sources(char *line)
resid_skew = (double) (ntohl(reply.data.source_data.resid_skew)) * 1.0e-3;
hostname_buf[25] = 0;
if (no_dns) {
if (mode == RPY_SD_MD_REF) {
snprintf(hostname_buf, sizeof(hostname_buf), "%s", UTI_RefidToString(ip_addr));
} else if (no_dns) {
snprintf(hostname_buf, sizeof(hostname_buf), "%s", UTI_IPToDottedQuad(ip_addr));
} else {
dns_lookup = DNS_IPAddress2Name(ip_addr);

View file

@ -50,6 +50,7 @@
#include "rtc.h"
#include "pktlength.h"
#include "clientlog.h"
#include "refclock.h"
/* ================================================== */
@ -871,7 +872,14 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
/* Get data */
LCL_ReadCookedTime(&now_corr, &local_clock_err);
if (SRC_ReportSource(ntohl(rx_message->data.source_data.index), &report, &now_corr)) {
NSR_ReportSource(&report, &now_corr);
switch (SRC_GetType(ntohl(rx_message->data.source_data.index))) {
case SRC_NTP:
NSR_ReportSource(&report, &now_corr);
break;
case SRC_REFCLOCK:
RCL_ReportSource(&report, &now_corr);
break;
}
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_SOURCE_DATA);

74
conf.c
View file

@ -44,6 +44,7 @@
#include "conf.h"
#include "ntp_sources.h"
#include "ntp_core.h"
#include "refclock.h"
#include "cmdmon.h"
#include "srcparams.h"
#include "logging.h"
@ -73,6 +74,7 @@ static void parse_peer(const char *);
static void parse_acquisitionport(const char *);
static void parse_port(const char *);
static void parse_server(const char *);
static void parse_refclock(const char *);
static void parse_local(const char *);
static void parse_manual(const char *);
static void parse_initstepslew(const char *);
@ -187,6 +189,7 @@ typedef struct {
static const Command commands[] = {
{"server", 6, parse_server},
{"peer", 4, parse_peer},
{"refclock", 8, parse_refclock},
{"acquisitionport", 15, parse_acquisitionport},
{"port", 4, parse_port},
{"driftfile", 9, parse_driftfile},
@ -250,6 +253,11 @@ typedef struct {
static NTP_Source ntp_sources[MAX_NTP_SOURCES];
static int n_ntp_sources = 0;
#define MAX_RCL_SOURCES 8
static RefclockParameters refclock_sources[MAX_RCL_SOURCES];
static int n_refclock_sources = 0;
/* ================================================== */
typedef struct _AllowDeny {
@ -417,6 +425,61 @@ parse_peer(const char *line)
/* ================================================== */
static void
parse_refclock(const char *line)
{
int i, n, param, poll;
unsigned long ref_id;
double offset;
char name[5], cmd[10 + 1];
unsigned char ref[5];
i = n_refclock_sources;
if (i >= MAX_RCL_SOURCES)
return;
poll = 4;
offset = 0.0;
ref_id = 0;
if (sscanf(line, "%4s %d%n", name, &param, &n) != 2) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read refclock driver name and parameter at line %d", line_number);
return;
}
line += n;
while (sscanf(line, "%10s%n", cmd, &n) == 1) {
line += n;
if (!strncasecmp(cmd, "refid", 5)) {
if (sscanf(line, "%4s%n", (char *)ref, &n) != 1)
break;
ref_id = ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
} else if (!strncasecmp(cmd, "poll", 4)) {
if (sscanf(line, "%d%n", &poll, &n) != 1) {
break;
}
} else if (!strncasecmp(cmd, "offset", 6)) {
if (sscanf(line, "%lf%n", &offset, &n) != 1)
break;
} else {
LOG(LOGS_WARN, LOGF_Configure, "Unknown refclock parameter %s at line %d", cmd, line_number);
break;
}
line += n;
}
strncpy(refclock_sources[i].driver_name, name, 4);
refclock_sources[i].driver_parameter = param;
refclock_sources[i].poll = poll;
refclock_sources[i].offset = offset;
refclock_sources[i].ref_id = ref_id;
n_refclock_sources++;
}
/* ================================================== */
static void
parse_some_port(const char *line, int *portvar)
{
@ -1004,6 +1067,17 @@ CNF_AddSources(void) {
/* ================================================== */
void
CNF_AddRefclocks(void) {
int i;
for (i=0; i<n_refclock_sources; i++) {
RCL_AddRefclock(&refclock_sources[i]);
}
}
/* ================================================== */
void
CNF_AddBroadcasts(void)
{

1
conf.h
View file

@ -37,6 +37,7 @@ extern void CNF_ReadFile(const char *filename);
extern void CNF_AddSources(void);
extern void CNF_AddBroadcasts(void);
extern void CNF_AddRefclocks(void);
extern void CNF_ProcessInitStepSlew(void (*after_hook)(void *), void *anything);

View file

@ -64,7 +64,8 @@ typedef enum {
LOGF_SysSolaris,
LOGF_SysSunOS,
LOGF_SysWinnt,
LOGF_RtcLinux
LOGF_RtcLinux,
LOGF_Refclock
} LOG_Facility;
/* Init function */

4
main.c
View file

@ -58,6 +58,7 @@
#include "manual.h"
#include "version.h"
#include "rtc.h"
#include "refclock.h"
#include "clientlog.h"
#include "broadcast.h"
@ -103,6 +104,7 @@ MAI_CleanupAndExit(void)
SRC_Finalise();
SST_Finalise();
REF_Finalise();
RCL_Finalise();
RTC_Finalise();
CAM_Finalise();
NIO_Finalise();
@ -145,6 +147,7 @@ post_acquire_hook(void *anything)
CNF_SetupAccessRestrictions();
RTC_StartMeasurements();
RCL_StartRefclocks();
}
/* ================================================== */
@ -309,6 +312,7 @@ int main
NIO_Initialise();
CAM_Initialise();
RTC_Initialise();
RCL_Initialise();
if (SchedPriority > 0) {
SYS_SetScheduler(SchedPriority);

View file

@ -319,7 +319,7 @@ create_instance(NTP_Remote_Address *remote_addr, NTP_Mode mode, SourceParameters
result->local_poll = params->minpoll;
/* Create a source instance for this NTP source */
result->source = SRC_CreateNewInstance(remote_addr->ip_addr); /* Will need extra params eventually */
result->source = SRC_CreateNewInstance(remote_addr->ip_addr, SRC_NTP);
result->local_rx.tv_sec = 0;
result->local_rx.tv_usec = 0;

213
refclock.c Normal file
View file

@ -0,0 +1,213 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
**********************************************************************
=======================================================================
Routines implementing reference clocks.
*/
#include "refclock.h"
#include "conf.h"
#include "local.h"
#include "util.h"
#include "sources.h"
#include "logging.h"
#include "sched.h"
struct RCL_Instance_Record {
RefclockDriver *driver;
void *data;
int driver_parameter;
int poll;
int missed_samples;
unsigned long ref_id;
double offset;
SCH_TimeoutID timeout_id;
SRC_Instance source;
};
#define MAX_RCL_SOURCES 8
static struct RCL_Instance_Record refclocks[MAX_RCL_SOURCES];
static int n_sources = 0;
static void poll_timeout(void *arg);
void
RCL_Initialise(void)
{
CNF_AddRefclocks();
}
void
RCL_Finalise(void)
{
int i;
for (i = 0; i < n_sources; i++) {
RCL_Instance inst = (RCL_Instance)&refclocks[i];
if (inst->driver->fini)
inst->driver->fini(inst);
}
}
int
RCL_AddRefclock(RefclockParameters *params)
{
RCL_Instance inst = &refclocks[n_sources];
if (n_sources == MAX_RCL_SOURCES)
return 0;
if (0) {
} else {
LOG_FATAL(LOGF_Refclock, "unknown refclock driver %s", params->driver_name);
return 0;
}
inst->data = NULL;
inst->driver_parameter = params->driver_parameter;
inst->poll = params->poll;
inst->missed_samples = 0;
inst->offset = params->offset;
inst->timeout_id = -1;
inst->source = NULL;
if (params->ref_id)
inst->ref_id = params->ref_id;
else {
unsigned char ref[5] = { 0, 0, 0, 0, 0 };
snprintf((char *)ref, 5, "%s%d", params->driver_name, params->driver_parameter);
inst->ref_id = ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
}
if (inst->driver->init)
if (!inst->driver->init(inst)) {
LOG_FATAL(LOGF_Refclock, "refclock %s initialisation failed", params->driver_name);
return 0;
}
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock added");
#endif
n_sources++;
return 1;
}
void
RCL_StartRefclocks(void)
{
int i;
for (i = 0; i < n_sources; i++) {
RCL_Instance inst = &refclocks[i];
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK);
if (inst->driver->poll)
inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst);
}
}
void
RCL_ReportSource(RPT_SourceReport *report, struct timeval *now)
{
int i;
unsigned long ref_id;
ref_id = report->ip_addr;
for (i = 0; i < n_sources; i++) {
RCL_Instance inst = &refclocks[i];
if (inst->ref_id == ref_id) {
report->poll = inst->poll;
report->mode = RPT_LOCAL_REFERENCE;
break;
}
}
}
void
RCL_SetDriverData(RCL_Instance instance, void *data)
{
instance->data = data;
}
void *
RCL_GetDriverData(RCL_Instance instance)
{
return instance->data;
}
int
RCL_GetDriverParameter(RCL_Instance instance)
{
return instance->driver_parameter;
}
int
RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status)
{
double correction;
struct timeval cooked_time;
SRC_Instance inst = instance->source;
#if 0
LOG(LOGS_INFO, LOGF_Refclock, "refclock offset: %f", offset);
#endif
SRC_SetReachable(inst);
correction = LCL_GetOffsetCorrection(sample_time);
UTI_AddDoubleToTimeval(sample_time, correction, &cooked_time);
SRC_AccumulateSample(inst, &cooked_time, offset - correction + instance->offset,
1e-6, 0.0, 0.0, 0.0, 0, leap_status);
instance->missed_samples = 0;
return 1;
}
static void
poll_timeout(void *arg)
{
double next;
RCL_Instance inst = (RCL_Instance)arg;
inst->missed_samples++;
inst->driver->poll(inst);
if (inst->missed_samples > 9)
SRC_UnsetReachable(inst->source);
if (inst->poll >= 0)
next = 1 << inst->poll;
else
next = 1.0 / (1 << -inst->poll);
inst->timeout_id = SCH_AddTimeoutByDelay(next, poll_timeout, arg);
}

63
refclock.h Normal file
View file

@ -0,0 +1,63 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
**********************************************************************
=======================================================================
Header file for refclocks.
*/
#ifndef GOT_REFCLOCK_H
#define GOT_REFCLOCK_H
#include "srcparams.h"
#include "sources.h"
typedef struct {
char driver_name[4];
int driver_parameter;
int poll;
unsigned long ref_id;
double offset;
} RefclockParameters;
typedef struct RCL_Instance_Record *RCL_Instance;
typedef struct {
int (*init)(RCL_Instance instance);
void (*fini)(RCL_Instance instance);
int (*poll)(RCL_Instance instance);
} RefclockDriver;
extern void RCL_Initialise(void);
extern void RCL_Finalise(void);
extern int RCL_AddRefclock(RefclockParameters *params);
extern void RCL_StartRefclocks(void);
extern void RCL_StartRefclocks(void);
extern void RCL_ReportSource(RPT_SourceReport *report, struct timeval *now);
/* functions used by drivers */
extern void RCL_SetDriverData(RCL_Instance instance, void *data);
extern void *RCL_GetDriverData(RCL_Instance instance);
extern int RCL_GetDriverParameter(RCL_Instance instance);
extern int RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status);
#endif

View file

@ -96,6 +96,9 @@ struct SRC_Instance_Record {
/* Flag indicating the status of the source */
SRC_Status status;
/* Type of the source */
SRC_Type type;
struct SelectInfo sel_info;
};
@ -126,6 +129,8 @@ static int selected_source_index; /* Which source index is currently
static void
slew_sources(struct timeval *raw, struct timeval *cooked, double dfreq, double afreq,
double doffset, int is_step_change, void *anything);
static char *
source_to_string(SRC_Instance inst);
/* ================================================== */
/* Initialisation function */
@ -155,7 +160,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_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type)
{
SRC_Instance result;
@ -186,6 +191,7 @@ SRC_Instance SRC_CreateNewInstance(unsigned long ref_id)
result->ref_id = ref_id;
result->reachable = 0;
result->status = SRC_BAD_STATS;
result->type = type;
n_sources++;
@ -280,7 +286,7 @@ void SRC_AccumulateSample
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_Sources, "ip=[%s] t=%s ofs=%f del=%f disp=%f str=%d",
UTI_IPToDottedQuad(inst->ref_id), UTI_TimevalToString(sample_time), -offset, root_delay, root_dispersion, stratum);
source_to_string(inst), UTI_TimevalToString(sample_time), -offset, root_delay, root_dispersion, stratum);
#endif
/* WE HAVE TO NEGATE OFFSET IN THIS CALL, IT IS HERE THAT THE SENSE OF OFFSET
@ -301,7 +307,7 @@ SRC_SetReachable(SRC_Instance inst)
inst->reachable = 1;
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_Sources, "%s", UTI_IPToDottedQuad(inst->ref_id));
LOG(LOGS_INFO, LOGF_Sources, "%s", source_to_string(inst));
#endif
/* Don't do selection at this point, though - that will come about
@ -316,7 +322,7 @@ SRC_UnsetReachable(SRC_Instance inst)
inst->reachable = 0;
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_Sources, "%s%s", UTI_IPToDottedQuad(inst->ref_id),
LOG(LOGS_INFO, LOGF_Sources, "%s%s", source_to_string(inst),
(inst->index == selected_source_index) ? "(REF)":"");
#endif
@ -349,6 +355,22 @@ compare_sort_elements(const void *a, const void *b)
}
}
/* ================================================== */
static char *
source_to_string(SRC_Instance inst)
{
switch (inst->type) {
case SRC_NTP:
return UTI_IPToDottedQuad(inst->ref_id);
case SRC_REFCLOCK:
return UTI_RefidToString(inst->ref_id);
default:
CROAK("Unknown source type");
}
return NULL;
}
/* ================================================== */
/* This function selects the current reference from amongst the pool
of sources we are holding.
@ -418,7 +440,7 @@ SRC_SelectSource(unsigned long match_addr)
#if 0
LOG(LOGS_INFO, LOGF_Sources, "%s off=%f dist=%f lo=%f hi=%f",
UTI_IPToDottedQuad(sources[i]->ref_id),
source_to_string(sources[i]),
si->best_offset, si->root_distance,
si->lo_limit, si->hi_limit);
#endif
@ -491,7 +513,7 @@ SRC_SelectSource(unsigned long match_addr)
for (i=0; i<n_endpoints; i++) {
#if 0
LOG(LOGS_INFO, LOGF_Sources, "i=%d t=%f tag=%d addr=%s", i, sort_list[i].offset, sort_list[i].tag,
UTI_IPToDottedQuad(sources[sort_list[i].index]->ref_id));
source_to_string(sources[sort_list[i].index]));
#endif
switch(sort_list[i].tag) {
case LOW:
@ -565,12 +587,12 @@ SRC_SelectSource(unsigned long match_addr)
sel_sources[n_sel_sources++] = i;
#if 0
LOG(LOGS_INFO, LOGF_Sources, "i=%d addr=%s is valid", i, UTI_IPToDottedQuad(sources[i]->ref_id));
LOG(LOGS_INFO, LOGF_Sources, "i=%d addr=%s is valid", i, source_to_string(sources[i]));
#endif
} else {
sources[i]->status = SRC_FALSETICKER;
#if 0
LOG(LOGS_INFO, LOGF_Sources, "i=%d addr=%s is a falseticker", i, UTI_IPToDottedQuad(sources[i]->ref_id));
LOG(LOGS_INFO, LOGF_Sources, "i=%d addr=%s is a falseticker", i, source_to_string(sources[i]));
#endif
}
}
@ -603,7 +625,7 @@ SRC_SelectSource(unsigned long match_addr)
sel_sources[i] = INVALID_SOURCE;
sources[index]->status = SRC_JITTERY;
#if 0
LOG(LOGS_INFO, LOGF_Sources, "i=%d addr=%s has too much variance", i, UTI_IPToDottedQuad(sources[i]->ref_id));
LOG(LOGS_INFO, LOGF_Sources, "i=%d addr=%s has too much variance", i, source_to_string(sources[i]));
#endif
}
}
@ -658,7 +680,7 @@ SRC_SelectSource(unsigned long match_addr)
selected_source_index = min_distance_index;
LOG(LOGS_INFO, LOGF_Sources, "Selected source %s",
UTI_IPToDottedQuad(sources[selected_source_index]->ref_id));
source_to_string(sources[selected_source_index]));
#if 0
@ -935,6 +957,16 @@ SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report)
/* ================================================== */
SRC_Type
SRC_GetType(int index)
{
if ((index >= n_sources) || (index < 0))
return -1;
return sources[index]->type;
}
/* ================================================== */
SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst)
{
SRC_Skew_Direction result = SRC_Skew_Nochange;

View file

@ -50,10 +50,15 @@ extern void SRC_Initialise(void);
/* Finalisation function */
extern void SRC_Finalise(void);
typedef enum {
SRC_NTP, /* NTP client/peer */
SRC_REFCLOCK /* Rerefence clock */
} SRC_Type;
/* 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);
extern SRC_Instance SRC_CreateNewInstance(unsigned long ref_id, SRC_Type type);
/* Function to get rid of a source when it is being unconfigured.
This may cause the current reference source to be reselected, if this
@ -143,6 +148,8 @@ extern int SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval
extern int SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report);
extern SRC_Type SRC_GetType(int index);
typedef enum {
SRC_Skew_Decrease,
SRC_Skew_Nochange,

16
util.c
View file

@ -247,6 +247,22 @@ UTI_TimestampToString(NTP_int64 *ts)
/* ================================================== */
char *
UTI_RefidToString(unsigned long ref_id)
{
unsigned int a, b, c, d;
char *result;
a = (ref_id>>24) & 0xff;
b = (ref_id>>16) & 0xff;
c = (ref_id>> 8) & 0xff;
d = (ref_id>> 0) & 0xff;
result = NEXT_BUFFER;
snprintf(result, BUFFER_LENGTH, "%c%c%c%c", a, b, c, d);
return result;
}
/* ================================================== */
char *
UTI_IPToDottedQuad(unsigned long ip)
{

3
util.h
View file

@ -72,6 +72,9 @@ extern char *UTI_TimevalToString(struct timeval *tv);
diagnostic display */
extern char *UTI_TimestampToString(NTP_int64 *ts);
/* Convert ref_id into a temporary string, for diagnostics */
extern char *UTI_RefidToString(unsigned long ref_id);
/* Convert an IP address to dotted quad notation, for diagnostics */
extern char *UTI_IPToDottedQuad(unsigned long ip);