1 This patch adds support for the Linux adjtimex call to OpenNTPd, to adjust
2 the kernel to compensate for systematic clock skew/drift.
5 cd openntpd-3.6p1 && patch -p0 </tmp/openntpd-3.6p1-linux-adjtimex4.patch
7 then either rebuild configure with "autoconf" or define USE_ADJTIMEX with:
8 CFLAGS=-DUSE_ADJTIMEX ./configure && make
11 ===================================================================
12 RCS file: /usr/local/cvs/openntpd-portable/client.c,v
13 retrieving revision 1.14
14 diff -u -p -r1.14 client.c
15 --- client.c 20 Aug 2004 11:44:24 -0000 1.14
16 +++ client.c 11 Nov 2004 23:10:24 -0000
17 @@ -270,7 +270,8 @@ client_update(struct ntp_peer *p)
19 * find the offset which arrived with the lowest delay
20 * use that as the peer update
21 - * invalidate it and all older ones
22 + * Afterwards, invalidate all offsets: since we're going to adjust,
23 + * the old ones will not be valid any more anyway.
26 for (i = 0; good == 0 && i < OFFSET_ARRAY_SIZE; i++)
27 @@ -293,8 +294,7 @@ client_update(struct ntp_peer *p)
30 for (i = 0; i < OFFSET_ARRAY_SIZE; i++)
31 - if (p->reply[i].rcvd <= p->reply[best].rcvd)
32 - p->reply[i].good = 0;
33 + p->reply[i].good = 0;
38 ===================================================================
39 RCS file: /usr/local/cvs/openntpd-portable/configure.ac,v
40 retrieving revision 1.31.2.3
41 diff -u -p -r1.31.2.3 configure.ac
42 --- configure.ac 15 Oct 2004 01:39:37 -0000 1.31.2.3
43 +++ configure.ac 11 Nov 2004 23:10:24 -0000
44 @@ -388,6 +388,11 @@ AC_ARG_WITH(builtin-arc4random,
45 [ builtin_arc4random=$withval ]
48 +AC_ARG_WITH(adjtimex,
49 + [ --with-adjtimex Use adjtimex to adjust kernel skew],
50 + [ AC_DEFINE(USE_ADJTIMEX, [], [Use adjust skew with adjtimex (experimental)]) ]
53 # Search for OpenSSL if required.
54 if test "$ac_cv_func_arc4random" != "yes" && test "x$builtin_arc4random" != "xyes"; then
55 saved_CPPFLAGS="$CPPFLAGS"
57 ===================================================================
58 RCS file: /usr/local/cvs/openntpd-portable/defines.h,v
59 retrieving revision 1.13.2.1
60 diff -u -p -r1.13.2.1 defines.h
61 --- defines.h 14 Oct 2004 09:58:57 -0000 1.13.2.1
62 +++ defines.h 11 Nov 2004 23:10:24 -0000
64 # define setproctitle(x)
68 +# define adjtime(a,b) (_compat_adjtime((a),(b)))
72 # if defined(HAVE_STRUCT_SOCKADDR_SA_LEN)
73 # define SA_LEN(x) ((x)->sa_len)
74 Index: openbsd-compat/Makefile.in
75 ===================================================================
76 RCS file: /usr/local/cvs/openntpd-portable/openbsd-compat/Makefile.in,v
77 retrieving revision 1.4.2.1
78 diff -u -p -r1.4.2.1 Makefile.in
79 --- openbsd-compat/Makefile.in 14 Oct 2004 09:59:00 -0000 1.4.2.1
80 +++ openbsd-compat/Makefile.in 11 Nov 2004 23:11:05 -0000
81 @@ -8,6 +8,7 @@ all: libopenbsd-compat.a
83 OPENBSD= asprintf.o daemon.o inet_pton.o strlcpy.o
84 COMPAT= bsd-arc4random.o bsd-misc.o fake-rfc2553.o uidswap.o
89 @@ -22,14 +23,14 @@ INSTALL=@INSTALL@
91 $(COMPAT): ../config.h
92 $(OPENBSD): ../config.h
97 $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
99 -libopenbsd-compat.a: $(COMPAT) $(OPENBSD)
100 - $(AR) rv $@ $(COMPAT) $(OPENBSD)
101 +libopenbsd-compat.a: $(COMPAT) $(OPENBSD) $(PORT)
102 + $(AR) rv $@ $(COMPAT) $(OPENBSD) $(PORT)
106 - rm -f $(COMPAT) $(OPENBSD) libopenbsd-compat.a
107 + rm -f $(COMPAT) $(OPENBSD) $(PORT) libopenbsd-compat.a
108 Index: openbsd-compat/openbsd-compat.h
109 ===================================================================
110 RCS file: /usr/local/cvs/openntpd-portable/openbsd-compat/openbsd-compat.h,v
111 retrieving revision 1.4.2.3
112 diff -u -p -r1.4.2.3 openbsd-compat.h
113 --- openbsd-compat/openbsd-compat.h 14 Oct 2004 12:36:34 -0000 1.4.2.3
114 +++ openbsd-compat/openbsd-compat.h 11 Nov 2004 23:10:24 -0000
115 @@ -52,4 +52,9 @@ int seteuid(uid_t);
117 #endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */
120 +# include <sys/time.h>
121 +int _compat_adjtime(const struct timeval *, struct timeval *);
124 int permanently_set_uid(struct passwd *);
125 Index: openbsd-compat/port-linux.c
126 ===================================================================
127 RCS file: openbsd-compat/port-linux.c
128 diff -N openbsd-compat/port-linux.c
129 --- /dev/null 1 Jan 1970 00:00:00 -0000
130 +++ openbsd-compat/port-linux.c 11 Nov 2004 23:12:42 -0000
135 + * Copyright (c) 2004 Darren Tucker <dtucker at zip com au>
137 + * Permission to use, copy, modify, and distribute this software for any
138 + * purpose with or without fee is hereby granted, provided that the above
139 + * copyright notice and this permission notice appear in all copies.
141 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
142 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
143 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
144 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
145 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
146 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
147 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
150 +#include "includes.h"
153 +#include <sys/timex.h>
159 +/* scale factor used by adjtimex freq param. 1 ppm = 65536 */
160 +#define ADJTIMEX_FREQ_SCALE 65536
162 +/* maximum change to skew per adjustment, in PPM */
163 +#define MAX_SKEW_DELTA 5.0
166 + * Prevent warnings. We can't just include ntpd.h because of conflicting
167 + * definitions of ntp_adjtime()
169 +void log_warn(const char *, ...);
170 +void log_info(const char *, ...);
173 +_compat_adjtime(const struct timeval *delta, struct timeval *olddelta)
175 + static struct timeval tlast = {0,0};
176 + static double tskew = 0;
177 + static int synced = -1;
178 + struct timeval tnow, tdelta;
179 + double skew = 0, newskew, deltaskew, adjust, interval = 0;
181 + int result, saved_errno;
183 + gettimeofday(&tnow, NULL);
184 + adjust = (double)delta->tv_sec;
185 + adjust += (double)delta->tv_usec / 1000000;
187 + /* Even if the caller doesn't care about the olddelta, we do */
188 + if (olddelta == NULL)
189 + olddelta = &tdelta;
191 + result = adjtime(delta, olddelta);
192 + saved_errno = errno;
194 + if (olddelta->tv_sec == 0 && olddelta->tv_usec == 0 &&
201 + * do skew calculations if we have synced
203 + if (synced == 0 ) {
205 + if (adjtimex(&tmx) == -1)
206 + log_warn("adjtimex get failed");
208 + tskew = (double)tmx.freq / ADJTIMEX_FREQ_SCALE;
209 + } else if (synced >= 1) {
210 + interval = (double)(tnow.tv_sec - tlast.tv_sec);
211 + interval += (double)(tnow.tv_usec - tlast.tv_usec) / 1000000;
213 + skew = (adjust * 1000000) / interval;
214 + newskew = ((tskew * synced) + skew) / synced;
215 + deltaskew = newskew - tskew;
217 + if (deltaskew > MAX_SKEW_DELTA) {
218 + log_info("skew change %0.3lf exceeds limit", deltaskew);
219 + tskew += MAX_SKEW_DELTA;
220 + } else if (deltaskew < -MAX_SKEW_DELTA) {
221 + log_info("skew change %0.3lf exceeds limit", deltaskew);
222 + tskew -= MAX_SKEW_DELTA;
227 + /* Adjust the kernel skew. */
228 + tmx.freq = (long)(tskew * ADJTIMEX_FREQ_SCALE);
229 + tmx.modes = ADJ_FREQUENCY;
230 + if (adjtimex(&tmx) == -1)
231 + log_warn("adjtimex set freq failed");
234 + log_info("interval %0.3lf skew %0.3lf total skew %0.3lf", interval,
238 + errno = saved_errno;