re
this diff converts ntpd to use socket timestamps (SO_TIMESTAMP sockopt)
for received packets. this seems to reduce deviation by a factor of 5.
code pohnz0red from bgpd and others using recvmsg.
this has ran on a number of servers already (and still should apply
to original ntpd code ;) but surely can use another look.
cu
--
paranoic mickey (my employers have changed but, the name has remained)
Index: client.c
===================================================================
RCS file: /cvs/src/usr.sbin/ntpd/client.c,v
retrieving revision 1.3
diff -u -p -r1.3 client.c
--- client.c 13 May 2009 18:10:04 -0000 1.3
+++ client.c 14 May 2009 14:03:36 -0000
@@ -122,7 +122,7 @@ client_nextaddr(struct ntp_peer *p)
int
client_query(struct ntp_peer *p)
{
- int tos = IPTOS_LOWDELAY;
+ int val;
if (p->addr == NULL && client_nextaddr(p) == -1) {
set_next(p, MAX(SETTIME_TIMEOUT,
@@ -149,9 +149,14 @@ client_query(struct ntp_peer *p)
} else
fatal("client_query connect");
}
+ val = IPTOS_LOWDELAY;
if (p->addr->ss.ss_family == AF_INET && setsockopt(p->query->fd,
- IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1)
+ IPPROTO_IP, IP_TOS, &val, sizeof(val)) == -1)
log_warn("setsockopt IPTOS_LOWDELAY");
+ val = 1;
+ if (setsockopt(p->query->fd, SOL_SOCKET, SO_TIMESTAMP,
+ &val, sizeof(val)) < 0)
+ fatal("setsockopt SO_TIMESTAMP");
}
/*
@@ -190,25 +195,68 @@ 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];
+ union {
+ struct cmsghdr hdr;
+ char buf[CMSG_SPACE(sizeof tv1)];
+ } cmsgbuf;
+ struct cmsghdr *cmsg;
ssize_t size;
- struct ntp_msg msg;
double T1, T2, T3, T4;
time_t interval;
- if ((size = recvfrom(p->query->fd, &buf, sizeof(buf), 0,
- NULL, NULL)) == -1) {
+ somsg.msg_name = NULL;
+ somsg.msg_namelen = 0;
+ somsg.msg_iov = iov;
+ iov[0].iov_base = buf;
+ iov[0].iov_len = sizeof buf;
+ somsg.msg_iovlen = 1;
+ somsg.msg_control = cmsgbuf.buf;
+ somsg.msg_controllen = sizeof cmsgbuf.buf;
+ somsg.msg_flags = 0;
+
+ T4 = getoffset();
+ if ((size = recvmsg(p->query->fd, &somsg, 0)) < 0) {
if (errno == EHOSTUNREACH || errno == EHOSTDOWN ||
errno == ENETUNREACH || errno == ENETDOWN ||
errno == ECONNREFUSED || errno == EADDRNOTAVAIL) {
- client_log_error(p, "recvfrom", errno);
+ client_log_error(p, "recvmsg", errno);
set_next(p, error_interval());
return (0);
} else
fatal("recvfrom");
}
- T4 = gettime_corrected();
+ if (somsg.msg_flags & MSG_TRUNC) {
+ client_log_error(p, "recvmsg packet", EMSGSIZE);
+ set_next(p, error_interval());
+ return (0);
+ }
+
+ if (somsg.msg_flags & MSG_CTRUNC) {
+ client_log_error(p, "recvmsg control data", E2BIG);
+ set_next(p, error_interval());
+ return (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;
+ }
+ }
+
+ if (T4 < JAN_1970) {
+ client_log_error(p, "recvmsg control format", EBADF);
+ set_next(p, error_interval());
+ return (0);
+ }
ntp_getmsg((struct sockaddr *)&p->addr->ss, buf, size, &msg);