ntpd: fix jitter calculations and status propagation

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2010-01-02 15:57:07 +01:00
parent f25252c69e
commit 1ee5afdce2

View File

@ -166,7 +166,7 @@ typedef struct {
int p_fd; int p_fd;
int datapoint_idx; int datapoint_idx;
uint32_t lastpkt_refid; uint32_t lastpkt_refid;
uint8_t lastpkt_leap; uint8_t lastpkt_status;
uint8_t lastpkt_stratum; uint8_t lastpkt_stratum;
uint8_t p_reachable_bits; uint8_t p_reachable_bits;
double p_xmttime; 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 * in stratum 2+ packets, it's IPv4 address or 4 first bytes of MD5 hash of IPv6
*/ */
uint32_t refid; uint32_t refid;
uint8_t leap; uint8_t ntp_status;
/* precision is defined as the larger of the resolution and time to /* precision is defined as the larger of the resolution and time to
* read the clock, in log2 units. For instance, the precision of a * 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 * 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))) #define G_precision_sec (1.0 / (1 << (- G_precision_exp)))
uint8_t stratum; uint8_t stratum;
/* Bool. After set to 1, never goes back to 0: */ /* 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 adjtimex_was_done;
uint8_t discipline_state; // doc calls it c.state uint8_t discipline_state; // doc calls it c.state
@ -415,12 +413,13 @@ filter_datapoints(peer_t *p, double t)
*/ */
wavg = 0; wavg = 0;
w = 0.5; w = 0.5;
// n-1 /* n-1
// --- dispersion(i) * --- dispersion(i)
// filter_dispersion = \ ------------- * filter_dispersion = \ -------------
// / (i+1) * / (i+1)
// --- 2 * --- 2
// i=0 * i=0
*/
got_newest = 0; got_newest = 0;
sum = 0; sum = 0;
for (i = 0; i < NUM_DATAPOINTS; i++) { for (i = 0; i < NUM_DATAPOINTS; i++) {
@ -474,21 +473,22 @@ filter_datapoints(peer_t *p, double t)
} }
p->filter_offset = wavg; p->filter_offset = wavg;
// +----- -----+ ^ 1/2 /* +----- -----+ ^ 1/2
// | n-1 | * | n-1 |
// | --- | * | --- |
// 1 | \ 2 | * | 1 \ 2 |
// filter_jitter = --- * | / (avg-offset_j) | * filter_jitter = | --- * / (avg-offset_j) |
// n | --- | * | n --- |
// | j=0 | * | j=0 |
// +----- -----+ * +----- -----+
// where n is the number of valid datapoints in the filter (n > 1); * where n is the number of valid datapoints in the filter (n > 1);
// if filter_jitter < precision then filter_jitter = precision * if filter_jitter < precision then filter_jitter = precision
*/
sum = 0; sum = 0;
for (i = 0; i < NUM_DATAPOINTS; i++) { for (i = 0; i < NUM_DATAPOINTS; i++) {
sum += SQUARE(wavg - p->filter_datapoint[i].d_offset); 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; p->filter_jitter = sum > G_precision_sec ? sum : G_precision_sec;
VERB3 bb_error_msg("filter offset:%f(corr:%e) disp:%f jitter:%f", VERB3 bb_error_msg("filter offset:%f(corr:%e) disp:%f jitter:%f",
@ -570,22 +570,23 @@ do_sendto(int fd,
static int static int
send_query_to_peer(peer_t *p) send_query_to_peer(peer_t *p)
{ {
// Why do we need to bind()? /* Why do we need to bind()?
// See what happens when we don't bind: * See what happens when we don't bind:
// *
// socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 3 * socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 3
// setsockopt(3, SOL_IP, IP_TOS, [16], 4) = 0 * setsockopt(3, SOL_IP, IP_TOS, [16], 4) = 0
// gettimeofday({1259071266, 327885}, NULL) = 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 * 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. * ^^^ we sent it from some source port picked by kernel.
// time(NULL) = 1259071266 * time(NULL) = 1259071266
// write(2, "ntpd: entering poll 15 secs\n", 28) = 28 * write(2, "ntpd: entering poll 15 secs\n", 28) = 28
// poll([{fd=3, events=POLLIN}], 1, 15000) = 1 ([{fd=3, revents=POLLIN}]) * poll([{fd=3, events=POLLIN}], 1, 15000) = 1 ([{fd=3, revents=POLLIN}])
// recv(3, "yyy", 68, MSG_DONTWAIT) = 48 * recv(3, "yyy", 68, MSG_DONTWAIT) = 48
// ^^^ this recv will receive packets to any local port! * ^^^ this recv will receive packets to any local port!
// *
// Uncomment this and use strace to see it in action: * 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); } */
#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) { if (p->p_fd == -1) {
int fd, family; 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)); 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); 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); VERB3 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted);
return 0; return 0;
} }
//TODO: we never accept such packets anyway, right? #if 0 /* we filter out such packets earlier */
if ((p->lastpkt_leap & LI_ALARM) == LI_ALARM if ((p->lastpkt_status & LI_ALARM) == LI_ALARM
|| p->lastpkt_stratum >= MAXSTRAT || p->lastpkt_stratum >= MAXSTRAT
) { ) {
VERB3 bb_error_msg("peer %s unfit for selection: bad status/stratum", p->p_dotted); VERB3 bb_error_msg("peer %s unfit for selection: bad status/stratum", p->p_dotted);
return 0; return 0;
} }
#endif
/* rd is root_distance(p, t) */ /* rd is root_distance(p, t) */
if (rd > MAXDIST + FREQ_TOLERANCE * (1 << G.poll_exp)) { 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); 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; selection_jitter_sq = 0;
for (j = 0; j < num_survivors; j++) { for (j = 0; j < num_survivors; j++) {
peer_t *q = survivor[j].p; peer_t *q = survivor[j].p;
//TODO: where is 1/(n-1) * ... multiplier?
selection_jitter_sq += SQUARE(p->filter_offset - q->filter_offset); selection_jitter_sq += SQUARE(p->filter_offset - q->filter_offset);
} }
if (i == 0 || selection_jitter_sq > max_selection_jitter) { 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", VERB5 bb_error_msg("survivor %d selection_jitter^2:%f",
i, selection_jitter_sq); 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", VERB4 bb_error_msg("max_selection_jitter (at %d):%f min_jitter:%f",
max_idx, max_selection_jitter, min_jitter); 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 offset = p->filter_offset;
double recv_time = p->lastpkt_recv_time; double recv_time = p->lastpkt_recv_time;
double abs_offset; double abs_offset;
#if !USING_KERNEL_PLL_LOOP
double freq_drift; double freq_drift;
#endif
double since_last_update; double since_last_update;
double etemp, dtemp; double etemp, dtemp;
@ -1017,7 +1018,9 @@ update_local_clock(peer_t *p, double t)
* and frequency errors. * and frequency errors.
*/ */
since_last_update = recv_time - G.reftime; since_last_update = recv_time - G.reftime;
#if !USING_KERNEL_PLL_LOOP
freq_drift = 0; freq_drift = 0;
#endif
if (G.discipline_state == STATE_FREQ) { if (G.discipline_state == STATE_FREQ) {
/* Ignore updates until the stepout threshold */ /* Ignore updates until the stepout threshold */
if (since_last_update < WATCH_THRESHOLD) { if (since_last_update < WATCH_THRESHOLD) {
@ -1025,7 +1028,9 @@ update_local_clock(peer_t *p, double t)
WATCH_THRESHOLD - since_last_update); WATCH_THRESHOLD - since_last_update);
return 0; /* "leave poll interval as is" */ return 0; /* "leave poll interval as is" */
} }
#if !USING_KERNEL_PLL_LOOP
freq_drift = (offset - G.last_update_offset) / since_last_update; freq_drift = (offset - G.last_update_offset) / since_last_update;
#endif
} }
/* There are two main regimes: when the /* There are two main regimes: when the
@ -1145,6 +1150,7 @@ update_local_clock(peer_t *p, double t)
break; break;
default: default:
#if !USING_KERNEL_PLL_LOOP
/* Compute freq_drift due to PLL and FLL contributions. /* Compute freq_drift due to PLL and FLL contributions.
* *
* The FLL and PLL frequency gain constants * 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)); etemp = MIND(since_last_update, (1 << G.poll_exp));
dtemp = (4 * PLL) << G.poll_exp; dtemp = (4 * PLL) << G.poll_exp;
freq_drift += offset * etemp / SQUARE(dtemp); freq_drift += offset * etemp / SQUARE(dtemp);
#endif
set_new_values(STATE_SYNC, offset, recv_time); set_new_values(STATE_SYNC, offset, recv_time);
break; break;
} }
@ -1174,7 +1181,7 @@ update_local_clock(peer_t *p, double t)
} }
G.reftime = t; G.reftime = t;
G.leap = p->lastpkt_leap; G.ntp_status = p->lastpkt_status;
G.refid = p->lastpkt_refid; G.refid = p->lastpkt_refid;
G.rootdelay = p->lastpkt_rootdelay + p->lastpkt_delay; G.rootdelay = p->lastpkt_rootdelay + p->lastpkt_delay;
dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(s.jitter)); 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 */ /* + (G.last_update_offset < 0 ? -0.5 : 0.5) - too small to bother */
+ old_tmx_offset; /* almost always 0 */ + old_tmx_offset; /* almost always 0 */
tmx.status = STA_PLL; tmx.status = STA_PLL;
//if (sys_leap == LEAP_ADDSECOND) if (G.ntp_status & LI_PLUSSEC)
// tmx.status |= STA_INS; tmx.status |= STA_INS;
//else if (sys_leap == LEAP_DELSECOND) if (G.ntp_status & LI_MINUSSEC)
// tmx.status |= STA_DEL; tmx.status |= STA_DEL;
tmx.constant = G.poll_exp - 4; tmx.constant = G.poll_exp - 4;
//tmx.esterror = (u_int32)(clock_jitter * 1e6); //tmx.esterror = (u_int32)(clock_jitter * 1e6);
//tmx.maxerror = (u_int32)((sys_rootdelay / 2 + sys_rootdisp) * 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; 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 */ // /* Verify valid root distance */
// if (msg.m_rootdelay / 2 + msg.m_rootdisp >= MAXDISP || p->lastpkt_reftime > msg.m_xmt) // if (msg.m_rootdelay / 2 + msg.m_rootdisp >= MAXDISP || p->lastpkt_reftime > msg.m_xmt)
// return; /* invalid header values */ // 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_rootdelay = sfp_to_d(msg.m_rootdelay);
p->lastpkt_rootdisp = sfp_to_d(msg.m_rootdisp); p->lastpkt_rootdisp = sfp_to_d(msg.m_rootdisp);
p->lastpkt_refid = msg.m_refid; p->lastpkt_refid = msg.m_refid;
@ -1557,7 +1558,7 @@ recv_and_process_client_pkt(void /*int fd*/)
/* Build a reply packet */ /* Build a reply packet */
memset(&msg, 0, sizeof(msg)); 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 & VERSION_MASK);
msg.m_status |= ((query_status & MODE_MASK) == MODE_CLIENT) ? msg.m_status |= ((query_status & MODE_MASK) == MODE_CLIENT) ?
MODE_SERVER : MODE_SYM_PAS; 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; timeout = nextaction - cur_time;
if (timeout < 1) if (timeout < 1)
timeout = 1; timeout = 1;