Recently I made the switch from ntp to openntpd. Seemingly random memory write errors by the ntp daemon finally convinced me that ntp had become too bloated for the reliability I desired.
So far, my experience with openntpd has been very good. But I missed some of the status reporting ability of ntp (e.g, the 'ntpq -c peer' command). As part of the daily.local script, I like to capture the openntpd SIGINFO status, but somehow "4 out of 4 peers valid" was not the level of information I wanted. I decided to offer my first code patch here. In this patch, I had the following goals: - no changes to existing time-computation algorithms and data structures - no new include files required for compiling - no new libraries required for linking - no changes to any files used by make - treat current openntpd data structures as read-only - leave current status messages unchanged, as some folk may be using log file scanners - log the new status informaiton as "info" priority to avoid cluttering more important log files - within the above constraints, provide useful status of openntpd's interaction with the peers This is the output you will see in daemon.log when a SIGINFO signal is received (presuming that syslog puts daemon.info into that file) === start of output ntpd[1503]: 4 out of 4 peers valid ntpd[1503]: clock is synced, stratum 3 ntpd[1503]: peer ntpd[1503]: wt tl st next poll offset delay jitter ntpd[1503]: 10.20.1.1 ntp.89lr.home ntpd[1503]: 1 10 3 688s 1550s 0.985mS 0.346mS 0.081mS ntpd[1503]: 64.113.32.10 from pool 1.us.pool.ntp.org ntpd[1503]: 1 10 2 721s 1609s 6.404mS 51.893mS 2.624mS ntpd[1503]: 67.18.187.111 from pool 1.us.pool.ntp.org ntpd[1503]: 1 10 2 684s 1533s -2.835mS 80.682mS 4.734mS ntpd[1503]: 208.53.158.34 from pool 1.us.pool.ntp.org ntpd[1503]: 1 10 2 641s 1547s -0.624mS 41.273mS 0.388mS === end of output where the columns for each peer are: weight, trustlevel, stratum, time remaining to the next poll, poll interval, local clock's offset from the peer's clock, network delay, jitter in the network delay. With the above goals in mind, I offer the following patch for 5.1. === begin file ntp_5-1.patch Apply by doing: cd /usr/src patch -p0 < ntp_5-1.patch And then rebuild and install ntpd: cd /usr/src/usr.sbin/ntpd make obj make depend make make install And finally, run the new version: /etc/rc.d/ntpd restart =================================================================== --- usr.sbin/ntpd/ntp.c +++ usr.sbin/ntpd/ntp.c Sun Jun 10 15:07:30 2012 @@ -761,23 +761,103 @@ } lastreport = now; if (peer_cnt > 0) { - log_warnx("%u out of %u peers valid", peer_cnt - badpeers, - peer_cnt); + + log_warnx("%u out of %u peers valid", + peer_cnt - badpeers, peer_cnt); + + if (conf->status.synced == 1) + log_info("clock is synced, stratum %u", + conf->status.stratum); + else log_info("clock is unsynced"); + + log_info("peer"); + log_info(" wt tl st next poll offset " + "delay jitter"); + TAILQ_FOREACH(p, &conf->ntp_peers, entry) { + const char *a = "not resolved"; + const char *pool = ""; + + if (p->addr) + a = log_sockaddr( + (struct sockaddr *)&p->addr->ss); + if (p->addr_head.pool) + pool = "from pool "; + + log_info("%s %s%s %s", + a, pool, p->addr_head.name, + print_rtable(p->rtable) ); + if (p->trustlevel < TRUSTLEVEL_BADPEER) { - const char *a = "not resolved"; - const char *pool = ""; - if (p->addr) - a = log_sockaddr( - (struct sockaddr *)&p->addr->ss); - if (p->addr_head.pool) - pool = "from pool "; log_warnx("bad peer %s%s (%s) %s", pool, p->addr_head.name, a, print_rtable(p->rtable)); } + else { + u_int8_t shift, best, validdelaycnt, jittercnt; + double avg_offset, avg_delay, jitter; + + validdelaycnt = best = 0; + avg_offset = avg_delay = 0.0; + for (shift = 0; shift < OFFSET_ARRAY_SIZE; + shift++) { + if (p->reply[shift].delay > 0.0) { + avg_offset += + p->reply[shift].offset; + avg_delay += + p->reply[shift].delay; + + if (p->reply[shift].delay < + p->reply[best].delay) + best = shift; + + validdelaycnt++; + } + } + + if (validdelaycnt > 0) { + avg_offset /= validdelaycnt; + avg_delay /= validdelaycnt; + } + + /* use simple average for jitter */ + /* calculation, as the RFC5905-recommended */ + /* RMS average needs the math library */ + jittercnt = 0; + jitter = 0.0; + for (shift = 0; shift < OFFSET_ARRAY_SIZE; + shift++) { + if (p->reply[shift].delay > 0.0 && + shift != best) { + jitter += + p->reply[shift].delay - + p->reply[best].delay; + jittercnt++; + } + } + + if (jittercnt > 0) jitter /= jittercnt; + + if (p->shift == 0) + shift = OFFSET_ARRAY_SIZE - 1; + else shift = p->shift - 1; + + log_info(" %2u %2u %2u %4us %4us %11.3fmS " + "%9.3fmS %8.3fmS", + p->weight, + p->trustlevel, + p->reply[shift].status.stratum, + p->next - now, + p->next - p->reply[shift].rcvd, + /* milliseconds to reduce number of */ + /* leading zeroes */ + avg_offset * 1000.0, + avg_delay * 1000.0, + jitter * 1000.0); + } } } + if (sensors_cnt > 0) { log_warnx("%u out of %u sensors valid", sensors_cnt - badsensors, sensors_cnt); --- usr.sbin/ntpd/ntpd.8 +++ usr.sbin/ntpd/ntpd.8 Sun Jun 10 22:17:40 2012 @@ -122,7 +122,12 @@ receives a .Dv SIGINFO signal, it writes its peer and sensor status to -.Xr syslog 3 . +.Xr syslog 3 . Included in the status for each peer are: weight, +trustlevel, stratum, time remaining to the next poll (seconds), +poll interval (seconds), local clock's offset from the peer's clock +(milliseconds), network delay (milliseconds), and jitter in the +network delay (milliseconds). + .Sh FILES .Bl -tag -width "/var/db/ntpd.driftXXX" -compact .It Pa /etc/ntpd.conf === end file ntp_5-1.patch