NTPD Refusing to accept time from GPSD

One of the (minor) drawbacks of the Raspberry Pi is the lack of a hardware clock. Normally, you'd work around this by configuring a good pool of NTP servers to connect to. What do you do though, if you can't guarantee there will be an Internet connection available when needed?

The solution is obvious, so obvious that many have already done it - use the time provided by a cheap GPS dongle. The gpsd daemon helpfully pushes the time to Shared Memory Segments (SHM) so it's a simple adjustment to the NTP configuration file to have NTPD pull the time from the dongle.

Except, it seems on Raspbian, it isn't quite so simple. You've followed all the instructions (simple as they are) but are still seeing an entry like this

# ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
SHM(0)          .GPS.            0 l    -   16    0    0.000    0.000   0.001

No matter what you try, reach stays at 0.

Frustrating, and there's very little to give you a guide. This post will tell you what the issue is, as well as how to go about finding it should it re-occur

TL:DR

For those not interested in how to troubleshoot the issue: The issue is that at some point, someone has decided that NTPD should run as the user ntp. As a result, NTPD isn't allowed to access the SHM needed to retrieve the time from the GPS.

This change is buried in the init script (/etc/init.d/ntp) edit that and look for 

user=ntp

Change to

user=root

There are good reasons why you might want NTPD to run as an unprivileged user, however for our particular use case that's not an option.  

Keep in mind you'll need to check that your changes haven't been reverted whenever NTP is updated.

 

Investigating

The tutorials on the net all assume that the configuration will just work, and by extension if it isn't working you've screwed up the config. We know this probably isn't the case (though not impossible) so let's start with what else we know

  • NTP is configured to retrieve from 127.127.28.0 - an IP used for the SHM
  • We followed the GPSD documentation thoroughly

So, we need to look at whether NTP can actually connect to the SHM (it's easier than working out if GPSD can write to it)

# ntpq -p 127.127.28.0
127.127.28.0: timed out, nothing received

So NTP can't connect, let's take a look at the shared memory segments then

# ipcs -m

------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x4e545030 0 root 600 80 2
0x4e545031 32769 root 600 80 1
0x4e545032 65538 root 666 80 1
0x4e545033 98307 root 666 80 1

We know from the NTP documentation in ntpshm.c that shared segments with keys 1314148400 - 1314148403 belong to NTP (in hex that would be 0x4e545030 - 0x4e545033).

We can also see that all the segments are owned by root, and the first two can only be read by root. NTPD should be running as root, but lets check

# ps aux | grep ntp
ntp 10004 0.3 0.3 5472 1516 ? Ss 01:46 0:00 /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 102:104 root 10057 0.0 0.1 3500 804 pts/0 S+ 01:46 0:00 grep ntp

So NTP is running as user ntp, and we can already see that's happening because it's been passed the argument -u 102:104, there's nothing in /etc/default/ntp in terms of setting users, so the init script is the next place to look.

So, if we edit /etc/init.d/ntp and change

user=ntp

to

user=root

followed by

service ntp restart

We should find that NTP is suddenly able to use the GPS as a time source;

# ntpq -p

remote refid st t when poll reach delay offset jitter
==============================================================================
ntp-ext.cosng.n 146.213.3.180 2 u 12 64 3 62.228 -423.81 2.459
ptbtime1.ptb.de .PTB. 1 u 11 64 3 42.923 -421.15 2.436
dns4.rpi.edu 147.84.59.145 2 u 11 64 3 90.491 -415.90 2.412
portal.kt.kg 89.109.251.23 2 u 6 64 3 290.391 -481.50 139.861
*SHM(0) .GPS. 0 l 11 16 37 0.000 -1.917 2.750 

That should now be job done (notice that reach is now > 0).

A slightly more graceful solution might be to allow NTPD to run as user ntp, but to ensure it can access the SHM, but this works just as well - it's on a system that's very well isolated from the rest of the world so running as root shouldn't pose any real concern.