ntpd: fix jitter calculations and status propagation
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
f25252c69e
commit
1ee5afdce2
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user