From: Martin Burnicki Date: Fri, 19 Jun 2015 14:06:35 +0000 (+0200) Subject: More support for smeared leap seconds. X-Git-Tag: NTP_4_2_8P3_RC2~6^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=79c061360e84ac9630a145ca0bc4d9ca0a54fb1b;p=thirdparty%2Fntp.git More support for smeared leap seconds. bk: 558421ebHYzZ_IAmTBZ__FJKvkmD_w --- diff --git a/include/ntpd.h b/include/ntpd.h index 12d51115e..c30b80624 100644 --- a/include/ntpd.h +++ b/include/ntpd.h @@ -223,6 +223,7 @@ extern void receive (struct recvbuf *); extern void peer_clear (struct peer *, const char *); extern void process_packet (struct peer *, struct pkt *, u_int); extern void clock_select (void); +extern void set_sys_leap (u_char); extern u_long leapsec; /* seconds to next leap (proximity class) */ extern int leapdif; /* TAI difference step at next leap second*/ @@ -533,6 +534,7 @@ extern u_long current_time; /* seconds since startup */ extern u_long timer_timereset; extern u_long timer_overflows; extern u_long timer_xmtcalls; +extern struct leap_smear_info leap_smear; extern int leap_smear_intv; #ifdef SYS_WINNT HANDLE WaitableTimerHandle; diff --git a/ntpd/ntp_config.c b/ntpd/ntp_config.c index bdc72448a..c760e6a59 100644 --- a/ntpd/ntp_config.c +++ b/ntpd/ntp_config.c @@ -3513,6 +3513,7 @@ config_vars( case T_Leapsmearinterval: leap_smear_intv = curr_var->value.i; + msyslog(LOG_INFO, "config: leap smear interval %i s", leap_smear_intv); break; case T_Pidfile: diff --git a/ntpd/ntp_control.c b/ntpd/ntp_control.c index aa9f78cb0..72a365792 100644 --- a/ntpd/ntp_control.c +++ b/ntpd/ntp_control.c @@ -221,7 +221,9 @@ static const struct ctl_proc control_codes[] = { #define CS_TIMER_XMTS 87 #define CS_FUZZ 88 #define CS_WANDER_THRESH 89 -#define CS_MAX_NOAUTOKEY CS_WANDER_THRESH +#define CS_LEAPSMEARINTV 90 +#define CS_LEAPSMEAROFFS 91 +#define CS_MAX_NOAUTOKEY CS_LEAPSMEAROFFS #ifdef AUTOKEY #define CS_FLAGS (1 + CS_MAX_NOAUTOKEY) #define CS_HOST (2 + CS_MAX_NOAUTOKEY) @@ -417,6 +419,8 @@ static const struct ctl_var sys_var[] = { { CS_TIMER_XMTS, RO, "timer_xmts" }, /* 87 */ { CS_FUZZ, RO, "fuzz" }, /* 88 */ { CS_WANDER_THRESH, RO, "clk_wander_threshold" }, /* 89 */ + { CS_LEAPSMEARINTV, RO, "leapsmearinterval" }, /* 90 */ + { CS_LEAPSMEAROFFS, RO, "leapsmearoffset" }, /* 91 */ #ifdef AUTOKEY { CS_FLAGS, RO, "flags" }, /* 1 + CS_MAX_NOAUTOKEY */ { CS_HOST, RO, "host" }, /* 2 + CS_MAX_NOAUTOKEY */ @@ -459,6 +463,8 @@ static const u_char def_sys_var[] = { CS_TAI, CS_LEAPTAB, CS_LEAPEND, + CS_LEAPSMEARINTV, + CS_LEAPSMEAROFFS, #ifdef AUTOKEY CS_HOST, CS_IDENT, @@ -1972,6 +1978,17 @@ ctl_putsys( break; } + case CS_LEAPSMEARINTV: + if (leap_smear_intv > 0) + ctl_putuint(sys_var[CS_LEAPSMEARINTV].text, leap_smear_intv); + break; + + case CS_LEAPSMEAROFFS: + if (leap_smear_intv > 0) + ctl_putdbl(sys_var[CS_LEAPSMEAROFFS].text, + leap_smear.doffset * 1e3); + break; + case CS_RATE: ctl_putuint(sys_var[CS_RATE].text, ntp_minpoll); break; diff --git a/ntpd/ntp_leapsec.h b/ntpd/ntp_leapsec.h index 2f8a5d345..affe627e0 100644 --- a/ntpd/ntp_leapsec.h +++ b/ntpd/ntp_leapsec.h @@ -123,6 +123,7 @@ struct leap_smear_info { int enabled; /* not 0 if smearing is generally enabled */ int in_progress; /* not 0 if smearing is in progress, i.e. the offset has been computed */ int leap_occurred; /* not 0 if the leap second has already occurred, i.e., during the leap second */ + double doffset; /* the current smear offset as double */ l_fp offset; /* the current smear offset */ uint32_t t_offset; /* the current time for which a smear offset has been computed */ long interval; /* smear interval, in [s], should be at least some hours */ diff --git a/ntpd/ntp_proto.c b/ntpd/ntp_proto.c index eadda4859..107573cc9 100644 --- a/ntpd/ntp_proto.c +++ b/ntpd/ntp_proto.c @@ -61,7 +61,8 @@ typedef struct peer_select_tag { * System variables are declared here. Unless specified otherwise, all * times are in seconds. */ -u_char sys_leap; /* system leap indicator */ +u_char sys_leap; /* system leap indicator, use set_sys_leap() to change this */ +u_char xmt_leap; /* leap indicator sent in client requests, set up by set_sys_leap() */ u_char sys_stratum; /* system stratum */ s_char sys_precision; /* local clock precision (log2 s) */ double sys_rootdelay; /* roundtrip delay to primary source */ @@ -71,6 +72,7 @@ l_fp sys_reftime; /* last update time */ struct peer *sys_peer; /* current peer */ struct leap_smear_info leap_smear; +int leap_sec_in_progress; /* * Rate controls. Leaky buckets are used to throttle the packet @@ -153,6 +155,31 @@ void pool_name_resolved (int, int, void *, const char *, const struct addrinfo *); #endif /* WORKER */ +void +set_sys_leap(u_char new_sys_leap) { + sys_leap = new_sys_leap; + xmt_leap = sys_leap; + + /* + * Under certain conditions we send faked leap bits to clients, so + * eventually change xmt_leap below, but never change LEAP_NOTINSYNC. + */ + if (xmt_leap != LEAP_NOTINSYNC) { + if (leap_sec_in_progress) { + /* always send "not sync" */ + xmt_leap = LEAP_NOTINSYNC; + } + else { + /* + * If leap smear is enabled in general we must never send a leap second warning + * to clients, so make sure we only send "in sync". + */ + if (leap_smear.enabled) + xmt_leap = LEAP_NOWARNING; + } + } +} + /* * transmit - transmit procedure called by poll timeout @@ -1911,7 +1938,7 @@ clock_update( */ case 2: clear_all(); - sys_leap = LEAP_NOTINSYNC; + set_sys_leap(LEAP_NOTINSYNC); sys_stratum = STRATUM_UNSPEC; memcpy(&sys_refid, "STEP", 4); sys_rootdelay = 0; @@ -1932,7 +1959,7 @@ clock_update( * process. */ if (sys_leap == LEAP_NOTINSYNC) { - sys_leap = LEAP_NOWARNING; + set_sys_leap(LEAP_NOWARNING); #ifdef AUTOKEY if (crypto_flags) crypto_update(); @@ -2426,7 +2453,7 @@ clock_select(void) osys_peer = sys_peer; sys_survivors = 0; #ifdef LOCKCLOCK - sys_leap = LEAP_NOTINSYNC; + set_sys_leap(LEAP_NOTINSYNC); sys_stratum = STRATUM_UNSPEC; memcpy(&sys_refid, "DOWN", 4); #endif /* LOCKCLOCK */ @@ -3480,22 +3507,14 @@ fast_xmit( /* * Make copies of the variables which can be affected by smearing. */ - int this_leap = sys_leap; l_fp this_recv_time; - /* - * If leap smear is enabled in general we must never send a leap second warning - * to clients, so make sure we only send "in sync" or "not in sync". - */ - if (leap_smear.enabled) - if (this_leap != LEAP_NOTINSYNC) - this_leap = LEAP_NOWARNING; /* * If we are inside the leap smear interval we add the current smear offset to * the packet receive time, to the packet transmit time, and eventually to the * reftime to make sure the reftime isn't later than the transmit/receive times. */ - xpkt.li_vn_mode = PKT_LI_VN_MODE(this_leap, + xpkt.li_vn_mode = PKT_LI_VN_MODE(xmt_leap, PKT_VERSION(rpkt->li_vn_mode), xmode); xpkt.stratum = STRATUM_TO_PKT(sys_stratum); xpkt.ppoll = max(rpkt->ppoll, ntp_minpoll); @@ -4021,7 +4040,7 @@ init_proto(void) * Fill in the sys_* stuff. Default is don't listen to * broadcasting, require authentication. */ - sys_leap = LEAP_NOTINSYNC; + set_sys_leap(LEAP_NOTINSYNC); sys_stratum = STRATUM_UNSPEC; memcpy(&sys_refid, "INIT", 4); sys_peer = NULL; diff --git a/ntpd/ntp_timer.c b/ntpd/ntp_timer.c index feeb531b1..e211f224f 100644 --- a/ntpd/ntp_timer.c +++ b/ntpd/ntp_timer.c @@ -42,6 +42,7 @@ #endif extern struct leap_smear_info leap_smear; +extern int leap_sec_in_progress; static void check_leapsec(u_int32, const time_t*, int/*BOOL*/); @@ -499,6 +500,17 @@ timer_clr_stats(void) } +static void +check_leap_sec_in_progress( const leap_result_t *lsdata ) { + int prv_leap_sec_in_progress = leap_sec_in_progress; + leap_sec_in_progress = lsdata->tai_diff && (lsdata->ddist < 3); + + /* if changed we may have to update the leap status sent to clients */ + if (leap_sec_in_progress != prv_leap_sec_in_progress) + set_sys_leap(sys_leap); +} + + static void check_leapsec( u_int32 now , @@ -530,7 +542,7 @@ check_leapsec( leapsec_electric(0); # endif #endif - leap_smear.enabled = 1; //##++ TODO this should depend on whether an interval has been specified in the config + leap_smear.enabled = leap_smear_intv != 0; if (reset) { lsprox = LSPROX_NOWARN; @@ -547,7 +559,7 @@ check_leapsec( if (leap_smear.enabled) { if (lsdata.tai_diff) { if (leap_smear.interval == 0) { - leap_smear.interval = 120; // TODO set configured value + leap_smear.interval = leap_smear_intv; leap_smear.intv_end = lsdata.ttime.Q_s; leap_smear.intv_start = leap_smear.intv_end - leap_smear.interval; DPRINTF(1, ("*** leapsec_query: setting leap_smear interval %li, begin %.0f, end %.0f\n", @@ -563,21 +575,36 @@ check_leapsec( if (leap_smear.interval) { double dtemp = now; if (dtemp >= leap_smear.intv_start && dtemp <= leap_smear.intv_end) { + double leap_smear_time = dtemp - leap_smear.intv_start; /* * For now we just do a linear interpolation over the smear interval */ - dtemp = -((dtemp - leap_smear.intv_start) * lsdata.tai_diff / leap_smear.interval); +#if 0 + // linear interpolation + leap_smear.doffset = -(leap_smear_time * lsdata.tai_diff / leap_smear.interval); +#else + // Google approach: lie(t) = (1.0 - cos(pi * t / w)) / 2.0 + leap_smear.doffset = -((double) lsdata.tai_diff - cos( M_PI * leap_smear_time / leap_smear.interval)) / 2.0; +#endif /* * TODO see if we're inside an inserted leap second, so we need to compute - * dtemp = 1.0 - dtemp + * leap_smear.doffset = 1.0 - leap_smear.doffset */ - DTOLFP(dtemp, &leap_smear.offset); + DTOLFP(leap_smear.doffset, &leap_smear.offset); leap_smear.in_progress = 1; DPRINTF(1, ("*** leapsec_query: [%.0f:%.0f], now %u, smear offset %.6f\n", - leap_smear.intv_start, leap_smear.intv_end, now, dtemp)); + leap_smear.intv_start, leap_smear.intv_end, now, leap_smear.doffset)); +#if 1 //##++++++++++++++ + msyslog(LOG_NOTICE, "*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f\n", + leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval, + now, leap_smear_time, leap_smear.doffset); +#endif + } } } + else + leap_smear.interval = 0; if (fired) { /* Full hit. Eventually step the clock, but always @@ -646,10 +673,13 @@ check_leapsec( leapsec = lsprox; } - if (leapsec >= LSPROX_SCHEDULE) - leapdif = lsdata.tai_diff; - else - leapdif = 0; + if (leapsec >= LSPROX_SCHEDULE) + leapdif = lsdata.tai_diff; + else + leapdif = 0; + + check_leap_sec_in_progress(&lsdata); + #ifdef AUTOKEY if (update_autokey) crypto_update_taichange();