diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-01-17 02:51:33 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-01-17 02:51:33 +0100 |
commit | 9b20adca4b2b59c791b4b5579857e4f028a969ed (patch) | |
tree | b77738b270eb05f845213299a517929dc93b6b9f /networking/ntpd.c | |
parent | 5b9a910749176cabcd6e822ca46af66a9947d032 (diff) | |
download | busybox-w32-9b20adca4b2b59c791b4b5579857e4f028a969ed.tar.gz busybox-w32-9b20adca4b2b59c791b4b5579857e4f028a969ed.tar.bz2 busybox-w32-9b20adca4b2b59c791b4b5579857e4f028a969ed.zip |
ntpd: add anti-clock-hopping code
function old new delta
select_and_cluster 837 950 +113
update_local_clock 759 767 +8
root_distance 61 - -61
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/ntpd.c')
-rw-r--r-- | networking/ntpd.c | 78 |
1 files changed, 61 insertions, 17 deletions
diff --git a/networking/ntpd.c b/networking/ntpd.c index b2cd0a3c0..aca79c95a 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c | |||
@@ -306,13 +306,15 @@ struct globals { | |||
306 | uint8_t poll_exp; // s.poll | 306 | uint8_t poll_exp; // s.poll |
307 | int polladj_count; // c.count | 307 | int polladj_count; // c.count |
308 | long kernel_freq_drift; | 308 | long kernel_freq_drift; |
309 | peer_t *last_update_peer; | ||
309 | double last_update_offset; // c.last | 310 | double last_update_offset; // c.last |
310 | double last_update_recv_time; // s.t | 311 | double last_update_recv_time; // s.t |
311 | double discipline_jitter; // c.jitter | 312 | double discipline_jitter; // c.jitter |
312 | //TODO: add s.jitter - grep for it here and see clock_combine() in doc | 313 | //double cluster_offset; // s.offset |
314 | //double cluster_jitter; // s.jitter | ||
313 | #if !USING_KERNEL_PLL_LOOP | 315 | #if !USING_KERNEL_PLL_LOOP |
314 | double discipline_freq_drift; // c.freq | 316 | double discipline_freq_drift; // c.freq |
315 | //TODO: conditionally calculate wander? it's used only for logging | 317 | /* Maybe conditionally calculate wander? it's used only for logging */ |
316 | double discipline_wander; // c.wander | 318 | double discipline_wander; // c.wander |
317 | #endif | 319 | #endif |
318 | }; | 320 | }; |
@@ -821,6 +823,7 @@ typedef struct { | |||
821 | peer_t *p; | 823 | peer_t *p; |
822 | int type; | 824 | int type; |
823 | double edge; | 825 | double edge; |
826 | double opt_rd; /* optimization */ | ||
824 | } point_t; | 827 | } point_t; |
825 | static int | 828 | static int |
826 | compare_point_edge(const void *aa, const void *bb) | 829 | compare_point_edge(const void *aa, const void *bb) |
@@ -876,6 +879,7 @@ fit(peer_t *p, double rd) | |||
876 | static peer_t* | 879 | static peer_t* |
877 | select_and_cluster(void) | 880 | select_and_cluster(void) |
878 | { | 881 | { |
882 | peer_t *p; | ||
879 | llist_t *item; | 883 | llist_t *item; |
880 | int i, j; | 884 | int i, j; |
881 | int size = 3 * G.peer_cnt; | 885 | int size = 3 * G.peer_cnt; |
@@ -893,10 +897,11 @@ select_and_cluster(void) | |||
893 | num_points = 0; | 897 | num_points = 0; |
894 | item = G.ntp_peers; | 898 | item = G.ntp_peers; |
895 | if (G.initial_poll_complete) while (item != NULL) { | 899 | if (G.initial_poll_complete) while (item != NULL) { |
896 | peer_t *p = (peer_t *) item->data; | 900 | double rd, offset; |
897 | double rd = root_distance(p); | ||
898 | double offset = p->filter_offset; | ||
899 | 901 | ||
902 | p = (peer_t *) item->data; | ||
903 | rd = root_distance(p); | ||
904 | offset = p->filter_offset; | ||
900 | if (!fit(p, rd)) { | 905 | if (!fit(p, rd)) { |
901 | item = item->link; | 906 | item = item->link; |
902 | continue; | 907 | continue; |
@@ -911,14 +916,17 @@ select_and_cluster(void) | |||
911 | point[num_points].p = p; | 916 | point[num_points].p = p; |
912 | point[num_points].type = -1; | 917 | point[num_points].type = -1; |
913 | point[num_points].edge = offset - rd; | 918 | point[num_points].edge = offset - rd; |
919 | point[num_points].opt_rd = rd; | ||
914 | num_points++; | 920 | num_points++; |
915 | point[num_points].p = p; | 921 | point[num_points].p = p; |
916 | point[num_points].type = 0; | 922 | point[num_points].type = 0; |
917 | point[num_points].edge = offset; | 923 | point[num_points].edge = offset; |
924 | point[num_points].opt_rd = rd; | ||
918 | num_points++; | 925 | num_points++; |
919 | point[num_points].p = p; | 926 | point[num_points].p = p; |
920 | point[num_points].type = 1; | 927 | point[num_points].type = 1; |
921 | point[num_points].edge = offset + rd; | 928 | point[num_points].edge = offset + rd; |
929 | point[num_points].opt_rd = rd; | ||
922 | num_points++; | 930 | num_points++; |
923 | item = item->link; | 931 | item = item->link; |
924 | } | 932 | } |
@@ -999,14 +1007,12 @@ select_and_cluster(void) | |||
999 | */ | 1007 | */ |
1000 | num_survivors = 0; | 1008 | num_survivors = 0; |
1001 | for (i = 0; i < num_points; i++) { | 1009 | for (i = 0; i < num_points; i++) { |
1002 | peer_t *p; | ||
1003 | |||
1004 | if (point[i].edge < low || point[i].edge > high) | 1010 | if (point[i].edge < low || point[i].edge > high) |
1005 | continue; | 1011 | continue; |
1006 | p = point[i].p; | 1012 | p = point[i].p; |
1007 | survivor[num_survivors].p = p; | 1013 | survivor[num_survivors].p = p; |
1008 | //TODO: save root_distance in point_t and reuse here? | 1014 | /* x.opt_rd == root_distance(p); */ |
1009 | survivor[num_survivors].metric = MAXDIST * p->lastpkt_stratum + root_distance(p); | 1015 | survivor[num_survivors].metric = MAXDIST * p->lastpkt_stratum + point[i].opt_rd; |
1010 | VERB4 bb_error_msg("survivor[%d] metric:%f peer:%s", | 1016 | VERB4 bb_error_msg("survivor[%d] metric:%f peer:%s", |
1011 | num_survivors, survivor[num_survivors].metric, p->p_dotted); | 1017 | num_survivors, survivor[num_survivors].metric, p->p_dotted); |
1012 | num_survivors++; | 1018 | num_survivors++; |
@@ -1050,8 +1056,8 @@ select_and_cluster(void) | |||
1050 | */ | 1056 | */ |
1051 | for (i = 0; i < num_survivors; i++) { | 1057 | for (i = 0; i < num_survivors; i++) { |
1052 | double selection_jitter_sq; | 1058 | double selection_jitter_sq; |
1053 | peer_t *p = survivor[i].p; | ||
1054 | 1059 | ||
1060 | p = survivor[i].p; | ||
1055 | if (i == 0 || p->filter_jitter < min_jitter) | 1061 | if (i == 0 || p->filter_jitter < min_jitter) |
1056 | min_jitter = p->filter_jitter; | 1062 | min_jitter = p->filter_jitter; |
1057 | 1063 | ||
@@ -1093,18 +1099,54 @@ select_and_cluster(void) | |||
1093 | } | 1099 | } |
1094 | } | 1100 | } |
1095 | 1101 | ||
1102 | if (0) { | ||
1103 | /* Combine the offsets of the clustering algorithm survivors | ||
1104 | * using a weighted average with weight determined by the root | ||
1105 | * distance. Compute the selection jitter as the weighted RMS | ||
1106 | * difference between the first survivor and the remaining | ||
1107 | * survivors. In some cases the inherent clock jitter can be | ||
1108 | * reduced by not using this algorithm, especially when frequent | ||
1109 | * clockhopping is involved. bbox: thus we don't do it. | ||
1110 | */ | ||
1111 | double x, y, z, w; | ||
1112 | y = z = w = 0; | ||
1113 | for (i = 0; i < num_survivors; i++) { | ||
1114 | p = survivor[i].p; | ||
1115 | x = root_distance(p); | ||
1116 | y += 1 / x; | ||
1117 | z += p->filter_offset / x; | ||
1118 | w += SQUARE(p->filter_offset - survivor[0].p->filter_offset) / x; | ||
1119 | } | ||
1120 | //G.cluster_offset = z / y; | ||
1121 | //G.cluster_jitter = SQRT(w / y); | ||
1122 | } | ||
1123 | |||
1096 | /* Pick the best clock. If the old system peer is on the list | 1124 | /* Pick the best clock. If the old system peer is on the list |
1097 | * and at the same stratum as the first survivor on the list, | 1125 | * and at the same stratum as the first survivor on the list, |
1098 | * then don't do a clock hop. Otherwise, select the first | 1126 | * then don't do a clock hop. Otherwise, select the first |
1099 | * survivor on the list as the new system peer. | 1127 | * survivor on the list as the new system peer. |
1100 | */ | 1128 | */ |
1101 | //TODO - see clock_combine() | 1129 | p = survivor[0].p; |
1130 | if (G.last_update_peer | ||
1131 | && G.last_update_peer->lastpkt_stratum <= p->lastpkt_stratum | ||
1132 | ) { | ||
1133 | /* Starting from 1 is ok here */ | ||
1134 | for (i = 1; i < num_survivors; i++) { | ||
1135 | if (G.last_update_peer == survivor[i].p) { | ||
1136 | VERB4 bb_error_msg("keeping old synced peer"); | ||
1137 | p = G.last_update_peer; | ||
1138 | goto keep_old; | ||
1139 | } | ||
1140 | } | ||
1141 | } | ||
1142 | G.last_update_peer = p; | ||
1143 | keep_old: | ||
1102 | VERB3 bb_error_msg("selected peer %s filter_offset:%f age:%f", | 1144 | VERB3 bb_error_msg("selected peer %s filter_offset:%f age:%f", |
1103 | survivor[0].p->p_dotted, | 1145 | p->p_dotted, |
1104 | survivor[0].p->filter_offset, | 1146 | p->filter_offset, |
1105 | G.cur_time - survivor[0].p->lastpkt_recv_time | 1147 | G.cur_time - p->lastpkt_recv_time |
1106 | ); | 1148 | ); |
1107 | return survivor[0].p; | 1149 | return p; |
1108 | } | 1150 | } |
1109 | 1151 | ||
1110 | 1152 | ||
@@ -1131,6 +1173,7 @@ update_local_clock(peer_t *p) | |||
1131 | int rc; | 1173 | int rc; |
1132 | long old_tmx_offset; | 1174 | long old_tmx_offset; |
1133 | struct timex tmx; | 1175 | struct timex tmx; |
1176 | /* Note: can use G.cluster_offset instead: */ | ||
1134 | double offset = p->filter_offset; | 1177 | double offset = p->filter_offset; |
1135 | double recv_time = p->lastpkt_recv_time; | 1178 | double recv_time = p->lastpkt_recv_time; |
1136 | double abs_offset; | 1179 | double abs_offset; |
@@ -1343,7 +1386,7 @@ update_local_clock(peer_t *p) | |||
1343 | G.ntp_status = p->lastpkt_status; | 1386 | G.ntp_status = p->lastpkt_status; |
1344 | G.refid = p->lastpkt_refid; | 1387 | G.refid = p->lastpkt_refid; |
1345 | G.rootdelay = p->lastpkt_rootdelay + p->lastpkt_delay; | 1388 | G.rootdelay = p->lastpkt_rootdelay + p->lastpkt_delay; |
1346 | dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(s.jitter)); | 1389 | dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(G.cluster_jitter)); |
1347 | dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time) + abs_offset, MINDISP); | 1390 | dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time) + abs_offset, MINDISP); |
1348 | G.rootdisp = p->lastpkt_rootdisp + dtemp; | 1391 | G.rootdisp = p->lastpkt_rootdisp + dtemp; |
1349 | VERB3 bb_error_msg("updating leap/refid/reftime/rootdisp from peer %s", p->p_dotted); | 1392 | VERB3 bb_error_msg("updating leap/refid/reftime/rootdisp from peer %s", p->p_dotted); |
@@ -1433,7 +1476,8 @@ update_local_clock(peer_t *p) | |||
1433 | } | 1476 | } |
1434 | #endif | 1477 | #endif |
1435 | G.kernel_freq_drift = tmx.freq / 65536; | 1478 | G.kernel_freq_drift = tmx.freq / 65536; |
1436 | VERB2 bb_error_msg("update offset:%f, clock drift:%ld ppm", G.last_update_offset, G.kernel_freq_drift); | 1479 | VERB2 bb_error_msg("update peer:%s, offset:%f, clock drift:%ld ppm", |
1480 | p->p_dotted, G.last_update_offset, G.kernel_freq_drift); | ||
1437 | 1481 | ||
1438 | return 1; /* "ok to increase poll interval" */ | 1482 | return 1; /* "ok to increase poll interval" */ |
1439 | } | 1483 | } |