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);
 

Reply via email to