Raspberry NTP stratum 1

DIY
temps de lecture ~13 min
  1. 1. Principe de base
  2. 2. Architecture
  3. 3. Installation
    1. 3.1. 1- le PPS
    2. 3.2. 2- GPSD
    3. 3.3. 3- chrony
  4. 4. Conclusion

L’objet de ce billet est de vous donner les clés de configuration d’un raspberry pi afin de le transformer en serveur NTP fiable de stratum 1, c’est à dire en haut de la hiérarchie du NTP. Ce dispositif n’a pas la précision d’un serveur connecté à une source atomique présentant une fréquence d’oscillation très fiable, mais comme la plupart des serveurs stratum 1 il utilise une source GPS déjà de bonne qualité.

Principe de base

Le système de géolocalisation GPS (idem pour Galileo) se base sur une triangulation des signaux de plusieurs satellites afin de déterminer finement la distance du récepteur à chacun de ces satellites. Les signaux reçus des satellites comportent l’heure absolue et leur position respective est connue sur la base d’éphémérides. Pour déterminer finement la position du récepteur on doit donc utiliser l’heure présentée par chaque satellite dont le signal arrive avec quelques décalage en fonction de leur distance et utiliser l’éphéméride pour positionner le satellite à l’heure estimée. Plus l’heure estimée est fiabilisée, plus la position de chaque satellite est précise et la position du récepteur précise également.

Ce qui nous intéresse plus particulièrement dans ce principe de positionnement est l’heure que le récepteur va déterminer pour calculer sa position. La position en l’occurrence n’est pas importante pour notre serveur NTP.

En complément de l’heure calculée par le récepteur GPS ce qui est très intéressant ici est d’utiliser la source fournie par le composant du récepteur et permettant de fournir un oscillateur fiable (PPS). C’est à partir de celui-ci que nous obtiendrons la fiabilité de notre horloge et pas depuis l’heure du GPS. Les ordres de grandeur en termes de fiabilité sont de l’ordre de 100 ms d’écart pour l’heure du GPS contre 200 ns pour le PPS.

Architecture

Pour reproduire cette installation il vous faudra un Raspberry Pi et une carte GPS avec une sortie PPS, j’utilise un chip de type Neo 6M de chez uBlox, on en trouve aux alentours de 10€ à souder ou autour de 30€ sur un pi-hat.

Le GPS pousse ses informations brutes sur le port série /dev/ttyAMA0 qu’il faut donc dédier à cet usage (on supprimera la console standard).

