aboutsummaryrefslogtreecommitdiff
path: root/networking/ntpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/ntpd.c')
-rw-r--r--networking/ntpd.c280
1 files changed, 45 insertions, 235 deletions
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 1f17b08ef..9c15999f3 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -373,8 +373,7 @@ typedef struct {
373} peer_t; 373} peer_t;
374 374
375 375
376#define USING_KERNEL_PLL_LOOP 1 376#define USING_KERNEL_PLL_LOOP 1
377#define USING_INITIAL_FREQ_ESTIMATION 0
378 377
379enum { 378enum {
380 OPT_n = (1 << 0), 379 OPT_n = (1 << 0),
@@ -462,12 +461,7 @@ struct globals {
462#define G_precision_sec 0.002 461#define G_precision_sec 0.002
463 uint8_t stratum; 462 uint8_t stratum;
464 463
465#define STATE_NSET 0 /* initial state, "nothing is set" */ 464 //uint8_t discipline_state; // doc calls it c.state
466//#define STATE_FSET 1 /* frequency set from file */
467//#define STATE_SPIK 2 /* spike detected */
468//#define STATE_FREQ 3 /* initial frequency */
469#define STATE_SYNC 4 /* clock synchronized (normal operation) */
470 uint8_t discipline_state; // doc calls it c.state
471 uint8_t poll_exp; // s.poll 465 uint8_t poll_exp; // s.poll
472 int polladj_count; // c.count 466 int polladj_count; // c.count
473 int FREQHOLD_cnt; 467 int FREQHOLD_cnt;
@@ -657,104 +651,11 @@ filter_datapoints(peer_t *p)
657 double sum, wavg; 651 double sum, wavg;
658 datapoint_t *fdp; 652 datapoint_t *fdp;
659 653
660#if 0
661/* Simulations have shown that use of *averaged* offset for p->filter_offset 654/* Simulations have shown that use of *averaged* offset for p->filter_offset
662 * is in fact worse than simply using last received one: with large poll intervals 655 * is in fact worse than simply using last received one: with large poll intervals
663 * (>= 2048) averaging code uses offset values which are outdated by hours, 656 * (>= 2048) averaging code uses offset values which are outdated by hours,
664 * and time/frequency correction goes totally wrong when fed essentially bogus offsets. 657 * and time/frequency correction goes totally wrong when fed essentially bogus offsets.
665 */ 658 */
666 int got_newest;
667 double minoff, maxoff, w;
668 double x = x; /* for compiler */
669 double oldest_off = oldest_off;
670 double oldest_age = oldest_age;
671 double newest_off = newest_off;
672 double newest_age = newest_age;
673
674 fdp = p->filter_datapoint;
675
676 minoff = maxoff = fdp[0].d_offset;
677 for (i = 1; i < NUM_DATAPOINTS; i++) {
678 if (minoff > fdp[i].d_offset)
679 minoff = fdp[i].d_offset;
680 if (maxoff < fdp[i].d_offset)
681 maxoff = fdp[i].d_offset;
682 }
683
684 idx = p->datapoint_idx; /* most recent datapoint's index */
685 /* Average offset:
686 * Drop two outliers and take weighted average of the rest:
687 * most_recent/2 + older1/4 + older2/8 ... + older5/32 + older6/32
688 * we use older6/32, not older6/64 since sum of weights should be 1:
689 * 1/2 + 1/4 + 1/8 + 1/16 + 1/32 + 1/32 = 1
690 */
691 wavg = 0;
692 w = 0.5;
693 /* n-1
694 * --- dispersion(i)
695 * filter_dispersion = \ -------------
696 * / (i+1)
697 * --- 2
698 * i=0
699 */
700 got_newest = 0;
701 sum = 0;
702 for (i = 0; i < NUM_DATAPOINTS; i++) {
703 VERB5 {
704 bb_error_msg("datapoint[%d]: off:%f disp:%f(%f) age:%f%s",
705 i,
706 fdp[idx].d_offset,
707 fdp[idx].d_dispersion, dispersion(&fdp[idx]),
708 G.cur_time - fdp[idx].d_recv_time,
709 (minoff == fdp[idx].d_offset || maxoff == fdp[idx].d_offset)
710 ? " (outlier by offset)" : ""
711 );
712 }
713
714 sum += dispersion(&fdp[idx]) / (2 << i);
715
716 if (minoff == fdp[idx].d_offset) {
717 minoff -= 1; /* so that we don't match it ever again */
718 } else
719 if (maxoff == fdp[idx].d_offset) {
720 maxoff += 1;
721 } else {
722 oldest_off = fdp[idx].d_offset;
723 oldest_age = G.cur_time - fdp[idx].d_recv_time;
724 if (!got_newest) {
725 got_newest = 1;
726 newest_off = oldest_off;
727 newest_age = oldest_age;
728 }
729 x = oldest_off * w;
730 wavg += x;
731 w /= 2;
732 }
733
734 idx = (idx - 1) & (NUM_DATAPOINTS - 1);
735 }
736 p->filter_dispersion = sum;
737 wavg += x; /* add another older6/64 to form older6/32 */
738 /* Fix systematic underestimation with large poll intervals.
739 * Imagine that we still have a bit of uncorrected drift,
740 * and poll interval is big (say, 100 sec). Offsets form a progression:
741 * 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 - 0.7 is most recent.
742 * The algorithm above drops 0.0 and 0.7 as outliers,
743 * and then we have this estimation, ~25% off from 0.7:
744 * 0.1/32 + 0.2/32 + 0.3/16 + 0.4/8 + 0.5/4 + 0.6/2 = 0.503125
745 */
746 x = oldest_age - newest_age;
747 if (x != 0) {
748 x = newest_age / x; /* in above example, 100 / (600 - 100) */
749 if (x < 1) { /* paranoia check */
750 x = (newest_off - oldest_off) * x; /* 0.5 * 100/500 = 0.1 */
751 wavg += x;
752 }
753 }
754 p->filter_offset = wavg;
755
756#else
757
758 fdp = p->filter_datapoint; 659 fdp = p->filter_datapoint;
759 idx = p->datapoint_idx; /* most recent datapoint's index */ 660 idx = p->datapoint_idx; /* most recent datapoint's index */
760 661
@@ -777,7 +678,6 @@ filter_datapoints(peer_t *p)
777 } 678 }
778 wavg /= NUM_DATAPOINTS; 679 wavg /= NUM_DATAPOINTS;
779 p->filter_dispersion = sum; 680 p->filter_dispersion = sum;
780#endif
781 681
782 /* +----- -----+ ^ 1/2 682 /* +----- -----+ ^ 1/2
783 * | n-1 | 683 * | n-1 |
@@ -1548,15 +1448,14 @@ select_and_cluster(void)
1548 * Local clock discipline and its helpers 1448 * Local clock discipline and its helpers
1549 */ 1449 */
1550static void 1450static void
1551set_new_values(int disc_state, double offset, double recv_time) 1451set_new_values(double offset, double recv_time)
1552{ 1452{
1553 /* Enter new state and set state variables. Note we use the time 1453 /* Enter new state and set state variables. Note we use the time
1554 * of the last clock filter sample, which must be earlier than 1454 * of the last clock filter sample, which must be earlier than
1555 * the current time. 1455 * the current time.
1556 */ 1456 */
1557 VERB4 bb_error_msg("disc_state=%d last update offset=%f recv_time=%f", 1457 VERB4 bb_error_msg("last update offset=%f recv_time=%f",
1558 disc_state, offset, recv_time); 1458 offset, recv_time);
1559 G.discipline_state = disc_state;
1560 G.last_update_offset = offset; 1459 G.last_update_offset = offset;
1561 G.last_update_recv_time = recv_time; 1460 G.last_update_recv_time = recv_time;
1562} 1461}
@@ -1572,8 +1471,6 @@ update_local_clock(peer_t *p)
1572 double abs_offset; 1471 double abs_offset;
1573#if !USING_KERNEL_PLL_LOOP 1472#if !USING_KERNEL_PLL_LOOP
1574 double freq_drift; 1473 double freq_drift;
1575#endif
1576#if !USING_KERNEL_PLL_LOOP || USING_INITIAL_FREQ_ESTIMATION
1577 double since_last_update; 1474 double since_last_update;
1578#endif 1475#endif
1579 double etemp, dtemp; 1476 double etemp, dtemp;
@@ -1603,63 +1500,15 @@ update_local_clock(peer_t *p)
1603 * action is and defines how the system reacts to large time 1500 * action is and defines how the system reacts to large time
1604 * and frequency errors. 1501 * and frequency errors.
1605 */ 1502 */
1606#if !USING_KERNEL_PLL_LOOP || USING_INITIAL_FREQ_ESTIMATION
1607 since_last_update = recv_time - G.reftime;
1608#endif
1609#if !USING_KERNEL_PLL_LOOP 1503#if !USING_KERNEL_PLL_LOOP
1504 since_last_update = recv_time - G.reftime;
1610 freq_drift = 0; 1505 freq_drift = 0;
1611#endif 1506#endif
1612#if USING_INITIAL_FREQ_ESTIMATION
1613 if (G.discipline_state == STATE_FREQ) {
1614 /* Ignore updates until the stepout threshold */
1615 if (since_last_update < WATCH_THRESHOLD) {
1616 VERB4 bb_error_msg("measuring drift, datapoint ignored, %f sec remains",
1617 WATCH_THRESHOLD - since_last_update);
1618 return 0; /* "leave poll interval as is" */
1619 }
1620# if !USING_KERNEL_PLL_LOOP
1621 freq_drift = (offset - G.last_update_offset) / since_last_update;
1622# endif
1623 }
1624#endif
1625 1507
1626 /* There are two main regimes: when the 1508 /* There are two main regimes: when the
1627 * offset exceeds the step threshold and when it does not. 1509 * offset exceeds the step threshold and when it does not.
1628 */ 1510 */
1629 if (abs_offset > STEP_THRESHOLD) { 1511 if (abs_offset > STEP_THRESHOLD) {
1630#if 0
1631 double remains;
1632
1633// This "spike state" seems to be useless, peer selection already drops
1634// occassional "bad" datapoints. If we are here, there were _many_
1635// large offsets. When a few first large offsets are seen,
1636// we end up in "no valid datapoints, no peer selected" state.
1637// Only when enough of them are seen (which means it's not a fluke),
1638// we end up here. Looks like _our_ clock is off.
1639 switch (G.discipline_state) {
1640 case STATE_SYNC:
1641 /* The first outlyer: ignore it, switch to SPIK state */
1642 VERB3 bb_error_msg("update from %s: offset:%+f, spike%s",
1643 p->p_dotted, offset,
1644 "");
1645 G.discipline_state = STATE_SPIK;
1646 return -1; /* "decrease poll interval" */
1647
1648 case STATE_SPIK:
1649 /* Ignore succeeding outlyers until either an inlyer
1650 * is found or the stepout threshold is exceeded.
1651 */
1652 remains = WATCH_THRESHOLD - since_last_update;
1653 if (remains > 0) {
1654 VERB3 bb_error_msg("update from %s: offset:%+f, spike%s",
1655 p->p_dotted, offset,
1656 ", datapoint ignored");
1657 return -1; /* "decrease poll interval" */
1658 }
1659 /* fall through: we need to step */
1660 } /* switch */
1661#endif
1662
1663 /* Step the time and clamp down the poll interval. 1512 /* Step the time and clamp down the poll interval.
1664 * 1513 *
1665 * In NSET state an initial frequency correction is 1514 * In NSET state an initial frequency correction is
@@ -1694,16 +1543,17 @@ update_local_clock(peer_t *p)
1694 1543
1695 recv_time += offset; 1544 recv_time += offset;
1696 1545
1697#if USING_INITIAL_FREQ_ESTIMATION
1698 if (G.discipline_state == STATE_NSET) {
1699 set_new_values(STATE_FREQ, /*offset:*/ 0, recv_time);
1700 return 1; /* "ok to increase poll interval" */
1701 }
1702#endif
1703 abs_offset = offset = 0; 1546 abs_offset = offset = 0;
1704 set_new_values(STATE_SYNC, offset, recv_time); 1547 set_new_values(offset, recv_time);
1705 } else { /* abs_offset <= STEP_THRESHOLD */ 1548 } else { /* abs_offset <= STEP_THRESHOLD */
1706 1549
1550 if (option_mask32 & OPT_q) {
1551 /* We were only asked to set time once.
1552 * The clock is precise enough, no need to step.
1553 */
1554 exit(0);
1555 }
1556
1707 /* The ratio is calculated before jitter is updated to make 1557 /* The ratio is calculated before jitter is updated to make
1708 * poll adjust code more sensitive to large offsets. 1558 * poll adjust code more sensitive to large offsets.
1709 */ 1559 */
@@ -1718,75 +1568,31 @@ update_local_clock(peer_t *p)
1718 if (G.discipline_jitter < G_precision_sec) 1568 if (G.discipline_jitter < G_precision_sec)
1719 G.discipline_jitter = G_precision_sec; 1569 G.discipline_jitter = G_precision_sec;
1720 1570
1721 switch (G.discipline_state) {
1722 case STATE_NSET:
1723 if (option_mask32 & OPT_q) {
1724 /* We were only asked to set time once.
1725 * The clock is precise enough, no need to step.
1726 */
1727 exit(0);
1728 }
1729#if USING_INITIAL_FREQ_ESTIMATION
1730 /* This is the first update received and the frequency
1731 * has not been initialized. The first thing to do
1732 * is directly measure the oscillator frequency.
1733 */
1734 set_new_values(STATE_FREQ, offset, recv_time);
1735#else
1736 set_new_values(STATE_SYNC, offset, recv_time);
1737#endif
1738 VERB4 bb_simple_error_msg("transitioning to FREQ, datapoint ignored");
1739 return 0; /* "leave poll interval as is" */
1740
1741#if 0 /* this is dead code for now */
1742 case STATE_FSET:
1743 /* This is the first update and the frequency
1744 * has been initialized. Adjust the phase, but
1745 * don't adjust the frequency until the next update.
1746 */
1747 set_new_values(STATE_SYNC, offset, recv_time);
1748 /* freq_drift remains 0 */
1749 break;
1750#endif
1751
1752#if USING_INITIAL_FREQ_ESTIMATION
1753 case STATE_FREQ:
1754 /* since_last_update >= WATCH_THRESHOLD, we waited enough.
1755 * Correct the phase and frequency and switch to SYNC state.
1756 * freq_drift was already estimated (see code above)
1757 */
1758 set_new_values(STATE_SYNC, offset, recv_time);
1759 break;
1760#endif
1761
1762 default:
1763#if !USING_KERNEL_PLL_LOOP 1571#if !USING_KERNEL_PLL_LOOP
1764 /* Compute freq_drift due to PLL and FLL contributions. 1572 /* Compute freq_drift due to PLL and FLL contributions.
1765 * 1573 *
1766 * The FLL and PLL frequency gain constants 1574 * The FLL and PLL frequency gain constants
1767 * depend on the poll interval and Allan 1575 * depend on the poll interval and Allan
1768 * intercept. The FLL is not used below one-half 1576 * intercept. The FLL is not used below one-half
1769 * the Allan intercept. Above that the loop gain 1577 * the Allan intercept. Above that the loop gain
1770 * increases in steps to 1 / AVG. 1578 * increases in steps to 1 / AVG.
1771 */ 1579 */
1772 if ((1 << G.poll_exp) > ALLAN / 2) { 1580 if ((1 << G.poll_exp) > ALLAN / 2) {
1773 etemp = FLL - G.poll_exp; 1581 etemp = FLL - G.poll_exp;
1774 if (etemp < AVG) 1582 if (etemp < AVG)
1775 etemp = AVG; 1583 etemp = AVG;
1776 freq_drift += (offset - G.last_update_offset) / (MAXD(since_last_update, ALLAN) * etemp); 1584 freq_drift += (offset - G.last_update_offset) / (MAXD(since_last_update, ALLAN) * etemp);
1777 }
1778 /* For the PLL the integration interval
1779 * (numerator) is the minimum of the update
1780 * interval and poll interval. This allows
1781 * oversampling, but not undersampling.
1782 */
1783 etemp = MIND(since_last_update, (1 << G.poll_exp));
1784 dtemp = (4 * PLL) << G.poll_exp;
1785 freq_drift += offset * etemp / SQUARE(dtemp);
1786#endif
1787 set_new_values(STATE_SYNC, offset, recv_time);
1788 break;
1789 } 1585 }
1586 /* For the PLL the integration interval
1587 * (numerator) is the minimum of the update
1588 * interval and poll interval. This allows
1589 * oversampling, but not undersampling.
1590 */
1591 etemp = MIND(since_last_update, (1 << G.poll_exp));
1592 dtemp = (4 * PLL) << G.poll_exp;
1593 freq_drift += offset * etemp / SQUARE(dtemp);
1594#endif
1595 set_new_values(offset, recv_time);
1790 if (G.stratum != p->lastpkt_stratum + 1) { 1596 if (G.stratum != p->lastpkt_stratum + 1) {
1791 G.stratum = p->lastpkt_stratum + 1; 1597 G.stratum = p->lastpkt_stratum + 1;
1792 run_script("stratum", offset); 1598 run_script("stratum", offset);
@@ -1805,9 +1611,7 @@ update_local_clock(peer_t *p)
1805 G.rootdisp = p->lastpkt_rootdisp + dtemp; 1611 G.rootdisp = p->lastpkt_rootdisp + dtemp;
1806 VERB4 bb_error_msg("updating leap/refid/reftime/rootdisp from peer %s", p->p_dotted); 1612 VERB4 bb_error_msg("updating leap/refid/reftime/rootdisp from peer %s", p->p_dotted);
1807 1613
1808 /* We are in STATE_SYNC now, but did not do adjtimex yet. 1614 /* By this time, freq_drift and offset are set
1809 * (Any other state does not reach this, they all return earlier)
1810 * By this time, freq_drift and offset are set
1811 * to values suitable for adjtimex. 1615 * to values suitable for adjtimex.
1812 */ 1616 */
1813#if !USING_KERNEL_PLL_LOOP 1617#if !USING_KERNEL_PLL_LOOP
@@ -2349,6 +2153,12 @@ recv_and_process_client_pkt(void /*int fd*/)
2349 do_sendto(G_listen_fd, 2153 do_sendto(G_listen_fd,
2350 /*from:*/ &to->u.sa, /*to:*/ from, /*addrlen:*/ to->len, 2154 /*from:*/ &to->u.sa, /*to:*/ from, /*addrlen:*/ to->len,
2351 &msg, size); 2155 &msg, size);
2156 VERB3 {
2157 char *addr;
2158 addr = xmalloc_sockaddr2dotted_noport(from);
2159 bb_error_msg("responded to query from %s", addr);
2160 free(addr);
2161 }
2352 2162
2353 bail: 2163 bail:
2354 free(to); 2164 free(to);
@@ -2767,7 +2577,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
2767 timeout++; /* (nextaction - G.cur_time) rounds down, compensating */ 2577 timeout++; /* (nextaction - G.cur_time) rounds down, compensating */
2768 2578
2769 /* Here we may block */ 2579 /* Here we may block */
2770 VERB2 { 2580 VERB3 {
2771 if (i > (ENABLE_FEATURE_NTPD_SERVER && G_listen_fd != -1)) { 2581 if (i > (ENABLE_FEATURE_NTPD_SERVER && G_listen_fd != -1)) {
2772 /* We wait for at least one reply. 2582 /* We wait for at least one reply.
2773 * Poll for it, without wasting time for message. 2583 * Poll for it, without wasting time for message.