diff options
author | Miroslav Lichvar | 2014-10-02 17:18:43 +0200 |
---|---|---|
committer | Denys Vlasenko | 2014-10-02 17:24:34 +0200 |
commit | b434ce70696879aad066fff67253e44e5f5b238e (patch) | |
tree | b29fa99983269a0ccd448d3ba8b6eba8b4dace93 | |
parent | cf76b5ce12a685b0c0a8ea53fa95cb0f0922a4f1 (diff) | |
download | busybox-b434ce70696879aad066fff67253e44e5f5b238e.zip busybox-b434ce70696879aad066fff67253e44e5f5b238e.tar.gz |
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 b2b2791..838a367 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -136,17 +136,17 @@ #define BURSTPOLL 0 /* initial poll */ #define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */ /* - * If offset > discipline_jitter * POLLADJ_GATE, and poll interval is >= 2^BIGPOLL, - * then it is decreased _at once_. (If < 2^BIGPOLL, it will be decreased _eventually_). + * If offset > discipline_jitter * POLLADJ_GATE, and poll interval is > 2^BIGPOLL, + * then it is decreased _at once_. (If <= 2^BIGPOLL, it will be decreased _eventually_). */ -#define BIGPOLL 10 /* 2^10 sec ~= 17 min */ +#define BIGPOLL 9 /* 2^9 sec ~= 8.5 min */ #define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */ /* * Actively lower poll when we see such big offsets. * With STEP_THRESHOLD = 0.125, it means we try to sync more aggressively * if offset increases over ~0.04 sec */ -#define POLLDOWN_OFFSET (STEP_THRESHOLD / 3) +//#define POLLDOWN_OFFSET (STEP_THRESHOLD / 3) #define MINDISP 0.01 /* minimum dispersion (sec) */ #define MAXDISP 16 /* maximum dispersion (sec) */ #define MAXSTRAT 16 /* maximum stratum (infinity metric) */ @@ -984,8 +984,8 @@ static void clamp_pollexp_and_set_MAXSTRAT(void) { if (G.poll_exp < MINPOLL) G.poll_exp = MINPOLL; - if (G.poll_exp >= BIGPOLL) - G.poll_exp = BIGPOLL - 1; + if (G.poll_exp > BIGPOLL) + G.poll_exp = BIGPOLL; G.polladj_count = 0; G.stratum = MAXSTRAT; } @@ -1682,7 +1682,7 @@ poll_interval(int upper_bound) VERB4 bb_error_msg("chose poll interval:%u (poll_exp:%d)", interval, G.poll_exp); return interval; } -static NOINLINE void +static void adjust_poll(int count) { G.polladj_count += count; @@ -1693,7 +1693,7 @@ adjust_poll(int count) VERB4 bb_error_msg("polladj: discipline_jitter:%f ++poll_exp=%d", G.discipline_jitter, G.poll_exp); } - } else if (G.polladj_count < -POLLADJ_LIMIT || (count < 0 && G.poll_exp >= BIGPOLL)) { + } else if (G.polladj_count < -POLLADJ_LIMIT || (count < 0 && G.poll_exp > BIGPOLL)) { G.polladj_count = 0; if (G.poll_exp > MINPOLL) { llist_t *item; @@ -1736,19 +1736,23 @@ recv_and_process_peer_pkt(peer_t *p) * ntp servers reply from their *other IP*. * TODO: maybe we should check at least what we can: from.port == 123? */ + recv_again: size = recv(p->p_fd, &msg, sizeof(msg), MSG_DONTWAIT); - if (size == -1) { - bb_perror_msg("recv(%s) error", p->p_dotted); - if (errno == EHOSTUNREACH || errno == EHOSTDOWN - || errno == ENETUNREACH || errno == ENETDOWN - || errno == ECONNREFUSED || errno == EADDRNOTAVAIL - || errno == EAGAIN - ) { -//TODO: always do this? - interval = poll_interval(RETRY_INTERVAL); - goto set_next_and_ret; - } - xfunc_die(); + if (size < 0) { + if (errno == EINTR) + /* Signal caught */ + goto recv_again; + if (errno == EAGAIN) + /* There was no packet after all + * (poll() returning POLLIN for a fd + * is not a ironclad guarantee that data is there) + */ + return; + /* + * If you need a different handling for a specific + * errno, always explain it in comment. + */ + bb_perror_msg_and_die("recv(%s) error", p->p_dotted); } if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { @@ -1774,10 +1778,15 @@ recv_and_process_peer_pkt(peer_t *p) || msg.m_stratum == 0 || msg.m_stratum > NTP_MAXSTRATUM ) { -// TODO: stratum 0 responses may have commands in 32-bit m_refid field: -// "DENY", "RSTR" - peer does not like us at all -// "RATE" - peer is overloaded, reduce polling freq bb_error_msg("reply from %s: peer is unsynced", p->p_dotted); + /* + * Stratum 0 responses may have commands in 32-bit m_refid field: + * "DENY", "RSTR" - peer does not like us at all, + * "RATE" - peer is overloaded, reduce polling freq. + * If poll interval is small, increase it. + */ + if (G.poll_exp < BIGPOLL) + goto increase_interval; goto pick_normal_interval; } @@ -1866,11 +1875,19 @@ recv_and_process_peer_pkt(peer_t *p) /* Muck with statictics and update the clock */ filter_datapoints(p); q = select_and_cluster(); - rc = -1; + rc = 0; if (q) { - rc = 0; if (!(option_mask32 & OPT_w)) { rc = update_local_clock(q); +#if 0 +//Disabled this because there is a case where largish offsets +//are unavoidable: if network round-trip delay is, say, ~0.6s, +//error in offset estimation would be ~delay/2 ~= 0.3s. +//Thus, offsets will be usually in -0.3...0.3s range. +//In this case, this code would keep poll interval small, +//but it won't be helping. +//BIGOFF check below deals with a case of seeing multi-second offsets. + /* If drift is dangerously large, immediately * drop poll interval one step down. */ @@ -1879,9 +1896,15 @@ recv_and_process_peer_pkt(peer_t *p) adjust_poll(-POLLADJ_LIMIT * 3); rc = 0; } +#endif } + } else { + /* No peer selected. + * If poll interval is small, increase it. + */ + if (G.poll_exp < BIGPOLL) + goto increase_interval; } - /* else: no peer selected, rc = -1: we want to poll more often */ if (rc != 0) { /* Adjust the poll interval by comparing the current offset @@ -1893,6 +1916,7 @@ recv_and_process_peer_pkt(peer_t *p) if (rc > 0 && G.offset_to_jitter_ratio <= POLLADJ_GATE) { /* was += G.poll_exp but it is a bit * too optimistic for my taste at high poll_exp's */ + increase_interval: adjust_poll(MINPOLL); } else { adjust_poll(-G.poll_exp * 2); @@ -1917,7 +1941,6 @@ recv_and_process_peer_pkt(peer_t *p) interval = BIGOFF_INTERVAL; } - set_next_and_ret: set_next(p, interval); } @@ -2252,6 +2275,9 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) /* Timed out waiting for reply */ close(p->p_fd); p->p_fd = -1; + /* If poll interval is small, increase it */ + if (G.poll_exp < BIGPOLL) + adjust_poll(MINPOLL); timeout = poll_interval(NOREPLY_INTERVAL); bb_error_msg("timed out waiting for %s, reach 0x%02x, next query in %us", p->p_dotted, p->reachable_bits, timeout); |