Le signal PPS est repositionné sur un GPIO, j’ai choisi le PWM0 qui est géré par le matériel directement, positionné sur la broche 12 et généralement nommé BCM18 (cf https://pinout.xyz/). On fera analyser et utiliser le signal PPS par le noyau du raspbian afin d’en faire une discipline et la proposer dans le user space pour les logiciels qui en auraient besoin, ici ce sera gpsd.

Le logiciel gpsd interprète les signaux en provenance du port série et les normalisent dans un segment de mémoire partagée. Idem pour le PPS qui est également partagé dans un segment de mémoire.

Le serveur NTP, chrony, utilisera alors les 2 segments de mémoire afin de récupérer l’heure du GPS et la discipline PPS et s’en servir pour proposer le service NTP aux reste des utilisateurs du réseau IP.

Installation

A partir d’une installation neuve sur base de raspbian on installe quelques packages complémentaires. Je suis parti sur une base de version 10.3 pour ce blog.

1
2
3
apt-get -y update
apt-get -y upgrade
apt-get install -y gpsd gpsd-clients python-gps pps-tools chrony

Cet ajout consiste principalement en :

  • la gestion du GPS permettant de récupérer l’heure et la source PPS
  • la librairie et les outils pour le PPS
  • le serveur de temps chrony

1- le PPS

Le module pps-gpio est chargé dans le noyau, on le configure pour un chargement automatique dans le fichier /etc/modules :

/etc/modules
1
pps-gpio

Puis on le raccroche au GPIO sur lequel nous avons accroché le PPS de la carte GPS , dans :

/boot/config.txt
1
dtoverlay=pps-gpio,gpiopin=18

Après le prochain boot on peut vérifier la présence de la source PPS avec la commande ppstest qui va valider que l’on dispose bien d’un PPS, c’est cette source qui sera consommé par gpsd.

ppstest /dev/pps0
1
2
3
4
5
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1589711839.999999633, sequence: 6672 - clear 0.000000000, sequence: 0
source 0 - assert 1589711840.999998902, sequence: 6673 - clear 0.000000000, sequence: 0

2- GPSD

Le daemon gpsd interprète les informations transmises en texte sur le port série et utilise le PPS pour fiabiliser la dérive. On lui spécifie le port série sur lequel il va trouver ses informations de positionnement et d’heure dans son fichier de configuration

/etc/default/gpsd
1
2
DEVICES="/dev/ttyAMA0"
GPSD_OPTIONS="-n"

Une fois le service gpsd démarré, on peut vérifier les informations collectées avec la commande cgps qui affichera entre autre les informations de position, d’heure et les satellites présents et sélectionnés.

cgps -s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
│ Time: 2020-05-17T12:00:30.000Z ││PRN: Elev: Azim: SNR: Used: │
│ Latitude: 48.XX N ││ 5 13 052 30 Y │
│ Longitude: 2.YY E ││ 16 17 292 29 Y │
│ Altitude: 35.054 m ││ 21 43 111 26 Y │
│ Speed: 0.36 kph ││ 25 28 112 27 Y │
│ Heading: 58.7 deg (true) ││ 26 50 294 35 Y │
│ Climb: 14.82 m/min ││ 29 59 056 30 Y │
│ Status: 3D DIFF FIX (41 secs) ││ 31 57 220 46 Y │
│ Longitude Err: +/- 2 m ││ 136 34 136 28 Y │
│ Latitude Err: +/- 3 m ││ 2 02 033 22 N │
│ Altitude Err: +/- 10 m ││ 4 10 318 33 N │
│ Course Err: n/a ││ 18 45 159 47 N │
│ Speed Err: +/- 0 kph ││ 123 27 143 32 N │
│ Time offset: 0.137 ││ 125 31 203 46 N │
│ Grid Square: JN18du ││ │

Ici, 8 satellites utilisés pour la triangulation, la zone du récepteur est grossièrement donnée en coordonnées Grid (cf https://www.qrz.com/gridmapper).

Une vérification sur le PPS de l’écart avec ppswatch, vous pourrez alors avoir quelque chose comme:

ppswatch -a /dev/pps0
1
2
3
4
5
6
7
8
9
10
timestamp: 1589717422, sequence: 12242, offset: -1464
timestamp: 1589717423, sequence: 12243, offset: 61
timestamp: 1589717424, sequence: 12244, offset: -2060
timestamp: 1589717425, sequence: 12245, offset: -692
^C
Total number of PPS signals: 84
Maximum divergence: 3027
Mean value: -1052.42
Standard deviation: 907.399

3- chrony

Le serveur NTP utilisera les informations en provenance des 2 segments de mémoire partagée afin de récupérer les informations mises en page par gpsd concernant le GPS et le PPS. On configure ces 2 sources dans :

/etc/chrony/chrony.conf
1
2
refclock SHM 0 offset 0.5 delay 0.2 refid GPS noselect
refclock SHM 1 refid PPS precision 1e-9

Une fois démarré chrony va utiliser l’ensemble des sources dont il dispose, vous pouvez utiliser quelques sources de serveurs NTP sur internet afin de comparer les valeurs. Quelques outils à regarder avant de mettre en mode serveur pour les autres utilisateurs du réseau.

Les sources :

chronyc sources
1
2
3
4
5
6
7
8
9
10
11
12
13
14
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#? GPS 0 4 377 18 -367ms[ -367ms] +/- 100ms
#* PPS 0 4 377 19 +6ns[ -102ns] +/- 208ns
^- 2001:bc8:255e:100::1 2 10 377 450 -2302us[-2264us] +/- 54ms
^- 2001:41d0:a:268f::53 2 10 377 510 +1446us[+1493us] +/- 8450us
^- server2.websters-compute> 2 10 377 182 -667us[ -665us] +/- 45ms
^- yotsuba.fkraiem.org 2 10 377 694 -1314us[-1265us] +/- 48ms
^- ntp-1.arkena.net 2 10 377 418 +2954us[+2987us] +/- 31ms
^- wahe.diwi.org 2 10 377 498 +1356us[+1401us] +/- 29ms
^- www.almaprovence.fr 3 8 377 645 +11ms[ +11ms] +/- 62ms
^- ns3003772.ip-37-59-47.eu 2 10 377 202 -425us[ -422us] +/- 5508us
^- ts2.aco.net 1 10 377 518 -1931us[-1884us] +/- 20ms
^- ts2.aco.net 1 10 377 212 -3486us[-3483us] +/- 15ms

Ici des sources de différents stratum, on évitera dans la vraie vie d’aller directement chercher des sources de stratum 1, le protocole est assez fiable pour se limiter à des sources plus nombreuses même si un peu moins fiables. On retrouve GPS comme notre source de temps et PPS comme notre source d’horloge, c’est celle-ci qui est préférée, directement attachée et d’une fiabilité bien meilleure, sous la microseconde.

chronyc sourcestats
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
==============================================================================
GPS 16 7 240 +2.448 9.234 -367ms 765us
PPS 6 3 80 -0.001 0.024 -6ns 190ns
2001:bc8:255e:100::1 34 15 143m +0.334 0.116 -1544us 404us
2001:41d0:a:268f::53 21 12 127m +0.450 0.183 +1218us 406us
server2.websters-compute> 33 15 147m +0.337 0.151 +347us 527us
yotsuba.fkraiem.org 15 11 116m +0.395 0.178 -157us 313us
ntp-1.arkena.net 17 6 118m +0.284 0.328 +4144us 610us
wahe.diwi.org 33 16 142m +0.437 0.214 +1083us 619us
www.almaprovence.fr 8 7 38m +0.093 0.562 +11ms 108us
ns3003772.ip-37-59-47.eu 6 3 77m +0.255 0.464 -231us 248us
ts2.aco.net 34 19 142m +0.525 0.375 +1284us 1091us
ts2.aco.net 34 15 147m +0.485 0.127 -2708us 483us
chronyc tracking
1
2
3
4
5
6
7
8
9
10
11
12
13
Reference ID : 50505300 (PPS)
Stratum : 1
Ref time (UTC) : Sun May 17 12:17:52 2020
System time : 0.000000267 seconds slow of NTP time
Last offset : -0.000000383 seconds
RMS offset : 0.000000437 seconds
Frequency : 1.942 ppm fast
Residual freq : -0.003 ppm
Skew : 0.026 ppm
Root delay : 0.000000001 seconds
Root dispersion : 0.000014458 seconds
Update interval : 16.0 seconds
Leap status : Normal

Sur 2 clients du réseau on peut constater quelques écarts et la précision relative du raspberry

un client ntpd :

ntpq -p
1
2
3
4
5
6
7
8
9
remote refid st t when poll reach delay offset jitter
==============================================================================
*raspberrypi.hom .PPS. 1 u 30 512 377 1.083 0.350 0.567
+ts2.aco.net .GPS. 1 u 510 512 377 34.653 -0.004 0.231
-time.cloudflare 10.19.9.101 3 u 515 512 377 2.286 -2.071 0.178
+nio.nucli.net 131.188.3.222 2 u 14 512 377 2.057 0.147 0.307
+2a01:e0a:334:10 .GPS. 1 u 524 512 377 12.961 0.319 0.460
-www.almaprovenc 37.187.174.185 3 u 23 512 377 1.236 -10.238 0.663
+serveur-secours 212.83.158.83 3 u 514 512 377 2.138 0.308 0.368

un client chrony :

chronyc tracking
1
2
3
4
5
6
7
8
9
10
11
12
13
Reference ID : C0A810F1 (raspberrypi.home)
Stratum : 2
Ref time (UTC) : Sun May 17 12:01:41 2020
System time : 0.000027616 seconds slow of NTP time
Last offset : -0.000105767 seconds
RMS offset : 0.003665681 seconds
Frequency : 719.454 ppm fast
Residual freq : -0.002 ppm
Skew : 0.078 ppm
Root delay : 0.001195393 seconds
Root dispersion : 0.001225245 seconds
Update interval : 1024.9 seconds
Leap status : Normal

et

chronyc sources
1
2
3
4
5
6
7
8
9
10
11
210 Number of sources = 8
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^x clock.stdtime.gov.tw 4 6 377 37 +31ms[ +31ms] +/- 24ms
=* raspberrypi.home 1 10 377 1133 -69us[ -175us] +/- 628us
^- 2001:41d0:b:816::1 2 10 377 924 +1622us[+1622us] +/- 33ms
^- 2001:41d0:1:90a7::123 2 8 377 24 +340us[ +340us] +/- 6969us
^- ntp2.ds.network 2 10 377 811 -303us[ -303us] +/- 14ms
^- time-b.as43289.net 2 7 377 93 -154ms[ -154ms] +/- 334ms
^- ts2.aco.net 1 10 377 814 +74us[ +74us] +/- 18ms
^- ts2.aco.net 1 10 377 749 -3545us[-3545us] +/- 15ms

Conclusion

Avec peu d’investissement on peut disposer d’un serveur NTP disposant de sa propre horloge d’un niveau de précision et fiabilité assez élevé. Un bon moyen de rester autonome, voir de proposer ce serveur à la communauté via le pool ntp. Seul réel inconvénient, disposer d’un endroit pour le positionner avec son antenne en visibilité directe des satellites, ce qui est de loin le plus complexe dans cette opération.

Photo Fabrizio Verrecchia

Alexandre Chauvin Hameau

2020-05-17T17:10:02