]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
More support for smeared leap seconds.
authorMartin Burnicki <burnicki@ntp.org>
Fri, 19 Jun 2015 14:06:35 +0000 (16:06 +0200)
committerMartin Burnicki <burnicki@ntp.org>
Fri, 19 Jun 2015 14:06:35 +0000 (16:06 +0200)
bk: 558421ebHYzZ_IAmTBZ__FJKvkmD_w

include/ntpd.h
ntpd/ntp_config.c
ntpd/ntp_control.c
ntpd/ntp_leapsec.h
ntpd/ntp_proto.c
ntpd/ntp_timer.c

index 12d51115ecae343a21cff7d426b6dc15e2ab748d..c30b806247646229bc33fead959b483feaf24a4a 100644 (file)
@@ -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;
index bdc72448acb1719139b9efa1465afeda76cba0e8..c760e6a59d11871f7e2b0835e8c7bcb5513e6020 100644 (file)
@@ -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:
index aa9f78cb02909e0a391dab05772fc12bfe357988..72a365792a6a0eeaa95e5b6ed5f324a923ef2c6a 100644 (file)
@@ -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;
index 2f8a5d3451831e814f8645ecf0b269a939ad2192..affe627e0cb1403c561c7cadaf1a359a533342cd 100644 (file)
@@ -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 */
index eadda4859f042f9f0b3e0f00cd172051ddeef59c..107573cc97b2d2f0ba77882a3e6314abe807e965 100644 (file)
@@ -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;
index feeb531b165ed7824acc1a05d766ae0f67dafba9..e211f224fa0aeee2b3a266b8b8d5e8b100f3c7ad 100644 (file)
@@ -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();