3

I'm running ntpd on my machine, but I'm not sure if it is working correctly. How can I query ntpd to determine whether it has successfully connected to time servers and that my kernel time is synchronized?

6

There are several ways to determine whether ntpd is working:

  1. Use ntpq -p (or ntpq -pn to save time by skipping DNS lookups).

    This is what it looks like when NTP is working:

    host-a ~ # ntpq -p
         remote           refid      st t when poll reach   delay   offset  jitter
    ==============================================================================
     0.debian.pool.n .POOL.          16 p    -   64    0    0.000    0.000   0.000
     1.debian.pool.n .POOL.          16 p    -   64    0    0.000    0.000   0.000
     2.debian.pool.n .POOL.          16 p    -   64    0    0.000    0.000   0.000
     3.debian.pool.n .POOL.          16 p    -   64    0    0.000    0.000   0.000
    +mail.masters-of 144.76.76.107    3 u  975 1024  377   13.731   -0.737   2.552
    +ntp2.hetzner.de 124.216.164.14   2 u  232 1024  377   15.914   -0.650   0.854
    +rondra.lf-net.o 237.17.204.95    2 u 1020 1024  377   13.751   -0.557   4.292
    -funky.f5s.de    131.188.3.222    2 u  480 1024  377   15.730    2.082   4.377
    +stratum2-3.NTP. 129.70.137.82    2 u  742 1024  377   19.785   -0.366   7.498
    *mail.klausen.dk 193.79.237.14    2 u  173 1024  377   14.383   -0.513   2.066
    

    It'll list the actual peers it has connected to; * indicates the the source you are synchronized to. More information on the output is available in the NTP docs.

    This is what it looks like when it's not:

    host-b ~ # ntpq -p
         remote           refid      st t when poll reach   delay   offset  jitter
    ==============================================================================
     0.debian.pool.n .POOL.          16 p    -   64    0    0.000    0.000   0.000
     1.debian.pool.n .POOL.          16 p    -   64    0    0.000    0.000   0.000
     2.debian.pool.n .POOL.          16 p    -   64    0    0.000    0.000   0.000
     3.debian.pool.n .POOL.          16 p    -   64    0    0.000    0.000   0.000
    

    Note that there aren't any actual peers listed, which usually indicates that ntpd wasn't able to connect to any, probably because a firewall prevented the connections.

    ntpq -p isn't well-suited for scripted checks because the output has to be parsed, and while it's speed (30ms for a single call) isn't bad, there are faster ways which I'm going to discuss later on.

  2. If you're using systemd, you can use timedatectl status.

    This is what it looks like when NTP is working (note the System clock synchronized: yes):

    host-a ~ # timedatectl status 
                   Local time: Do 2021-04-22 13:29:20 CEST
               Universal time: Do 2021-04-22 11:29:20 UTC
                     RTC time: Do 2021-04-22 11:29:21
                    Time zone: Europe/Berlin (CEST, +0200)
    System clock synchronized: yes
                  NTP service: inactive
              RTC in local TZ: no
    

    This is what it looks like when it's not (note the System clock synchronized: no):

    host-b ~ # timedatectl status
                   Local time: Do 2021-04-22 13:29:53 CEST
               Universal time: Do 2021-04-22 11:29:53 UTC
                     RTC time: Do 2021-04-22 11:29:42
                    Time zone: Europe/Berlin (CEST, +0200)
    System clock synchronized: no
                  NTP service: inactive
              RTC in local TZ: no
    
    

    (NTP service refers to systemd-timesyncd, systemd's own NTP client. It shouldn't be running while ntpd is installed, so the no is to be expected here.)

    timedatectl status queries systemd-timedated which is only started on demand, which leads to a small performance penalty of ~100ms on the first call; further calls take about ~12ms.

    systemd-timedated in turn uses the adjtimex(2) syscall to query the kernel; if adjtimex(2) returns a status with the STA_UNSYNC bit set, the clock isn't synchronized. This means that timedatectl isn't actually talking to ntpd, but instead queries a bit stored in the kernel which NTP services like ntpd will update whenever the synchronization status changes.

    timedatectl status is well-suited for scripting, because you can query the relevant property directly:

    host-a ~ # timedatectl show -p NTPSynchronized --value                          
    yes
    host-b ~ # timedatectl show -p NTPSynchronized --value
    no
    
  3. Use adjtimex(2) directly:

    This is the least user-friendly approach, but the fastest one for scripting. busybox as provided by Debian buster has a adjtimex applet that serves as a simple wrapper around the adjtimex(2) syscall.

    This is what it looks like when NTP is working:

    host-a ~ # busybox adjtimex
        mode:         0
    -o  offset:       -570098 us
    -f  freq.adjust:  857283 (65536 = 1ppm)
        maxerror:     478704
        esterror:     302
        status:       8193 (PLL)
    -p  timeconstant: 10
        precision:    1 us
        tolerance:    32768000
    -t  tick:         10000 us
        time.tv_sec:  1619092119
        time.tv_usec: 60467600
        return value: 0 (clock synchronized)
    

    This is what it looks like when it's not (note the UNSYNC in the status line, and the ):

    host-b ~ # busybox adjtimex
        mode:         0
    -o  offset:       0 us
    -f  freq.adjust:  2126708 (65536 = 1ppm)
        maxerror:     16000000
        esterror:     16000000
        status:       16449 (PLL | UNSYNC)
    -p  timeconstant: 7
        precision:    1 us
        tolerance:    32768000
    -t  tick:         10000 us
        time.tv_sec:  1619091984
        time.tv_usec: 307119
        return value: 5 (clock not synchronized)
    

    Unfortunately busybox adjtimex doesn't seem to provide a way to print only a certain field, and the return value is only printed, not actually returned. This means that for scripting, you're going to have to parse the output (e.g. busybox adjtimex | grep -q UNSYNC). On the other hand, it compensates for this by being extremely fast - only 0.5ms!

1
  • 2
    Note that you can specify which service timedatectl sees as the "NTP service:" by setting the SYSTEMD_TIMEDATED_NTP_SERVICES environment variable for systemd-timedated.service. For example, if you set the variable as SYSTEMD_TIMEDATED_NTP_SERVICES=chronyd.service:ntpd.service then timedated (and also timedatectl) will look for chronyd.service and then ntpd.service. Old versions of systemd might not include this functionality. – telcoM Apr 22 at 12:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.