ntpd: fix jitter calculations and status propagation
authorDenys Vlasenko <vda.linux@googlemail.com>
Sat, 2 Jan 2010 14:57:07 +0000 (15:57 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sat, 2 Jan 2010 14:57:07 +0000 (15:57 +0100)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/ntpd.c

index cabfb79..92e2723 100644 (file)
@@ -166,7 +166,7 @@ typedef struct {
        int              p_fd;
        int              datapoint_idx;
        uint32_t         lastpkt_refid;
-       uint8_t          lastpkt_leap;
+       uint8_t          lastpkt_status;
        uint8_t          lastpkt_stratum;
        uint8_t          p_reachable_bits;
        double           p_xmttime;
@@ -216,7 +216,7 @@ struct globals {
         *  in stratum 2+ packets, it's IPv4 address or 4 first bytes of MD5 hash of IPv6
         */
        uint32_t refid;
-       uint8_t  leap;
+       uint8_t  ntp_status;
        /* precision is defined as the larger of the resolution and time to
         * read the clock, in log2 units.  For instance, the precision of a
         * mains-frequency clock incrementing at 60 Hz is 16 ms, even when the
@@ -245,8 +245,6 @@ struct globals {
 #define G_precision_sec  (1.0 / (1 << (- G_precision_exp)))
        uint8_t  stratum;
        /* Bool. After set to 1, never goes back to 0: */
-//TODO: fix logic:
-//     uint8_t  time_was_stepped;
        uint8_t  adjtimex_was_done;
 
        uint8_t  discipline_state;      // doc calls it c.state
@@ -415,12 +413,13 @@ filter_datapoints(peer_t *p, double t)
         */
        wavg = 0;
        w = 0.5;
-       //                     n-1
-       //                     ---    dispersion(i)
-       // filter_dispersion =  \     -------------
-       //                      /       (i+1)
-       //                     ---     2
-       //                     i=0
+       /*                     n-1
+        *                     ---    dispersion(i)
+        * filter_dispersion =  \     -------------
+        *                      /       (i+1)
+        *                     ---     2
+        *                     i=0
+        */
        got_newest = 0;
        sum = 0;
        for (i = 0; i < NUM_DATAPOINTS; i++) {
@@ -474,21 +473,22 @@ filter_datapoints(peer_t *p, double t)
        }
        p->filter_offset = wavg;
 
-       //                       +-----            -----+ ^ 1/2
-       //                       |  n-1                 |
-       //                       |  ---                 |
-       //                  1    |  \                2  |
-       // filter_jitter = --- * |  /  (avg-offset_j)   |
-       //                  n    |  ---                 |
-       //                       |  j=0                 |
-       //                       +-----            -----+
-       // where n is the number of valid datapoints in the filter (n > 1);
-       // if filter_jitter < precision then filter_jitter = precision
+       /*                  +-----                 -----+ ^ 1/2
+        *                  |       n-1                 |
+        *                  |       ---                 |
+        *                  |  1    \                2  |
+        * filter_jitter =  | --- * /  (avg-offset_j)   |
+        *                  |  n    ---                 |
+        *                  |       j=0                 |
+        *                  +-----                 -----+
+        * where n is the number of valid datapoints in the filter (n > 1);
+        * if filter_jitter < precision then filter_jitter = precision
+        */
        sum = 0;
        for (i = 0; i < NUM_DATAPOINTS; i++) {
                sum += SQUARE(wavg - p->filter_datapoint[i].d_offset);
        }
-       sum = SQRT(sum) / NUM_DATAPOINTS;
+       sum = SQRT(sum / NUM_DATAPOINTS);
        p->filter_jitter = sum > G_precision_sec ? sum : G_precision_sec;
 
        VERB3 bb_error_msg("filter offset:%f(corr:%e) disp:%f jitter:%f",
@@ -570,22 +570,23 @@ do_sendto(int fd,
 static int
 send_query_to_peer(peer_t *p)
 {
-       // Why do we need to bind()?
-       // See what happens when we don't bind:
-       //
-       // socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 3
-       // setsockopt(3, SOL_IP, IP_TOS, [16], 4) = 0
-       // gettimeofday({1259071266, 327885}, NULL) = 0
-       // sendto(3, "xxx", 48, MSG_DONTWAIT, {sa_family=AF_INET, sin_port=htons(123), sin_addr=inet_addr("10.34.32.125")}, 16) = 48
-       // ^^^ we sent it from some source port picked by kernel.
-       // time(NULL)              = 1259071266
-       // write(2, "ntpd: entering poll 15 secs\n", 28) = 28
-       // poll([{fd=3, events=POLLIN}], 1, 15000) = 1 ([{fd=3, revents=POLLIN}])
-       // recv(3, "yyy", 68, MSG_DONTWAIT) = 48
-       // ^^^ this recv will receive packets to any local port!
-       //
-       // Uncomment this and use strace to see it in action:
-#define PROBE_LOCAL_ADDR // { len_and_sockaddr lsa; lsa.len = LSA_SIZEOF_SA; getsockname(p->query.fd, &lsa.u.sa, &lsa.len); }
+       /* Why do we need to bind()?
+        * See what happens when we don't bind:
+        *
+        * socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 3
+        * setsockopt(3, SOL_IP, IP_TOS, [16], 4) = 0
+        * gettimeofday({1259071266, 327885}, NULL) = 0
+        * sendto(3, "xxx", 48, MSG_DONTWAIT, {sa_family=AF_INET, sin_port=htons(123), sin_addr=inet_addr("10.34.32.125")}, 16) = 48
+        * ^^^ we sent it from some source port picked by kernel.
+        * time(NULL)              = 1259071266
+        * write(2, "ntpd: entering poll 15 secs\n", 28) = 28
+        * poll([{fd=3, events=POLLIN}], 1, 15000) = 1 ([{fd=3, revents=POLLIN}])
+        * recv(3, "yyy", 68, MSG_DONTWAIT) = 48
+        * ^^^ this recv will receive packets to any local port!
+        *
+        * Uncomment this and use strace to see it in action:
+        */
+#define PROBE_LOCAL_ADDR /* { len_and_sockaddr lsa; lsa.len = LSA_SIZEOF_SA; getsockname(p->query.fd, &lsa.u.sa, &lsa.len); } */
 
        if (p->p_fd == -1) {
                int fd, family;
@@ -662,8 +663,6 @@ step_time(double offset)
        strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime(&tval));
 
        bb_error_msg("setting clock to %s (offset %fs)", buf, offset);
-
-//     G.time_was_stepped = 1;
 }
 
 
@@ -705,13 +704,14 @@ fit(peer_t *p, double rd)
                VERB3 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted);
                return 0;
        }
-//TODO: we never accept such packets anyway, right?
-       if ((p->lastpkt_leap & LI_ALARM) == LI_ALARM
+#if 0  /* we filter out such packets earlier */
+       if ((p->lastpkt_status & LI_ALARM) == LI_ALARM
         || p->lastpkt_stratum >= MAXSTRAT
        ) {
                VERB3 bb_error_msg("peer %s unfit for selection: bad status/stratum", p->p_dotted);
                return 0;
        }
+#endif
        /* rd is root_distance(p, t) */
        if (rd > MAXDIST + FREQ_TOLERANCE * (1 << G.poll_exp)) {
                VERB3 bb_error_msg("peer %s unfit for selection: root distance too high", p->p_dotted);
@@ -908,7 +908,6 @@ select_and_cluster(double t)
                        selection_jitter_sq = 0;
                        for (j = 0; j < num_survivors; j++) {
                                peer_t *q = survivor[j].p;
-//TODO: where is 1/(n-1) * ... multiplier?
                                selection_jitter_sq += SQUARE(p->filter_offset - q->filter_offset);
                        }
                        if (i == 0 || selection_jitter_sq > max_selection_jitter) {
@@ -918,7 +917,7 @@ select_and_cluster(double t)
                        VERB5 bb_error_msg("survivor %d selection_jitter^2:%f",
                                        i, selection_jitter_sq);
                }
-               max_selection_jitter = SQRT(max_selection_jitter);
+               max_selection_jitter = SQRT(max_selection_jitter / num_survivors);
                VERB4 bb_error_msg("max_selection_jitter (at %d):%f min_jitter:%f",
                                max_idx, max_selection_jitter, min_jitter);
 
@@ -991,7 +990,9 @@ update_local_clock(peer_t *p, double t)
        double offset = p->filter_offset;
        double recv_time = p->lastpkt_recv_time;
        double abs_offset;
+#if !USING_KERNEL_PLL_LOOP
        double freq_drift;
+#endif
        double since_last_update;
        double etemp, dtemp;
 
@@ -1017,7 +1018,9 @@ update_local_clock(peer_t *p, double t)
         * and frequency errors.
         */
        since_last_update = recv_time - G.reftime;
+#if !USING_KERNEL_PLL_LOOP
        freq_drift = 0;
+#endif
        if (G.discipline_state == STATE_FREQ) {
                /* Ignore updates until the stepout threshold */
                if (since_last_update < WATCH_THRESHOLD) {
@@ -1025,7 +1028,9 @@ update_local_clock(peer_t *p, double t)
                                        WATCH_THRESHOLD - since_last_update);
                        return 0; /* "leave poll interval as is" */
                }
+#if !USING_KERNEL_PLL_LOOP
                freq_drift = (offset - G.last_update_offset) / since_last_update;
+#endif
        }
 
        /* There are two main regimes: when the
@@ -1145,6 +1150,7 @@ update_local_clock(peer_t *p, double t)
                        break;
 
                default:
+#if !USING_KERNEL_PLL_LOOP
                        /* Compute freq_drift due to PLL and FLL contributions.
                         *
                         * The FLL and PLL frequency gain constants
@@ -1167,6 +1173,7 @@ update_local_clock(peer_t *p, double t)
                        etemp = MIND(since_last_update, (1 << G.poll_exp));
                        dtemp = (4 * PLL) << G.poll_exp;
                        freq_drift += offset * etemp / SQUARE(dtemp);
+#endif
                        set_new_values(STATE_SYNC, offset, recv_time);
                        break;
                }
@@ -1174,7 +1181,7 @@ update_local_clock(peer_t *p, double t)
        }
 
        G.reftime = t;
-       G.leap = p->lastpkt_leap;
+       G.ntp_status = p->lastpkt_status;
        G.refid = p->lastpkt_refid;
        G.rootdelay = p->lastpkt_rootdelay + p->lastpkt_delay;
        dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(s.jitter));
@@ -1241,10 +1248,10 @@ update_local_clock(peer_t *p, double t)
                        /* + (G.last_update_offset < 0 ? -0.5 : 0.5) - too small to bother */
                        + old_tmx_offset; /* almost always 0 */
        tmx.status = STA_PLL;
-       //if (sys_leap == LEAP_ADDSECOND)
-       //      tmx.status |= STA_INS;
-       //else if (sys_leap == LEAP_DELSECOND)
-       //      tmx.status |= STA_DEL;
+       if (G.ntp_status & LI_PLUSSEC)
+               tmx.status |= STA_INS;
+       if (G.ntp_status & LI_MINUSSEC)
+               tmx.status |= STA_DEL;
        tmx.constant = G.poll_exp - 4;
        //tmx.esterror = (u_int32)(clock_jitter * 1e6);
        //tmx.maxerror = (u_int32)((sys_rootdelay / 2 + sys_rootdisp) * 1e6);
@@ -1376,18 +1383,12 @@ recv_and_process_peer_pkt(peer_t *p)
                goto close_sock;
        }
 
-//     /*
-//      * Verify the server is synchronized with valid stratum and
-//      * reference time not later than the transmit time.
-//      */
-//     if (p->lastpkt_leap == NOSYNC || p->lastpkt_stratum >= MAXSTRAT)
-//             return;                 /* unsynchronized */
-//
 //     /* Verify valid root distance */
 //     if (msg.m_rootdelay / 2 + msg.m_rootdisp >= MAXDISP || p->lastpkt_reftime > msg.m_xmt)
 //             return;                 /* invalid header values */
 
-       p->lastpkt_leap = msg.m_status;
+       p->lastpkt_status = msg.m_status;
+       p->lastpkt_stratum = msg.m_stratum;
        p->lastpkt_rootdelay = sfp_to_d(msg.m_rootdelay);
        p->lastpkt_rootdisp = sfp_to_d(msg.m_rootdisp);
        p->lastpkt_refid = msg.m_refid;
@@ -1557,7 +1558,7 @@ recv_and_process_client_pkt(void /*int fd*/)
 
        /* Build a reply packet */
        memset(&msg, 0, sizeof(msg));
-       msg.m_status = G.stratum < MAXSTRAT ? G.leap : LI_ALARM;
+       msg.m_status = G.stratum < MAXSTRAT ? G.ntp_status : LI_ALARM;
        msg.m_status |= (query_status & VERSION_MASK);
        msg.m_status |= ((query_status & MODE_MASK) == MODE_CLIENT) ?
                         MODE_SERVER : MODE_SYM_PAS;
@@ -1822,10 +1823,6 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
                        }
                }
 
-//             if ((trial_cnt > 0 && sent_cnt == 0) || g.peer_cnt == 0) {
-//                     G.time_was_stepped = 1;
-//             }
-
                timeout = nextaction - cur_time;
                if (timeout < 1)
                        timeout = 1;