re using floating point for ntpd math is not a good idea. this comes from the fact that mixing small and large numbers in one fp expression leads to a huge loss of precision. besides the fact that there is no need to change representation from fixed point (ntp timestamps) to floating point and back all the time. plus to that using fpu in daemons is not polite and eats even more cpu time (:
this diff converts internal math to fixed point (64bit) except for one place -- local clock frequency drift. this part is still broken as one can see by constantly flipping frequency adjucements in the logs since math currently used performs computation on very large numbers (products of time stamps) and very small ones (products of time offsets) and thus totally useless. i have figured a better way to follow frequency drift but that can be done in the next step. this has ran on both i386 and sparc64 for months now and only has shown massive improvement in precision (decrease of deviation). thus local clock offset still flips every few hours from positive to negative and back due to broken frequency adjucements. please read and try. cu -- paranoic mickey (my employers have changed but, the name has remained) Index: Makefile =================================================================== RCS file: /cvs/src/usr.sbin/ntpd/Makefile,v retrieving revision 1.2 diff -u -p -r1.2 Makefile --- Makefile 13 May 2009 18:10:04 -0000 1.2 +++ Makefile 15 May 2009 14:26:35 -0000 @@ -3,7 +3,7 @@ PROG= ntpd SRCS= ntpd.c buffer.c log.c imsg.c ntp.c ntp_msg.c ntp_dns.c \ - parse.y config.c server.c client.c sensors.c util.c + parse.y config.c server.c client.c sensors.c CFLAGS+= -Wall -I${.CURDIR} CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wmissing-declarations Index: client.c =================================================================== RCS file: /cvs/src/usr.sbin/ntpd/client.c,v retrieving revision 1.4 diff -u -p -r1.4 client.c --- client.c 15 May 2009 11:40:42 -0000 1.4 +++ client.c 15 May 2009 14:26:35 -0000 @@ -195,19 +195,21 @@ client_query(struct ntp_peer *p) int client_dispatch(struct ntp_peer *p, u_int8_t settime) { - struct ntp_msg msg; - struct msghdr somsg; - struct iovec iov[1]; - struct timeval tv1; - char buf[NTP_MSGSIZE]; + extern int debug; /* from log.c */ + struct ntp_msg msg; + struct msghdr somsg; + struct iovec iov[1]; + struct timeval tv1, tv2; + char buf[NTP_MSGSIZE]; union { struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof tv1)]; } cmsgbuf; - struct cmsghdr *cmsg; - ssize_t size; - double T1, T2, T3, T4; - time_t interval; + int64_t T1, T2, T3, T4; + struct cmsghdr *cmsg; + struct ntp_offset *reply; + ssize_t size; + time_t interval; somsg.msg_name = NULL; somsg.msg_namelen = 0; @@ -219,7 +221,7 @@ client_dispatch(struct ntp_peer *p, u_in somsg.msg_controllen = sizeof cmsgbuf.buf; somsg.msg_flags = 0; - T4 = getoffset(); + getoffset(&tv2); if ((size = recvmsg(p->query->fd, &somsg, 0)) < 0) { if (errno == EHOSTUNREACH || errno == EHOSTDOWN || errno == ENETUNREACH || errno == ENETDOWN || @@ -243,17 +245,20 @@ client_dispatch(struct ntp_peer *p, u_in return (0); } + T4 = 0; for (cmsg = CMSG_FIRSTHDR(&somsg); cmsg != NULL; cmsg = CMSG_NXTHDR(&somsg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP) { memcpy(&tv1, CMSG_DATA(cmsg), sizeof tv1); - T4 += tv1.tv_sec + JAN_1970 + 1.0e-6 * tv1.tv_usec; + T4 = timeval2int64(&tv1); + T4 += (int64_t)JAN_1970 << 31; + T4 += timeval2int64(&tv2); break; } } - if (T4 < JAN_1970) { + if (T4 == 0) { client_log_error(p, "recvmsg control format", EBADF); set_next(p, error_interval()); return (0); @@ -301,8 +306,8 @@ client_dispatch(struct ntp_peer *p, u_in */ T1 = p->query->xmttime; - T2 = lfp_to_d(msg.rectime); - T3 = lfp_to_d(msg.xmttime); + T2 = lfxt2int64(&msg.rectime); + T3 = lfxt2int64(&msg.xmttime); /* * XXX workaround: time_t / tv_sec must never wrap. @@ -314,32 +319,51 @@ client_dispatch(struct ntp_peer *p, u_in return (0); } - p->reply[p->shift].offset = ((T2 - T1) + (T3 - T4)) / 2; - p->reply[p->shift].delay = (T4 - T1) - (T3 - T2); - if (p->reply[p->shift].delay < 0) { + if (T4 <= T1) { interval = error_interval(); set_next(p, interval); - log_info("reply from %s: negative delay %fs, " + log_info("local clock is not monotonic"); + return (0); + } + + reply = &p->reply[p->shift]; + + reply->offset = ((T2 - T1) + (T3 - T4)) / 2; + reply->delay = (T4 - T1) - (T3 - T2); + if (reply->delay < 0) { + char *s = ""; + int64_t val = reply->delay; + if (val < 0) { + s = "-"; + val = -val; + } + int642timeval(val, &tv2); + interval = error_interval(); + set_next(p, interval); + log_info("reply from %s: negative delay %s%ld.%06lus " "next query %ds", log_sockaddr((struct sockaddr *)&p->addr->ss), - p->reply[p->shift].delay, interval); + s, tv2.tv_sec, tv2.tv_usec, interval); return (0); } - p->reply[p->shift].error = (T2 - T1) - (T3 - T4); - p->reply[p->shift].rcvd = getmonotime(); - p->reply[p->shift].good = 1; - - p->reply[p->shift].status.leap = (msg.status & LIMASK); - p->reply[p->shift].status.precision = msg.precision; - p->reply[p->shift].status.rootdelay = sfp_to_d(msg.rootdelay); - p->reply[p->shift].status.rootdispersion = sfp_to_d(msg.dispersion); - p->reply[p->shift].status.refid = msg.refid; - p->reply[p->shift].status.reftime = lfp_to_d(msg.reftime); - p->reply[p->shift].status.poll = msg.ppoll; - p->reply[p->shift].status.stratum = msg.stratum; + + p->shift = (p->shift + 1) % OFFSET_ARRAY_SIZE; + + reply->error = (T2 - T1) - (T3 - T4); + reply->rcvd = getmonotime(); + reply->good = 1; + + reply->status.leap = msg.status & LIMASK; + reply->status.precision = msg.precision; + reply->status.refid = ntohl(msg.refid); + reply->status.poll = msg.ppoll; + reply->status.stratum = msg.stratum; + reply->status.rootdelay = sfxt2int64(&msg.rootdelay); + reply->status.rootdispersion = sfxt2int64(&msg.dispersion); + reply->status.reftime = lfxt2int64(&msg.reftime); if (p->addr->ss.ss_family == AF_INET) { - p->reply[p->shift].status.send_refid = + reply->status.send_refid = ((struct sockaddr_in *)&p->addr->ss)->sin_addr.s_addr; } else if (p->addr->ss.ss_family == AF_INET6) { MD5_CTX context; @@ -349,10 +373,10 @@ client_dispatch(struct ntp_peer *p, u_in MD5Update(&context, ((struct sockaddr_in6 *)&p->addr->ss)-> sin6_addr.s6_addr, sizeof(struct in6_addr)); MD5Final(digest, &context); - memcpy((char *)&p->reply[p->shift].status.send_refid, digest, + memcpy((char *)&reply->status.send_refid, digest, sizeof(u_int32_t)); } else - p->reply[p->shift].status.send_refid = msg.xmttime.fractionl; + reply->status.send_refid = msg.xmttime.fractionl; if (p->trustlevel < TRUSTLEVEL_PATHETIC) interval = scale_interval(INTERVAL_QUERY_PATHETIC); @@ -373,16 +397,25 @@ client_dispatch(struct ntp_peer *p, u_in p->trustlevel++; } - log_debug("reply from %s: offset %f delay %f, " - "next query %ds", log_sockaddr((struct sockaddr *)&p->addr->ss), - p->reply[p->shift].offset, p->reply[p->shift].delay, interval); + if (debug) { + char *s = ""; + int64_t val = reply->offset; + if (val < 0) { + s = "-"; + val = -val; + } + int642timeval(val, &tv1); + int642timeval(reply->delay, &tv2); + log_debug("reply from %s: " + "offset %s%ld.%06lus delay %ld.%06lus, next query %ds", + log_sockaddr((struct sockaddr *)&p->addr->ss), + s, tv1.tv_sec, tv1.tv_usec, tv2.tv_sec, tv2.tv_usec, + interval); + } client_update(p); if (settime) - priv_settime(p->reply[p->shift].offset); - - if (++p->shift >= OFFSET_ARRAY_SIZE) - p->shift = 0; + priv_settime(reply->offset); return (0); } @@ -390,7 +423,8 @@ client_dispatch(struct ntp_peer *p, u_in int client_update(struct ntp_peer *p) { - int i, best = 0, good = 0; + struct ntp_offset *reply, *best, *last; + int good; /* * clock filter @@ -399,28 +433,26 @@ client_update(struct ntp_peer *p) * invalidate it and all older ones */ - for (i = 0; good == 0 && i < OFFSET_ARRAY_SIZE; i++) - if (p->reply[i].good) { - good++; - best = i; - } - - for (; i < OFFSET_ARRAY_SIZE; i++) - if (p->reply[i].good) { - good++; - if (p->reply[i].delay < p->reply[best].delay) - best = i; - } + for (good = 0, best = NULL, reply = &p->reply[0], + last = &p->reply[OFFSET_ARRAY_SIZE]; reply < last; reply++) { + if (!reply->good) + continue; + good++; + if (!best) + best = reply; + if (reply->delay < best->delay) + best = reply; + } - if (good < 8) + if (good < OFFSET_ARRAY_SIZE) return (-1); - memcpy(&p->update, &p->reply[best], sizeof(p->update)); - if (priv_adjtime() == 0) { - for (i = 0; i < OFFSET_ARRAY_SIZE; i++) - if (p->reply[i].rcvd <= p->reply[best].rcvd) - p->reply[i].good = 0; - } + memcpy(&p->update, best, sizeof(p->update)); + if (priv_adjtime() == 0) + for (reply = &p->reply[0], last = &p->reply[OFFSET_ARRAY_SIZE]; + reply < last; reply++) + if (reply->rcvd <= best->rcvd) + reply->good = 0; return (0); } Index: ntp.c =================================================================== RCS file: /cvs/src/usr.sbin/ntpd/ntp.c,v retrieving revision 1.3 diff -u -p -r1.3 ntp.c --- ntp.c 13 May 2009 18:10:04 -0000 1.3 +++ ntp.c 15 May 2009 14:26:35 -0000 @@ -1,4 +1,3 @@ - /* * Copyright (c) 2003, 2004 Henning Brauer <henn...@openbsd.org> * Copyright (c) 2004 Alexander Guy <alexander....@andern.org> @@ -168,7 +167,7 @@ ntp_main(int pipe_prnt[2], struct ntpd_c conf->freq.xx = 0.0; conf->freq.xy = 0.0; conf->freq.y = 0.0; - conf->freq.overall_offset = 0.0; + conf->freq.overall_offset = 0; conf->status.synced = 0; clock_getres(CLOCK_REALTIME, &tp); @@ -522,9 +521,10 @@ peer_remove(struct ntp_peer *p) } static void -priv_adjfreq(double offset) +priv_adjfreq(int64_t offset) { - double curtime, freq; + double curtime, freq, doff; + int64_t relfreq; if (!conf->status.synced) return; @@ -535,12 +535,12 @@ priv_adjfreq(double offset) return; conf->freq.overall_offset += offset; - offset = conf->freq.overall_offset; curtime = gettime_corrected(); - conf->freq.xy += offset * curtime; + doff = conf->freq.overall_offset; + conf->freq.xy += doff * curtime; conf->freq.x += curtime; - conf->freq.y += offset; + conf->freq.y += doff; conf->freq.xx += curtime * curtime; if (conf->freq.samples % FREQUENCY_SAMPLES != 0) @@ -556,13 +556,14 @@ priv_adjfreq(double offset) else if (freq < -MAX_FREQUENCY_ADJUST) freq = -MAX_FREQUENCY_ADJUST; - imsg_compose(ibuf_main, IMSG_ADJFREQ, 0, 0, &freq, sizeof(freq)); + relfreq = freq * 1e9 * (1LL << 32); + imsg_compose(ibuf_main, IMSG_ADJFREQ, 0, 0, &relfreq, sizeof(relfreq)); conf->freq.xy = 0.0; conf->freq.x = 0.0; conf->freq.y = 0.0; conf->freq.xx = 0.0; conf->freq.samples = 0; - conf->freq.overall_offset = 0.0; + conf->freq.overall_offset = 0; conf->freq.num++; } @@ -573,7 +574,7 @@ priv_adjtime(void) struct ntp_sensor *s; int offset_cnt = 0, i = 0, j; struct ntp_offset **offsets; - double offset_median; + int64_t offset_median; TAILQ_FOREACH(p, &conf->ntp_peers, entry) { if (p->trustlevel < TRUSTLEVEL_BADPEER) @@ -626,8 +627,8 @@ priv_adjtime(void) } conf->status.leap = offsets[i]->status.leap; - imsg_compose(ibuf_main, IMSG_ADJTIME, 0, 0, - &offset_median, sizeof(offset_median)); + imsg_compose(ibuf_main, IMSG_ADJTIME, 0, 0, &offset_median, + sizeof(offset_median)); priv_adjfreq(offset_median); @@ -671,9 +672,12 @@ offset_compare(const void *aa, const voi } void -priv_settime(double offset) +priv_settime(int64_t offset) { - imsg_compose(ibuf_main, IMSG_SETTIME, 0, 0, &offset, sizeof(offset)); + struct timeval tv; + + int642timeval(offset, &tv); + imsg_compose(ibuf_main, IMSG_SETTIME, 0, 0, &tv, sizeof(tv)); conf->settime = 0; } @@ -687,19 +691,24 @@ priv_host_dns(char *name, u_int32_t peer } void -update_scale(double offset) +update_scale(int64_t offset) { - offset += getoffset(); - if (offset < 0) - offset = -offset; + struct timeval tv; + int64_t qscale; + + getoffset(&tv); + offset += timeval2int64(&tv); - if (offset > QSCALE_OFF_MAX || !conf->status.synced || - conf->freq.num < 3) + qscale = int64init(QSCALE_OFF_MAX / 1000000, QSCALE_OFF_MAX % 1000000); + if (offset > qscale || !conf->status.synced || conf->freq.num < 3) conf->scale = 1; - else if (offset < QSCALE_OFF_MIN) - conf->scale = QSCALE_OFF_MAX / QSCALE_OFF_MIN; - else - conf->scale = QSCALE_OFF_MAX / offset; + else { + conf->scale = qscale / offset; /* XXX */ + qscale = int64init(QSCALE_OFF_MIN / 1000000, + QSCALE_OFF_MIN % 1000000); + if (offset < qscale) + conf->scale = QSCALE_OFF_MAX / QSCALE_OFF_MIN; + } } time_t @@ -776,4 +785,41 @@ report_peers(int always) log_warnx("bad sensor %s", s->device); } } +} + +int64_t +gettime_corrected() +{ + struct timeval tv; + getoffset(&tv); + return gettime() + timeval2int64(&tv); +} + +void +getoffset(struct timeval *tv) +{ + if (adjtime(NULL, tv) == -1) + memset(tv, 0, sizeof(*tv)); +} + +int64_t +gettime() +{ + struct timeval tv; + + if (gettimeofday(&tv, NULL) == -1) + fatal("gettimeofday"); + + return timeval2int64(&tv) + ((int64_t)JAN_1970 << 31); +} + +time_t +getmonotime(void) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) + fatal("clock_gettime"); + + return (ts.tv_sec); } Index: ntp.h =================================================================== RCS file: /cvs/src/usr.sbin/ntpd/ntp.h,v retrieving revision 1.2 diff -u -p -r1.2 ntp.h --- ntp.h 13 May 2009 18:10:04 -0000 1.2 +++ ntp.h 15 May 2009 14:26:36 -0000 @@ -34,6 +34,7 @@ * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +F * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Integer Part | Fraction Part | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -43,11 +44,41 @@ struct l_fixedpt { u_int32_t fractionl; }; + /* 2147 = 2^31 / 1000000 */ +#define timeval2int64(tv) \ + (((int64_t)(tv)->tv_sec << 31) + (2147U * (tv)->tv_usec)) + +#define int64init(s,u) (((int64_t)(s) << 31) + (2147U * (u))) + +#define int642timeval(i,tv) do { \ + (tv)->tv_sec = (i) >> 31; \ + (tv)->tv_usec = ((i) & 0x7fffffff) / 2148; \ +} while (0) + +#define lfxt2int64(lf) \ + (((int64_t)ntohl((lf)->int_partl) << 31) + (ntohl((lf)->fractionl) >> 1)) + +#define int642lfxt(i,lf) do { \ + (lf)->int_partl = htonl((i) >> 31); \ + (lf)->fractionl = htonl((i) << 1); \ +} while (0) + +#define us2int64(us) (2147ULL * (us)) + struct s_fixedpt { u_int16_t int_parts; u_int16_t fractions; }; +#define int642sfxt(i,lf) do { \ + (lf)->int_parts = htons((i) >> 31); \ + (lf)->fractions = htons((i & 0x7fffffff) >> 15); \ +} while (0) + +#define sfxt2int64(lf) \ + (((int64_t)ntohs((lf)->int_parts) << 31) + \ + ((u_int)ntohs((lf)->fractions) << 15)) + /* RFC Section 4 * * 0 1 2 3 @@ -107,9 +138,9 @@ struct ntp_msg { } __packed; struct ntp_query { - int fd; - struct ntp_msg msg; - double xmttime; + struct ntp_msg msg; + int64_t xmttime; + int fd; }; /* @@ -139,8 +170,8 @@ struct ntp_query { #define MODE_RES1 6 /* reserved for NTP control message */ #define MODE_RES2 7 /* reserved for private use */ -#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */ -#define JAN_2030 1893456000UL + JAN_1970 /* 1. 1. 2030 00:00:00 */ +#define JAN_1970 2208988800LL /* 1970 - 1900 in seconds */ +#define JAN_2030 ((JAN_1970 + 1893456000LL) << 31) /* 1. 1. 2030 00:00:00 */ #define NTP_VERSION 4 #define NTP_MAXSTRATUM 15 Index: ntpd.c =================================================================== RCS file: /cvs/src/usr.sbin/ntpd/ntpd.c,v retrieving revision 1.4 diff -u -p -r1.4 ntpd.c --- ntpd.c 14 May 2009 12:23:33 -0000 1.4 +++ ntpd.c 15 May 2009 14:26:36 -0000 @@ -38,11 +38,11 @@ int main(int, char *[]); int check_child(pid_t, const char *); int dispatch_imsg(struct ntpd_conf *); void reset_adjtime(void); -int ntpd_adjtime(double); -void ntpd_adjfreq(double, int); -void ntpd_settime(double); +int ntpd_adjtime(int64_t); +void ntpd_adjfreq(int64_t, int); +void ntpd_settime(struct timeval *); void readfreq(void); -int writefreq(double); +int writefreq(int64_t); volatile sig_atomic_t quit = 0; volatile sig_atomic_t reconfig = 0; @@ -271,10 +271,11 @@ dispatch_imsg(struct ntpd_conf *lconf) { struct imsg imsg; int n, cnt; - double d; + struct timeval tv; char *name; struct ntp_addr *h, *hn; struct buf *buf; + int64_t d; if ((n = imsg_read(ibuf)) == -1) return (-1); @@ -306,13 +307,13 @@ dispatch_imsg(struct ntpd_conf *lconf) ntpd_adjfreq(d, 1); break; case IMSG_SETTIME: - if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d)) + if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(tv)) fatalx("invalid IMSG_SETTIME received"); if (!lconf->settime) break; log_init(lconf->debug); - memcpy(&d, imsg.data, sizeof(d)); - ntpd_settime(d); + memcpy(&tv, imsg.data, sizeof(tv)); + ntpd_settime(&tv); /* daemonize now */ if (!lconf->debug) if (daemon(1, 0)) @@ -361,19 +362,30 @@ reset_adjtime(void) } int -ntpd_adjtime(double d) +ntpd_adjtime(int64_t d) { - struct timeval tv, olddelta; - int synced = 0; static int firstadj = 1; + struct timeval tv, tv1, olddelta; + char *s = ""; + int synced = 0; - d += getoffset(); - if (d >= (double)LOG_NEGLIGIBLE_ADJTIME / 1000 || - d <= -1 * (double)LOG_NEGLIGIBLE_ADJTIME / 1000) - log_info("adjusting local clock by %fs", d); + getoffset(&olddelta); + int642timeval(d, &tv); + timeradd(&tv, &olddelta, &tv); + + if (d < 0) { + s = "-"; + d = -d; + } + + int642timeval(d, &tv1); + if (tv1.tv_sec || tv1.tv_usec >= LOG_NEGLIGEE * 1000) + log_info("adjusting local clock by %s%ld.%06lus", + s, tv1.tv_sec, tv1.tv_usec); else - log_debug("adjusting local clock by %fs", d); - d_to_tv(d, &tv); + log_debug("adjusting local clock by %s%ld.%06lus", + s, tv1.tv_sec, tv1.tv_usec); + if (adjtime(&tv, &olddelta) == -1) log_warn("adjtime failed"); else if (!firstadj && olddelta.tv_sec == 0 && olddelta.tv_usec == 0) @@ -383,44 +395,42 @@ ntpd_adjtime(double d) } void -ntpd_adjfreq(double relfreq, int wrlog) +ntpd_adjfreq(int64_t relfreq, int wrlog) { int64_t curfreq; - double ppmfreq; + char *sign = ""; int r; if (adjfreq(NULL, &curfreq) == -1) { log_warn("adjfreq failed"); return; } + curfreq += relfreq; /* - * adjfreq's unit is ns/s shifted left 32; convert relfreq to - * that unit before adding. We log values in part per million. + * adjfreq's unit is ns/s shifted left 32. + * We log values in part per million. */ - curfreq += relfreq * 1e9 * (1LL << 32); - r = writefreq(curfreq / 1e9 / (1LL << 32)); - ppmfreq = relfreq * 1e6; - if (wrlog) { - if (ppmfreq >= LOG_NEGLIGIBLE_ADJFREQ || - ppmfreq <= -LOG_NEGLIGIBLE_ADJFREQ) - log_info("adjusting clock frequency by %f to %fppm%s", - ppmfreq, curfreq / 1e3 / (1LL << 32), - r ? "" : " (no drift file)"); - else - log_debug("adjusting clock frequency by %f to %fppm%s", - ppmfreq, curfreq / 1e3 / (1LL << 32), - r ? "" : " (no drift file)"); - } + r = writefreq(curfreq); + if (relfreq < 0) { + relfreq = -relfreq; + sign = "-"; + } + if (wrlog) + log_info("adjusting clock frequency by %s0.%06d to %d.%06dppm%s", + sign, (int)(relfreq >> 32) % 1000000, + (int)(curfreq >> 32) / 1000000, + (int)(curfreq >> 32) % 1000000, + r ? " (no drift file)" : ""); if (adjfreq(&curfreq, NULL) == -1) log_warn("adjfreq failed"); } void -ntpd_settime(double d) +ntpd_settime(struct timeval *tv) { - struct timeval tv, curtime; + struct timeval curtime; char buf[80]; time_t tval; @@ -428,9 +438,8 @@ ntpd_settime(double d) log_warn("gettimeofday"); return; } - d_to_tv(d, &tv); - curtime.tv_usec += tv.tv_usec + 1000000; - curtime.tv_sec += tv.tv_sec - 1 + (curtime.tv_usec / 1000000); + curtime.tv_usec += tv->tv_usec + 1000000; + curtime.tv_sec += tv->tv_sec - 1 + (curtime.tv_usec / 1000000); curtime.tv_usec %= 1000000; if (settimeofday(&curtime, NULL) == -1) { @@ -440,15 +449,15 @@ ntpd_settime(double d) tval = curtime.tv_sec; strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime(&tval)); - log_info("set local clock to %s (offset %fs)", buf, d); + log_info("set local clock to %s (offset %ld.%06lus)", buf, + tv->tv_sec, tv->tv_usec); } void readfreq(void) { + int64_t current, d; FILE *fp; - int64_t current; - double d; fp = fopen(DRIFTFILE, "r"); if (fp == NULL) { @@ -463,7 +472,7 @@ readfreq(void) if (adjfreq(NULL, ¤t) == -1) log_warn("adjfreq failed"); else if (current == 0) { - if (fscanf(fp, "%le", &d) == 1) + if (fscanf(fp, "%lld", &d) == 1) ntpd_adjfreq(d, 0); else log_warnx("can't read %s", DRIFTFILE); @@ -472,7 +481,7 @@ readfreq(void) } int -writefreq(double d) +writefreq(int64_t d) { int r; FILE *fp; @@ -484,10 +493,10 @@ writefreq(double d) log_warn("can't open %s", DRIFTFILE); warnonce = 0; } - return 0; + return -1; } - fprintf(fp, "%e\n", d); + fprintf(fp, "%lld\n", d); r = ferror(fp); if (fclose(fp) != 0 || r != 0) { if (warnonce) { @@ -495,7 +504,7 @@ writefreq(double d) warnonce = 0; } unlink(DRIFTFILE); - return 0; + return -1; } - return 1; + return 0; } Index: ntpd.h =================================================================== RCS file: /cvs/src/usr.sbin/ntpd/ntpd.h,v retrieving revision 1.4 diff -u -p -r1.4 ntpd.h --- ntpd.h 14 May 2009 12:23:33 -0000 1.4 +++ ntpd.h 15 May 2009 14:26:36 -0000 @@ -34,7 +34,7 @@ #define CONFFILE "/etc/ntpd.conf" #define DRIFTFILE "/var/db/ntpd.drift" -#define READ_BUF_SIZE 8192 +#define READ_BUF_SIZE 512 #define INTERVAL_QUERY_NORMAL 30 /* sync to peers every n secs */ #define INTERVAL_QUERY_PATHETIC 60 @@ -47,15 +47,14 @@ #define MAX_SERVERS_DNS 8 -#define QSCALE_OFF_MIN 0.001 -#define QSCALE_OFF_MAX 0.050 +#define QSCALE_OFF_MIN 50000 /* us */ +#define QSCALE_OFF_MAX 500000 /* us */ #define QUERYTIME_MAX 15 /* single query might take n secs max */ #define OFFSET_ARRAY_SIZE 8 #define SENSOR_OFFSETS 7 #define SETTIME_TIMEOUT 15 /* max seconds to wait with -s */ -#define LOG_NEGLIGIBLE_ADJTIME 32 /* negligible drift to not log (ms) */ -#define LOG_NEGLIGIBLE_ADJFREQ 0.05 /* negligible rate to not log (ppm) */ +#define LOG_NEGLIGEE 32 /* negligible drift to not log (ms) */ #define FREQUENCY_SAMPLES 8 /* samples for est. of permanent drift */ #define MAX_FREQUENCY_ADJUST 128e-5 /* max correction per iteration */ #define REPORT_INTERVAL (24*60*60) /* interval between status reports */ @@ -94,9 +93,9 @@ struct ntp_addr_wrap { }; struct ntp_status { - double rootdelay; - double rootdispersion; - double reftime; + int64_t rootdelay; + int64_t rootdispersion; + int64_t reftime; u_int32_t refid; u_int32_t send_refid; u_int8_t synced; @@ -108,9 +107,9 @@ struct ntp_status { struct ntp_offset { struct ntp_status status; - double offset; - double delay; - double error; + int64_t offset; + int64_t delay; + int64_t error; time_t rcvd; u_int8_t good; }; @@ -126,56 +125,56 @@ struct ntp_peer { time_t next; time_t deadline; u_int32_t id; + int lasterror; + int senderrors; u_int8_t shift; u_int8_t trustlevel; u_int8_t weight; - int lasterror; - int senderrors; }; struct ntp_sensor { TAILQ_ENTRY(ntp_sensor) entry; struct ntp_offset offsets[SENSOR_OFFSETS]; struct ntp_offset update; + int64_t correction; time_t next; time_t last; char *device; u_int32_t refid; int sensordevid; - int correction; u_int8_t weight; u_int8_t shift; }; struct ntp_conf_sensor { - TAILQ_ENTRY(ntp_conf_sensor) entry; - char *device; - char *refstr; - int correction; - u_int8_t weight; + TAILQ_ENTRY(ntp_conf_sensor) entry; + char *device; + char *refstr; + int correction; + u_int8_t weight; }; struct ntp_freq { - double overall_offset; - double x, y; - double xx, xy; - int samples; - u_int num; + double x, y; + double xx, xy; + int64_t overall_offset; + int samples; + u_int num; }; struct ntpd_conf { - TAILQ_HEAD(listen_addrs, listen_addr) listen_addrs; - TAILQ_HEAD(ntp_peers, ntp_peer) ntp_peers; - TAILQ_HEAD(ntp_sensors, ntp_sensor) ntp_sensors; - TAILQ_HEAD(ntp_conf_sensors, ntp_conf_sensor) ntp_conf_sensors; - struct ntp_status status; - struct ntp_freq freq; - u_int8_t listen_all; - u_int8_t settime; - u_int8_t debug; - u_int32_t scale; - u_int8_t noaction; - u_int8_t family; + TAILQ_HEAD(, listen_addr) listen_addrs; + TAILQ_HEAD(, ntp_peer) ntp_peers; + TAILQ_HEAD(, ntp_sensor) ntp_sensors; + TAILQ_HEAD(, ntp_conf_sensor) ntp_conf_sensors; + struct ntp_status status; + struct ntp_freq freq; + u_int32_t scale; + u_int8_t listen_all; + u_int8_t settime; + u_int8_t debug; + u_int8_t noaction; + u_int8_t family; }; struct buf { @@ -201,7 +200,7 @@ struct buf_read { /* ipc messages */ #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) -#define MAX_IMSGSIZE 8192 +#define MAX_IMSGSIZE 512 struct imsgbuf { int fd; @@ -264,14 +263,18 @@ int imsg_close(struct imsgbuf *, struct void imsg_free(struct imsg *); /* ntp.c */ -pid_t ntp_main(int[2], struct ntpd_conf *, struct passwd *); -int priv_adjtime(void); -void priv_settime(double); -void priv_host_dns(char *, u_int32_t); -int offset_compare(const void *, const void *); -void update_scale(double); -time_t scale_interval(time_t); -time_t error_interval(void); +pid_t ntp_main(int[2], struct ntpd_conf *, struct passwd *); +int priv_adjtime(void); +void priv_settime(int64_t); +void priv_host_dns(char *, u_int32_t); +int offset_compare(const void *, const void *); +void update_scale(int64_t); +time_t scale_interval(time_t); +time_t error_interval(void); +int64_t gettime_corrected(void); +void getoffset(struct timeval *); +int64_t gettime(void); +time_t getmonotime(void); extern struct ntpd_conf *conf; /* parse.y */ @@ -301,23 +304,12 @@ int client_dispatch(struct ntp_peer *, u void client_log_error(struct ntp_peer *, const char *, int); void set_next(struct ntp_peer *, time_t); -/* util.c */ -double gettime_corrected(void); -double getoffset(void); -double gettime(void); -time_t getmonotime(void); -void d_to_tv(double, struct timeval *); -double lfp_to_d(struct l_fixedpt); -struct l_fixedpt d_to_lfp(double); -double sfp_to_d(struct s_fixedpt); -struct s_fixedpt d_to_sfp(double); - /* sensors.c */ -void sensor_init(void); -int sensor_scan(void); -void sensor_query(struct ntp_sensor *); -int sensor_hotplugfd(void); -void sensor_hotplugevent(int); +void sensor_init(void); +int sensor_scan(void); +void sensor_query(struct ntp_sensor *); +int sensor_hotplugfd(void); +void sensor_hotplugevent(int); /* ntp_dns.c */ pid_t ntp_dns(int[2], struct ntpd_conf *, struct passwd *); Index: sensors.c =================================================================== RCS file: /cvs/src/usr.sbin/ntpd/sensors.c,v retrieving revision 1.3 diff -u -p -r1.3 sensors.c --- sensors.c 13 May 2009 18:10:04 -0000 1.3 +++ sensors.c 15 May 2009 14:26:36 -0000 @@ -121,7 +121,7 @@ sensor_add(int sensordev, char *dxname) s->next = getmonotime(); s->weight = cs->weight; - s->correction = cs->correction; + s->correction = us2int64(cs->correction); if ((s->device = strdup(dxname)) == NULL) fatal("sensor_add strdup"); s->sensordevid = sensordev; @@ -135,8 +135,10 @@ sensor_add(int sensordev, char *dxname) TAILQ_INSERT_TAIL(&conf->ntp_sensors, s, entry); - log_debug("sensor %s added (weight %d, correction %.6f, refstr %.4s)", - s->device, s->weight, s->correction / 1e6, &s->refid); + log_debug( + "sensor %s added (weight %d, correction %d.%06u, refstr %-4s)", + s->device, s->weight, + cs->correction / 1000000, cs->correction % 1000000, &s->refid); } void @@ -152,6 +154,7 @@ sensor_query(struct ntp_sensor *s) { char dxname[MAXDEVNAMLEN]; struct sensor sensor; + struct timeval tv; if (conf->settime) s->next = getmonotime() + SENSOR_QUERY_INTERVAL_SETTIME; @@ -186,16 +189,17 @@ sensor_query(struct ntp_sensor *s) * sensor.value = TS - TD in ns * if value is positive, system time is ahead */ - s->offsets[s->shift].offset = (sensor.value / -1e9) - getoffset() + - (s->correction / 1e6); + getoffset(&tv); + s->offsets[s->shift].offset = s->correction + + us2int64(sensor.value / 1000) - timeval2int64(&tv); s->offsets[s->shift].rcvd = sensor.tv.tv_sec; s->offsets[s->shift].good = 1; s->offsets[s->shift].status.send_refid = s->refid; - s->offsets[s->shift].status.stratum = 0; /* increased when sent out */ + s->offsets[s->shift].status.stratum = 0; /* increased when sent out */ s->offsets[s->shift].status.rootdelay = 0; s->offsets[s->shift].status.rootdispersion = 0; - s->offsets[s->shift].status.reftime = sensor.tv.tv_sec; + s->offsets[s->shift].status.reftime = timeval2int64(&sensor.tv); s->offsets[s->shift].status.synced = 1; log_debug("sensor %s: offset %f", s->device, @@ -226,10 +230,9 @@ sensor_update(struct ntp_sensor *s) i = SENSOR_OFFSETS / 2; memcpy(&s->update, offsets[i], sizeof(s->update)); - if (SENSOR_OFFSETS % 2 == 0) { + if (SENSOR_OFFSETS % 2 == 0) s->update.offset = (offsets[i - 1]->offset + offsets[i]->offset) / 2; - } free(offsets); log_debug("sensor update %s: offset %f", s->device, s->update.offset); Index: server.c =================================================================== RCS file: /cvs/src/usr.sbin/ntpd/server.c,v retrieving revision 1.3 diff -u -p -r1.3 server.c --- server.c 13 May 2009 18:10:04 -0000 1.3 +++ server.c 15 May 2009 14:26:36 -0000 @@ -127,11 +127,11 @@ server_dispatch(int fd, struct ntpd_conf { ssize_t size; u_int8_t version; - double rectime; struct sockaddr_storage fsa; socklen_t fsa_len; struct ntp_msg query, reply; char buf[NTP_MSGSIZE]; + int64_t rectime; fsa_len = sizeof(fsa); if ((size = recvfrom(fd, &buf, sizeof(buf), 0, @@ -146,7 +146,6 @@ server_dispatch(int fd, struct ntpd_conf } rectime = gettime_corrected(); - if (ntp_getmsg((struct sockaddr *)&fsa, buf, size, &query) == -1) return (0); @@ -163,15 +162,16 @@ server_dispatch(int fd, struct ntpd_conf else reply.status |= MODE_SYM_PAS; + reply.refid = lconf->status.refid; reply.stratum = lconf->status.stratum; reply.ppoll = query.ppoll; reply.precision = lconf->status.precision; - reply.rectime = d_to_lfp(rectime); - reply.reftime = d_to_lfp(lconf->status.reftime); - reply.xmttime = d_to_lfp(gettime_corrected()); reply.orgtime = query.xmttime; - reply.rootdelay = d_to_sfp(lconf->status.rootdelay); - reply.refid = lconf->status.refid; + int642lfxt(rectime, &reply.rectime); + int642lfxt(lconf->status.reftime, &reply.reftime); + int642sfxt(lconf->status.rootdelay, &reply.rootdelay); + rectime = gettime_corrected(); + int642lfxt(rectime, &reply.xmttime); ntp_sendmsg(fd, (struct sockaddr *)&fsa, &reply, size, 0); return (0); Index: util.c =================================================================== RCS file: util.c diff -N util.c --- util.c 26 Aug 2008 14:44:25 -0000 1.1.1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,118 +0,0 @@ - -/* - * Copyright (c) 2004 Alexander Guy <alexander....@andern.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/time.h> -#include <limits.h> - -#include "ntpd.h" - -double -gettime_corrected(void) -{ - return (gettime() + getoffset()); -} - -double -getoffset(void) -{ - struct timeval tv; - if (adjtime(NULL, &tv) == -1) - return (0.0); - return (tv.tv_sec + 1.0e-6 * tv.tv_usec); -} - -double -gettime(void) -{ - struct timeval tv; - - if (gettimeofday(&tv, NULL) == -1) - fatal("gettimeofday"); - - return (tv.tv_sec + JAN_1970 + 1.0e-6 * tv.tv_usec); -} - -time_t -getmonotime(void) -{ - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) - fatal("clock_gettime"); - - return (ts.tv_sec); -} - - -void -d_to_tv(double d, struct timeval *tv) -{ - tv->tv_sec = (long)d; - tv->tv_usec = (d - tv->tv_sec) * 1000000; - while (tv->tv_usec < 0) { - tv->tv_usec += 1000000; - tv->tv_sec -= 1; - } -} - -double -lfp_to_d(struct l_fixedpt lfp) -{ - double ret; - - lfp.int_partl = ntohl(lfp.int_partl); - lfp.fractionl = ntohl(lfp.fractionl); - - ret = (double)(lfp.int_partl) + ((double)lfp.fractionl / UINT_MAX); - - return (ret); -} - -struct l_fixedpt -d_to_lfp(double d) -{ - struct l_fixedpt lfp; - - lfp.int_partl = htonl((u_int32_t)d); - lfp.fractionl = htonl((u_int32_t)((d - (u_int32_t)d) * UINT_MAX)); - - return (lfp); -} - -double -sfp_to_d(struct s_fixedpt sfp) -{ - double ret; - - sfp.int_parts = ntohs(sfp.int_parts); - sfp.fractions = ntohs(sfp.fractions); - - ret = (double)(sfp.int_parts) + ((double)sfp.fractions / USHRT_MAX); - - return (ret); -} - -struct s_fixedpt -d_to_sfp(double d) -{ - struct s_fixedpt sfp; - - sfp.int_parts = htons((u_int16_t)d); - sfp.fractions = htons((u_int16_t)((d - (u_int16_t)d) * USHRT_MAX)); - - return (sfp); -}