aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/xntpd/xntpd/ntp_loopfilter.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/xntpd/xntpd/ntp_loopfilter.c')
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_loopfilter.c258
1 files changed, 136 insertions, 122 deletions
diff --git a/usr.sbin/xntpd/xntpd/ntp_loopfilter.c b/usr.sbin/xntpd/xntpd/ntp_loopfilter.c
index e0411faca20c..61332b9b6384 100644
--- a/usr.sbin/xntpd/xntpd/ntp_loopfilter.c
+++ b/usr.sbin/xntpd/xntpd/ntp_loopfilter.c
@@ -92,17 +92,14 @@
#define RSH_DRIFT_TO_FRAC (CLOCK_DSCALE - 16)
#define RSH_DRIFT_TO_ADJ (RSH_DRIFT_TO_FRAC - CLOCK_ADJ)
#define RSH_FRAC_TO_FREQ (CLOCK_FREQ + CLOCK_ADJ - RSH_DRIFT_TO_FRAC)
+#define PPS_MAXAGE 120 /* pps signal timeout (s) */
+#define PPS_MAXUPDATE 600 /* pps update timeout (s) */
/*
- * Imported from the ntp_proto module
+ * Program variables
*/
-extern u_char sys_stratum;
-extern s_fp sys_rootdelay;
-extern u_fp sys_rootdispersion;
-extern s_char sys_precision;
-
l_fp last_offset; /* last adjustment done */
-static LONG clock_adjust; /* clock adjust register (fraction only) */
+static LONG clock_adjust; /* clock adjust (fraction only) */
s_fp drift_comp; /* drift compensation register */
static s_fp max_comp; /* drift limit imposed by max host clock slew */
@@ -111,11 +108,15 @@ static s_fp max_comp; /* drift limit imposed by max host clock slew */
static U_LONG tcadj_time; /* last time-constant adjust time */
U_LONG watchdog_timer; /* watchdog timer, in seconds */
-static int first_adjustment; /* set to 1 if waiting for first adjustment */
+static int first_adjustment; /* 1 if waiting for first adjustment */
static int tc_counter; /* time-constant hold counter */
- int pll_control; /* set nonzero if pll implemented in kernel */
- int pps_control; /* set nonzero if pps signal valid */
+static l_fp pps_offset; /* filtered pps offset */
+static u_fp pps_dispersion; /* pps dispersion */
+static U_LONG pps_time; /* last pps sample time */
+
+ int pps_control; /* true if working pps signal */
+ int pll_control; /* true if working kernel pll */
static l_fp pps_delay; /* pps tuning offset */
U_LONG pps_update; /* last pps update time */
int fdpps = -1; /* pps file descriptor */
@@ -151,8 +152,7 @@ static l_fp pps_delay; /* pps tuning offset */
( i == 300 ? B300 : 0 ))))))))
#define PPS_BAUD B38400 /* default serial port speed */
-#define PPS_MAXAGE 120 /* seconds after which we disbelieve pps */
-#define PPS_MAXUPDATE 600 /* seconds after which we disbelieve timecode */
+timecode */
#define PPS_DEV "/dev/pps" /* pps port */
#define PPS_FAC 3 /* pps shift (log2 trimmed samples) */
#define PPS_TRIM 6 /* samples trimmed from median filter */
@@ -163,18 +163,24 @@ static l_fp pps_delay; /* pps tuning offset */
static struct refclockio io; /* given to the I/O handler */
static int pps_baud; /* baud rate of PPS line */
#endif /* PPSCLK */
-static l_fp pps_offset; /* filtered pps offset */
-static u_fp pps_maxd; /* pps dispersion */
-static U_LONG pps_time; /* last pps sample time */
static U_LONG nsamples; /* number of pps samples collected */
static LONG samples[NPPS]; /* median filter for pps samples */
+
+#endif /* PPS || PPSCLK || PPSPPS */
+
+/*
+ * Imported from the ntp_proto module
+ */
+extern u_char sys_stratum;
+extern s_fp sys_rootdelay;
+extern u_fp sys_rootdispersion;
+extern s_char sys_precision;
+
/*
* Imported from ntp_io.c
*/
extern struct interface *loopback_interface;
-#endif /* PPS || PPSCLK || PPSPPS */
-
/*
* Imported from ntpd module
*/
@@ -189,10 +195,16 @@ extern U_LONG current_time; /* like it says, in seconds */
* sys_poll and sys_refskew are set here
*/
extern u_char sys_poll; /* log2 of system poll interval */
+extern u_char sys_leap; /* system leap bits */
extern l_fp sys_refskew; /* accumulated skew since last update */
extern u_fp sys_maxd; /* max dispersion of survivor list */
/*
+ * Imported from leap module
+ */
+extern u_char leapbits; /* sanitized leap bits */
+
+/*
* Function prototypes
*/
#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
@@ -203,10 +215,13 @@ static void pps_receive P((struct recvbuf *));
#endif /* PPS || PPSCLK || PPSPPS */
#if defined(KERNEL_PLL)
+#define MOD_BITS (MOD_OFFSET | MOD_MAXERROR | MOD_ESTERROR | \
+ MOD_STATUS | MOD_TIMECONST)
extern int sigvec P((int, struct sigvec *, struct sigvec *));
extern int syscall P((int, void *, ...));
void pll_trap P((void));
+static int pll_status; /* status bits for kernel pll */
static struct sigvec sigsys; /* current sigvec status */
static struct sigvec newsigsys; /* new sigvec status */
#endif /* KERNEL_PLL */
@@ -398,7 +413,7 @@ local_clock(fp_offset, peer)
#ifdef DEBUG
if (debug > 1)
- printf("local_clock(%s, %s)\n", lfptoa(fp_offset, 9),
+ printf("local_clock(%s, %s)\n", lfptoa(fp_offset, 6),
ntoa(&peer->srcadr));
#endif
@@ -431,33 +446,26 @@ local_clock(fp_offset, peer)
last_offset = *fp_offset;
/*
- * If the magnitude of the offset is greater than CLOCK.MAX, step
- * the time and reset the registers.
+ * If the magnitude of the offset is greater than CLOCK.MAX,
+ * step the time and reset the registers.
*/
if (tmp_ui > CLOCK_MAX_I || (tmp_ui == CLOCK_MAX_I
&& (U_LONG)tmp_uf >= (U_LONG)CLOCK_MAX_F)) {
if (watchdog_timer < CLOCK_MINSTEP) {
/* Mustn't step yet, pretend we adjusted. */
-#ifdef SLEWALWAYS
- syslog(LOG_INFO,
- "adjust: SLEW dropped (%s offset %s)\n",
- ntoa(&peer->srcadr), lfptoa(fp_offset, 9));
-#else
syslog(LOG_INFO,
- "adjust: STEP dropped (%s offset %s)\n",
- ntoa(&peer->srcadr), lfptoa(fp_offset, 9));
-#endif
+ "clock correction %s too large (ignored)\n",
+ lfptoa(fp_offset, 6));
return (0);
}
+ syslog(LOG_NOTICE, "clock reset (%s) %s\n",
#ifdef SLEWALWAYS
- syslog(LOG_NOTICE, " ** adjust: SLEW %s offset %s **\n",
- ntoa(&peer->srcadr), lfptoa(fp_offset, 9));
+ "slew",
#else
- syslog(LOG_NOTICE, " ** adjust: STEP %s offset %s **\n",
- ntoa(&peer->srcadr), lfptoa(fp_offset, 9));
+ "step",
#endif
+ lfptoa(fp_offset, 6));
step_systime(fp_offset);
-
clock_adjust = 0;
watchdog_timer = 0;
first_adjustment = 1;
@@ -479,21 +487,24 @@ local_clock(fp_offset, peer)
* The time constant update goes after adjust and skew updates,
* as in appendix G.
*/
-#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
/*
* If pps samples are valid, update offset, root delay and
- * root dispersion. This may be a dramatic surprise to high-
- * stratum clients, since all of a sudden this server looks
- * like a stratum-1 clock.
+ * root dispersion. Also, set the system stratum to 1, even if
+ * the source of approximate time runs at a higher stratum. This
+ * may be a dramatic surprise to high-stratum clients, since all
+ * of a sudden this server looks like a stratum-1 clock.
*/
if (pps_control) {
last_offset = pps_offset;
- sys_maxd = pps_maxd;
+ sys_maxd = pps_dispersion;
sys_stratum = 1;
sys_rootdelay = 0;
- sys_rootdispersion = pps_maxd;
+ offset = LFPTOFP(&pps_offset);
+ if (offset < 0)
+ offset = -offset;
+ sys_rootdispersion = offset + pps_dispersion;
}
-#endif /* PPS || PPSCLK || PPSPPS */
+ offset = last_offset.l_f;
/*
* The pll_control is active when the phase-lock code is
@@ -504,42 +515,56 @@ local_clock(fp_offset, peer)
* know the scaling of the frequency variable (s_fp) is the
* same as the kernel variable (1 << SHIFT_USEC = 16).
*
+ * For kernels with the PPS discipline, the current offset and
+ * dispersion are set from kernel variables to maintain
+ * beauteous displays, but don't do much of anything.
+ *
* In the case of stock kernels the phase-lock loop is
* implemented the hard way and the clock_adjust and drift_comp
* computed as required.
*/
- offset = last_offset.l_f;
if (pll_control) {
#if defined(KERNEL_PLL)
- ntv.mode = ADJ_OFFSET | ADJ_TIMECONST | ADJ_MAXERROR |
- ADJ_ESTERROR;
+ memset((char *)&ntv, 0, sizeof ntv);
+ ntv.modes = MOD_BITS;
if (offset >= 0) {
TSFTOTVU(offset, ntv.offset);
} else {
TSFTOTVU(-offset, ntv.offset);
ntv.offset = -ntv.offset;
}
- ntv.maxerror = sys_rootdispersion + sys_rootdelay / 2;
- ntv.esterror = sys_rootdispersion;
- ntv.time_constant = time_constant;
- ntv.shift = 0;
+ TSFTOTVU(sys_rootdispersion + sys_rootdelay / 2, ntv.maxerror);
+ TSFTOTVU(sys_rootdispersion, ntv.esterror);
+ ntv.status = pll_status;
+ if (pps_update)
+ ntv.status |= STA_PPSTIME;
+ if (sys_leap & LEAP_ADDSECOND &&
+ sys_leap & LEAP_DELSECOND)
+ ntv.status |= STA_UNSYNC;
+ else if (sys_leap & LEAP_ADDSECOND)
+ ntv.status |= STA_INS;
+ else if (sys_leap & LEAP_DELSECOND)
+ ntv.status |= STA_DEL;
+ ntv.constant = time_constant;
(void)ntp_adjtime(&ntv);
- drift_comp = ntv.frequency;
- if (ntv.shift != 0) {
- char buf[128];
- (void) sprintf(buf, "pps_freq=%s", fptoa(ntv.ybar, 3));
- set_sys_var(buf, strlen(buf)+1, RO|DEF);
- (void) sprintf(buf, "pps_disp=%s", fptoa(ntv.disp, 3));
- set_sys_var(buf, strlen(buf)+1, RO|DEF);
- (void) sprintf(buf, "pps_interval=%ld",1 << ntv.shift);
- set_sys_var(buf, strlen(buf)+1, RO);
- (void) sprintf(buf, "pps_intervals=%ld", ntv.calcnt);
- set_sys_var(buf, strlen(buf)+1, RO);
- (void) sprintf(buf, "pps_jitterexceeded=%ld", ntv.jitcnt);
- set_sys_var(buf, strlen(buf)+1, RO);
- (void) sprintf(buf, "pps_dispersionexceeded=%ld", ntv.discnt);
- set_sys_var(buf, strlen(buf)+1, RO);
- }
+ drift_comp = ntv.freq;
+ if (ntv.status & STA_PPSTIME && ntv.status & STA_PPSSIGNAL
+ && ntv.shift) {
+ if (ntv.offset >= 0) {
+ TVUTOTSF(ntv.offset, offset);
+ } else {
+ TVUTOTSF(-ntv.offset, offset);
+ offset = -offset;
+ }
+ pps_offset.l_i = pps_offset.l_f = 0;
+ M_ADDF(pps_offset.l_i, pps_offset.l_f, offset);
+ TVUTOTSF(ntv.jitter, tmp);
+ pps_dispersion = (tmp >> 16) & 0xffff;
+ pps_time = current_time;
+ record_peer_stats(&loopback_interface->sin,
+ ctlsysstatus(), &pps_offset, 0, pps_dispersion);
+ } else
+ pps_time = 0;
#endif /* KERNEL_PLL */
} else {
if (offset < 0) {
@@ -549,21 +574,14 @@ local_clock(fp_offset, peer)
}
/*
- * Calculate the new frequency error. The factor given in the
- * spec gives the adjustment per 2**CLOCK_ADJ seconds, but we
- * want it as a (scaled) pure ratio, so we include that factor
- * now and remove it later.
+ * Calculate the new frequency error. The factor given
+ * in the spec gives the adjustment per 2**CLOCK_ADJ
+ * seconds, but we want it as a (scaled) pure ratio, so
+ * we include that factor now and remove it later.
*/
if (first_adjustment) {
first_adjustment = 0;
} else {
- /*
- * Clamp the integration interval to maxpoll.
- * The bitcounting in Section 5 gives (n+1)-6 for 2**n,
- * but has a factor 2**6 missing from CLOCK_FREQ.
- * We make 2**n give n instead. If watchdog_timer is
- * zero, pretend it's one.
- */
tmp = peer->maxpoll;
tmp_uf = watchdog_timer;
if (tmp_uf == 0)
@@ -574,10 +592,11 @@ local_clock(fp_offset, peer)
}
/*
- * We apply the frequency scaling at the same time as
- * the sample interval; this ensures a safe right-shift.
- * (as long as it keeps below 31 bits, which current
- * parameters should ensure.
+ * We apply the frequency scaling at the same
+ * time as the sample interval; this ensures a
+ * safe right-shift. (as long as it keeps below
+ * 31 bits, which current parameters should
+ * ensure.
*/
tmp = (RSH_FRAC_TO_FREQ - tmp) +
time_constant + time_constant;
@@ -597,7 +616,9 @@ local_clock(fp_offset, peer)
/*
* Determine when to adjust the time constant and poll interval.
*/
- if (current_time - tcadj_time >= (1 << sys_poll)) {
+ if (pps_control)
+ time_constant = 0;
+ else if (current_time - tcadj_time >= (1 << sys_poll) && !pps_control) {
tcadj_time = current_time;
tmp = offset;
if (tmp < 0)
@@ -623,8 +644,8 @@ local_clock(fp_offset, peer)
#ifdef DEBUG
if (debug > 1)
printf("adj %s, drft %s, tau %3i\n",
- mfptoa((clock_adjust<0?-1:0), clock_adjust, 9),
- fptoa(drift_comp, 9), time_constant);
+ mfptoa((clock_adjust<0?-1:0), clock_adjust, 6),
+ fptoa(drift_comp, 6), time_constant);
#endif /* DEBUG */
(void) record_loop_stats(&last_offset, &drift_comp, time_constant);
@@ -678,20 +699,20 @@ adj_host_clock()
}
}
#endif /* PPSPPS */
- if (pps_time != 0 && current_time - pps_time > PPS_MAXAGE)
- pps_time = 0;
- if (pps_update != 0 && current_time - pps_update > PPS_MAXUPDATE)
- pps_update = 0;
- if (pps_time != 0 && pps_update != 0) {
+#endif /* PPS || PPSCLK || PPSPPS */
+ if (pps_time && current_time - pps_time > PPS_MAXAGE)
+ pps_time = 0;
+ if (pps_update && current_time - pps_update > PPS_MAXUPDATE)
+ pps_update = 0;
+ if (pps_time && pps_update) {
if (!pps_control)
- syslog(LOG_INFO, "pps synch");
+ syslog(LOG_INFO, "PPS synch");
pps_control = 1;
} else {
if (pps_control)
- syslog(LOG_INFO, "pps synch lost");
+ syslog(LOG_INFO, "PPS synch lost");
pps_control = 0;
}
-#endif /* PPS || PPSCLK || PPSPPS */
/*
* Resist the following code if the phase-lock loop has been
@@ -738,24 +759,27 @@ loop_config(item, lfp_value, int_value)
tmp = LFPTOFP(lfp_value);
if (tmp >= max_comp || tmp <= -max_comp) {
syslog(LOG_ERR,
- "loop_config: skew compensation %s too large",
+ "loop_config: frequency offset %s in ntp.conf file is too large",
fptoa(tmp, 5));
} else {
- char var[40];
-
drift_comp = tmp;
#if defined(KERNEL_PLL)
/*
- * If the phase-lock code is implemented in the kernel,
- * give the time_constant and saved frequency offset
- * to the kernel. If not, no harm is done.
+ * If the phase-lock code is implemented in the
+ * kernel, give the time_constant and saved
+ * frequency offset to the kernel. If not, no
+ * harm is done.
*/
pll_control = 1;
- ntv.mode = ADJ_FREQUENCY | ADJ_STATUS | ADJ_TIMECONST;
- ntv.status = TIME_BAD;
- ntv.time_constant = time_constant;
- ntv.frequency = drift_comp;
+ pll_status = STA_PLL | STA_PPSFREQ;
+ ntv.modes = MOD_BITS | MOD_FREQUENCY;
+ ntv.offset = 0;
+ ntv.freq = drift_comp;
+ ntv.maxerror = NTP_MAXDISPERSE;
+ ntv.esterror = NTP_MAXDISPERSE;
+ ntv.status = pll_status | STA_UNSYNC;
+ ntv.constant = time_constant;
newsigsys.sv_handler = pll_trap;
newsigsys.sv_mask = 0;
newsigsys.sv_flags = 0;
@@ -766,17 +790,13 @@ loop_config(item, lfp_value, int_value)
if ((sigvec(SIGSYS, &sigsys, (struct sigvec *)NULL)))
syslog(LOG_ERR,
"sigvec() fails to restore SIGSYS trap: %m\n");
- syslog(LOG_NOTICE,
- "%susing kernel phase-lock loop",
- (pll_control) ? "" : "Not ");
- (void)sprintf(var, "kernel_pll=%s", pll_control ? "true" : "false");
-
- set_sys_var(var, strlen(var)+1, RO);
-
-#if DEBUG
- if (debug)
- printf("pll_control %d\n", pll_control);
-#endif
+ if (pll_control)
+ syslog(LOG_NOTICE,
+ "using kernel phase-lock loop %04x",
+ ntv.status);
+ else
+ syslog(LOG_NOTICE,
+ "using xntpd phase-lock loop");
#endif /* KERNEL_PLL */
}
@@ -834,7 +854,7 @@ loop_config(item, lfp_value, int_value)
* _trap - trap processor for undefined syscalls
*
* This nugget is called by the kernel when the SYS_ntp_adjtime()
- * syscall bombs because the silly thing has not been implemented int
+ * syscall bombs because the silly thing has not been implemented in
* the kernel. In this case the phase-lock loop is emulated by
* the stock adjtime() syscall and a lot of indelicate abuse.
*/
@@ -900,8 +920,9 @@ int pps_sample(tsr)
/*
* Note the seconds offset is already in the low-order timestamp
- * doubleword, so all we have to do is sign-extend and invert it.
- * The resulting offset is believed only if within CLOCK_MAX.
+ * doubleword, so all we have to do is sign-extend and invert
+ * it. The resulting offset is believed only if within
+ * CLOCK_MAX.
*/
ts = *tsr;
lftemp.l_i = lftemp.l_f = 0;
@@ -957,21 +978,14 @@ int pps_sample(tsr)
}
lftemp.l_i = 0;
lftemp.l_f = sort[NPPS-1-PPS_TRIM] - sort[PPS_TRIM];
- pps_maxd = LFPTOFP(&lftemp);
- lftemp.l_i = 0;
- lftemp.l_f = sort[NPPS-1] - sort[0];
- utemp = LFPTOFP(&lftemp);
+ pps_dispersion = LFPTOFP(&lftemp);
#ifdef DEBUG
if (debug)
printf("pps_filter: %s %s %s\n", lfptoa(&pps_delay, 6),
lfptoa(&pps_offset, 6), lfptoa(&lftemp, 5));
#endif /* DEBUG */
- /*
- * Note the peerstats file will contain the gross dispersion in
- * the delay field. Temporaty hack.
- */
record_peer_stats(&loopback_interface->sin, ctlsysstatus(),
- &pps_offset, utemp, pps_maxd);
+ &pps_offset, 0, pps_dispersion);
return (0);
}
#endif /* PPS || PPSCLK || PPSPPS */