diff options
author | Miroslav Lichvar <mlichvar@redhat.com> | 2014-10-02 17:18:43 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2014-10-02 17:24:34 +0200 |
commit | b434ce70696879aad066fff67253e44e5f5b238e (patch) | |
tree | b29fa99983269a0ccd448d3ba8b6eba8b4dace93 | |
parent | cf76b5ce12a685b0c0a8ea53fa95cb0f0922a4f1 (diff) | |
download | busybox-w32-b434ce70696879aad066fff67253e44e5f5b238e.tar.gz busybox-w32-b434ce70696879aad066fff67253e44e5f5b238e.tar.bz2 busybox-w32-b434ce70696879aad066fff67253e44e5f5b238e.zip |
ntpd: don't stay at short polling interval
To avoid polling servers frequently slowly increase the interval up
to BIGPOLL when
- no replies are received from a peer
- no source can be selected
- peer claims to be unsynchronized (e.g. we are polling it too
frequently)
When recv() returns with an error, drop code to try to continue
on network errors: I'm not convinced those cases happen in real life.
function old new delta
recv_and_process_peer_pkt 919 838 -81
Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/ntpd.c | 80 |
1 files changed, 53 insertions, 27 deletions
diff --git a/networking/ntpd.c b/networking/ntpd.c index b2b2791a8..838a367fe 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c | |||
@@ -136,17 +136,17 @@ | |||
136 | #define BURSTPOLL 0 /* initial poll */ | 136 | #define BURSTPOLL 0 /* initial poll */ |
137 | #define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */ | 137 | #define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */ |
138 | /* | 138 | /* |
139 | * If offset > discipline_jitter * POLLADJ_GATE, and poll interval is >= 2^BIGPOLL, | 139 | * If offset > discipline_jitter * POLLADJ_GATE, and poll interval is > 2^BIGPOLL, |
140 | * then it is decreased _at once_. (If < 2^BIGPOLL, it will be decreased _eventually_). | 140 | * then it is decreased _at once_. (If <= 2^BIGPOLL, it will be decreased _eventually_). |
141 | */ | 141 | */ |
142 | #define BIGPOLL 10 /* 2^10 sec ~= 17 min */ | 142 | #define BIGPOLL 9 /* 2^9 sec ~= 8.5 min */ |
143 | #define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */ | 143 | #define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */ |
144 | /* | 144 | /* |
145 | * Actively lower poll when we see such big offsets. | 145 | * Actively lower poll when we see such big offsets. |
146 | * With STEP_THRESHOLD = 0.125, it means we try to sync more aggressively | 146 | * With STEP_THRESHOLD = 0.125, it means we try to sync more aggressively |
147 | * if offset increases over ~0.04 sec | 147 | * if offset increases over ~0.04 sec |
148 | */ | 148 | */ |
149 | #define POLLDOWN_OFFSET (STEP_THRESHOLD / 3) | 149 | //#define POLLDOWN_OFFSET (STEP_THRESHOLD / 3) |
150 | #define MINDISP 0.01 /* minimum dispersion (sec) */ | 150 | #define MINDISP 0.01 /* minimum dispersion (sec) */ |
151 | #define MAXDISP 16 /* maximum dispersion (sec) */ | 151 | #define MAXDISP 16 /* maximum dispersion (sec) */ |
152 | #define MAXSTRAT 16 /* maximum stratum (infinity metric) */ | 152 | #define MAXSTRAT 16 /* maximum stratum (infinity metric) */ |
@@ -984,8 +984,8 @@ static void clamp_pollexp_and_set_MAXSTRAT(void) | |||
984 | { | 984 | { |
985 | if (G.poll_exp < MINPOLL) | 985 | if (G.poll_exp < MINPOLL) |
986 | G.poll_exp = MINPOLL; | 986 | G.poll_exp = MINPOLL; |
987 | if (G.poll_exp >= BIGPOLL) | 987 | if (G.poll_exp > BIGPOLL) |
988 | G.poll_exp = BIGPOLL - 1; | 988 | G.poll_exp = BIGPOLL; |
989 | G.polladj_count = 0; | 989 | G.polladj_count = 0; |
990 | G.stratum = MAXSTRAT; | 990 | G.stratum = MAXSTRAT; |
991 | } | 991 | } |
@@ -1682,7 +1682,7 @@ poll_interval(int upper_bound) | |||
1682 | VERB4 bb_error_msg("chose poll interval:%u (poll_exp:%d)", interval, G.poll_exp); | 1682 | VERB4 bb_error_msg("chose poll interval:%u (poll_exp:%d)", interval, G.poll_exp); |
1683 | return interval; | 1683 | return interval; |
1684 | } | 1684 | } |
1685 | static NOINLINE void | 1685 | static void |
1686 | adjust_poll(int count) | 1686 | adjust_poll(int count) |
1687 | { | 1687 | { |
1688 | G.polladj_count += count; | 1688 | G.polladj_count += count; |
@@ -1693,7 +1693,7 @@ adjust_poll(int count) | |||
1693 | VERB4 bb_error_msg("polladj: discipline_jitter:%f ++poll_exp=%d", | 1693 | VERB4 bb_error_msg("polladj: discipline_jitter:%f ++poll_exp=%d", |
1694 | G.discipline_jitter, G.poll_exp); | 1694 | G.discipline_jitter, G.poll_exp); |
1695 | } | 1695 | } |
1696 | } else if (G.polladj_count < -POLLADJ_LIMIT || (count < 0 && G.poll_exp >= BIGPOLL)) { | 1696 | } else if (G.polladj_count < -POLLADJ_LIMIT || (count < 0 && G.poll_exp > BIGPOLL)) { |
1697 | G.polladj_count = 0; | 1697 | G.polladj_count = 0; |
1698 | if (G.poll_exp > MINPOLL) { | 1698 | if (G.poll_exp > MINPOLL) { |
1699 | llist_t *item; | 1699 | llist_t *item; |
@@ -1736,19 +1736,23 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1736 | * ntp servers reply from their *other IP*. | 1736 | * ntp servers reply from their *other IP*. |
1737 | * TODO: maybe we should check at least what we can: from.port == 123? | 1737 | * TODO: maybe we should check at least what we can: from.port == 123? |
1738 | */ | 1738 | */ |
1739 | recv_again: | ||
1739 | size = recv(p->p_fd, &msg, sizeof(msg), MSG_DONTWAIT); | 1740 | size = recv(p->p_fd, &msg, sizeof(msg), MSG_DONTWAIT); |
1740 | if (size == -1) { | 1741 | if (size < 0) { |
1741 | bb_perror_msg("recv(%s) error", p->p_dotted); | 1742 | if (errno == EINTR) |
1742 | if (errno == EHOSTUNREACH || errno == EHOSTDOWN | 1743 | /* Signal caught */ |
1743 | || errno == ENETUNREACH || errno == ENETDOWN | 1744 | goto recv_again; |
1744 | || errno == ECONNREFUSED || errno == EADDRNOTAVAIL | 1745 | if (errno == EAGAIN) |
1745 | || errno == EAGAIN | 1746 | /* There was no packet after all |
1746 | ) { | 1747 | * (poll() returning POLLIN for a fd |
1747 | //TODO: always do this? | 1748 | * is not a ironclad guarantee that data is there) |
1748 | interval = poll_interval(RETRY_INTERVAL); | 1749 | */ |
1749 | goto set_next_and_ret; | 1750 | return; |
1750 | } | 1751 | /* |
1751 | xfunc_die(); | 1752 | * If you need a different handling for a specific |
1753 | * errno, always explain it in comment. | ||
1754 | */ | ||
1755 | bb_perror_msg_and_die("recv(%s) error", p->p_dotted); | ||
1752 | } | 1756 | } |
1753 | 1757 | ||
1754 | if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { | 1758 | if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { |
@@ -1774,10 +1778,15 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1774 | || msg.m_stratum == 0 | 1778 | || msg.m_stratum == 0 |
1775 | || msg.m_stratum > NTP_MAXSTRATUM | 1779 | || msg.m_stratum > NTP_MAXSTRATUM |
1776 | ) { | 1780 | ) { |
1777 | // TODO: stratum 0 responses may have commands in 32-bit m_refid field: | ||
1778 | // "DENY", "RSTR" - peer does not like us at all | ||
1779 | // "RATE" - peer is overloaded, reduce polling freq | ||
1780 | bb_error_msg("reply from %s: peer is unsynced", p->p_dotted); | 1781 | bb_error_msg("reply from %s: peer is unsynced", p->p_dotted); |
1782 | /* | ||
1783 | * Stratum 0 responses may have commands in 32-bit m_refid field: | ||
1784 | * "DENY", "RSTR" - peer does not like us at all, | ||
1785 | * "RATE" - peer is overloaded, reduce polling freq. | ||
1786 | * If poll interval is small, increase it. | ||
1787 | */ | ||
1788 | if (G.poll_exp < BIGPOLL) | ||
1789 | goto increase_interval; | ||
1781 | goto pick_normal_interval; | 1790 | goto pick_normal_interval; |
1782 | } | 1791 | } |
1783 | 1792 | ||
@@ -1866,11 +1875,19 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1866 | /* Muck with statictics and update the clock */ | 1875 | /* Muck with statictics and update the clock */ |
1867 | filter_datapoints(p); | 1876 | filter_datapoints(p); |
1868 | q = select_and_cluster(); | 1877 | q = select_and_cluster(); |
1869 | rc = -1; | 1878 | rc = 0; |
1870 | if (q) { | 1879 | if (q) { |
1871 | rc = 0; | ||
1872 | if (!(option_mask32 & OPT_w)) { | 1880 | if (!(option_mask32 & OPT_w)) { |
1873 | rc = update_local_clock(q); | 1881 | rc = update_local_clock(q); |
1882 | #if 0 | ||
1883 | //Disabled this because there is a case where largish offsets | ||
1884 | //are unavoidable: if network round-trip delay is, say, ~0.6s, | ||
1885 | //error in offset estimation would be ~delay/2 ~= 0.3s. | ||
1886 | //Thus, offsets will be usually in -0.3...0.3s range. | ||
1887 | //In this case, this code would keep poll interval small, | ||
1888 | //but it won't be helping. | ||
1889 | //BIGOFF check below deals with a case of seeing multi-second offsets. | ||
1890 | |||
1874 | /* If drift is dangerously large, immediately | 1891 | /* If drift is dangerously large, immediately |
1875 | * drop poll interval one step down. | 1892 | * drop poll interval one step down. |
1876 | */ | 1893 | */ |
@@ -1879,9 +1896,15 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1879 | adjust_poll(-POLLADJ_LIMIT * 3); | 1896 | adjust_poll(-POLLADJ_LIMIT * 3); |
1880 | rc = 0; | 1897 | rc = 0; |
1881 | } | 1898 | } |
1899 | #endif | ||
1882 | } | 1900 | } |
1901 | } else { | ||
1902 | /* No peer selected. | ||
1903 | * If poll interval is small, increase it. | ||
1904 | */ | ||
1905 | if (G.poll_exp < BIGPOLL) | ||
1906 | goto increase_interval; | ||
1883 | } | 1907 | } |
1884 | /* else: no peer selected, rc = -1: we want to poll more often */ | ||
1885 | 1908 | ||
1886 | if (rc != 0) { | 1909 | if (rc != 0) { |
1887 | /* Adjust the poll interval by comparing the current offset | 1910 | /* Adjust the poll interval by comparing the current offset |
@@ -1893,6 +1916,7 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1893 | if (rc > 0 && G.offset_to_jitter_ratio <= POLLADJ_GATE) { | 1916 | if (rc > 0 && G.offset_to_jitter_ratio <= POLLADJ_GATE) { |
1894 | /* was += G.poll_exp but it is a bit | 1917 | /* was += G.poll_exp but it is a bit |
1895 | * too optimistic for my taste at high poll_exp's */ | 1918 | * too optimistic for my taste at high poll_exp's */ |
1919 | increase_interval: | ||
1896 | adjust_poll(MINPOLL); | 1920 | adjust_poll(MINPOLL); |
1897 | } else { | 1921 | } else { |
1898 | adjust_poll(-G.poll_exp * 2); | 1922 | adjust_poll(-G.poll_exp * 2); |
@@ -1917,7 +1941,6 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1917 | interval = BIGOFF_INTERVAL; | 1941 | interval = BIGOFF_INTERVAL; |
1918 | } | 1942 | } |
1919 | 1943 | ||
1920 | set_next_and_ret: | ||
1921 | set_next(p, interval); | 1944 | set_next(p, interval); |
1922 | } | 1945 | } |
1923 | 1946 | ||
@@ -2252,6 +2275,9 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) | |||
2252 | /* Timed out waiting for reply */ | 2275 | /* Timed out waiting for reply */ |
2253 | close(p->p_fd); | 2276 | close(p->p_fd); |
2254 | p->p_fd = -1; | 2277 | p->p_fd = -1; |
2278 | /* If poll interval is small, increase it */ | ||
2279 | if (G.poll_exp < BIGPOLL) | ||
2280 | adjust_poll(MINPOLL); | ||
2255 | timeout = poll_interval(NOREPLY_INTERVAL); | 2281 | timeout = poll_interval(NOREPLY_INTERVAL); |
2256 | bb_error_msg("timed out waiting for %s, reach 0x%02x, next query in %us", | 2282 | bb_error_msg("timed out waiting for %s, reach 0x%02x, next query in %us", |
2257 | p->p_dotted, p->reachable_bits, timeout); | 2283 | p->p_dotted, p->reachable_bits, timeout); |