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