ユーザ用ツール

サイト用ツール


raspberrypi:log20140208_ntp_stratum_1

文書の過去の版を表示しています。


Raspberry Pi で NTP Stratum-1 Server を作る.

●変更履歴

  • 2014-3-2 初版
  • 2014-04-29 追記(Linux Kernel Config の CONFIG_NO_HZ を無効にすることで1マイクロ秒未満の精度で同期します)
  • 2014-04-29 追記(NTP リフレクションアタック対策を iptables で行う)
  • 2014-05-03 変更(シェルスクリプトや差分は GitHub Gist に登録してそれを参照するようにした)

Evernote 共有リンク(Evernote で保存したい人向け) https://www.evernote.com/shard/s32/sh/332945c9-464e-4816-9f60-c0d6c735d4e7/69b8e7b5e94ddbc9abb2a677a2ac37e8

●背景

Raspberry Pi は消費電力が2W程です.これでNTP Stratum-1 Server を作ると省電力ながらも精度の良いNTPサーバが出来ると思いましたので試してみました. Linux カーネルにパッチをあてて PPS(Pulse Per Second)が処理できるようにして,NTPサーバも再コンパイルして Stratum-1 サーバを構築します.

●まとめ

  • Raspberry Pi に GPS の PPS 信号を入れることで,GPS と10マイクロ秒未満で同期させることが出来ます.
  • 1日の初めの暫くの間は,10マイクロ秒以上の変動が見られます.この原因は不明で調べています.
  • (2014-04-29)Linux Kernel Config を修正することで,更に1マイクロ秒未満でGPS信号と同期します.

●必要なスキル

  • カーネルの再コンパイルが出来る事
  • ntp サーバソフトウェアの再コンパイルが出来る事

Linux ディストリビューションは Raspbian です. http://www.raspberrypi.org/downloads から得られる Raspbian Raw Images を SD カードに書き込みます.

●GPS モジュールの入手

Raspberry Pi の拡張ピンに直結できるGPSモジュール基板が販売されています.

Raspberry Pi GPS Addon Board
http://ava.upuaut.net/store/index.php?route=product/product&product_id=95

日本からも購入できて,購入してから約10日後に届きました.

●Raspberry Pi GPS Addon Board の仕様

  • GPS コアモジュールは Ublox MAX-7Q です.
  • ボーレートは 9600bps です.
  • PPS は,GPIO18 に繋がっています.Raspberry Pi 拡張ピン RXD の隣です.

●NTP Stratum-1 Server 構築の前準備

●ソフトウェアを最新に

まずは Raspbian を最新の状態へ更新します。

$ sudo apt-get update
$ sudo apt-get upgrade

●ラズパイの UART (シリアル) を空ける.

次に、ラズパイとGPSモジュールは,ラズパイの UART で直結しますので,Raspbian の inittab と cmdline.txt を編集して,カーネルのコンソールやシリアル経由でのログインを無効にします.

  1. vi 等のテキストエディタで, /boot/cmdline.txt を開いて console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 と二つのパラメータがあれば,二つとも削除します.
  2. /etc/inittab を開いて, T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100 の行が有効になっていれば先頭に '#' を入れて無効にします.

この時点で,一度ラズパイを再起動します.

●不要なデーモンソフトウェアの停止

もし triggerhappy が動いていれば,不要ですので停止します. なお,apt-get remove triggerhappy で triggerhappy を remove しようとすると,raspi-config も remove されそうなので,triggerhappy は remove せずに,自動起動をしないようにだけします.

  $ sudo insserv -r triggerhappy

サウンド関係も不要ですので, /etc/modules を開いて snd-bcm2835 もロードさせないようにします.

  $ cat /etc/modules
  # /etc/modules: kernel modules to load at boot time.
  ...
  #snd-bcm2835

また,insserv で alsa-utils も自動起動しないようにします.

  $ sudo insserv -r alsa-utils

ホスト名の設定と,mdnsでホスト名でアクセスできるようにしておきます.

Raspbian では,ホスト名は /etc/hostname で決定します.また,avahi-daemon をインストールすると,Linux や Mac OS X から “ホスト名.local” で名前引き出来るようになりますのでインストールします.

  $ sudo apt-get install avahi-daemon

ここまでで基本設定は終了です.

●ラズパイと GPS モジュールを接続

ラズパイにGPSモジュールを取り付けて電源を入れます.PWR が光り,GPS衛星を受信して測位できるとPPSが点滅します.

●GPS モジュールの信号仕様の調査

GPSモジュール購入サイトからは,GPS モジュールの詳細な資料が無さそうですので,ロジックアナライザを使って,どの様に信号が来ているのかを調べてみます.

  • GPSモジュールは,ボーレートは9600bps
  • PPSは,GPIO18に繋がっていて,ON 100ミリ秒,OFF 900ミリ秒の周期で 1PPS のパルスを生成している.
  • ロジックアナライザを見る限りでは,PPS 信号周期は91マイクロ秒ほどの差がありそうです.
    ロジックアナライザの精度は http://www.saleae.com/logic/specs によると +/- 42ns です.
    ただこの時,24Mhz では測定していなかったはずですので,もしかするとロジックアナライザの計測の誤差の可能性もあります.

●GPS モジュールの動作確認

GPS からの情報は,位置や時刻は NMEA センテンスと呼ばれる形式でシリアルで通信します. そのため,ラズパイでシリアルからGPSモジュールを読めるツールをインストールします. http://www.satsignal.eu/ntp/Raspberry-Pi-NTP.html を参考に,以下のツールを入れます.

  $ sudo apt-get install gpsd gpsd-clients python-gps

gpsd は,GPS モジュールからのNMEAセンテンスを代表で受信して,クライアントからの要求に対して配送するデーモンです.最終的には gpsd は使いませんが,GPSモジュールの情報を受信できているかの動作確認に使います.

  $ sudo gpsd /dev/ttyAMA0 -n -F /var/run/gpsd.sock

gpsd が起動できれば,cgps -s を実行してGPSモジュールからの時間や位置情報などが受信できているかを確認します.

GPSモジュールからの時間や位置情報を受信できていれば,GPSモジュールとの接続はOKです. gpsd はこれ以上使用しません(2014-04-29).

●ラズパイを NTP サーバにする.

●ラズパイの Linux カーネルのPPSドライバを有効にします.

http://ntpi.openchaos.org/pps_pi/ を参考に,ラズパイの拡張ピンのGPIO18 をPPSドライバで使えるようにします. このページに記載がありますが,「Enable modules Device Drivers/PPS support/PPS support and PPS client using GPIO」を忘れないで下さい.

(2014-04-29)ラズパイの Linux カーネルの Config は,CONFIG_NO_HZ が有効になっています. この場合,精度をナノ秒精度で合わせられないようです.必ず CONFIG_NO_HZ は is not set にしましょう.

以下のURLのページが参考になります.

Linux Kernel Config の要所は以下の通りです.

  1. CONFIG_NO_HZ を無効にする.(# CONFIG_NO_HZ is not set)
    私の環境では,CONFIG_HZ_PERIODIC=y にしています.(Linux Kernel 3.10.28+)
  2. CONFIG_PPS を有効にする.
    私の環境では,CONFIG_PPS=m にしています.
  3. CONFIG_NTP_PPS を有効にする.
  4. CONFIG_PPS_CLIENT_GPIO を有効にする.
    私の環境では,CONFIG_PPS_CLIENT_GPIO=m にしています.

カーネルのビルドとインストールができたら,/etc/modules に pps-gpio を追加します.

  $ cat /etc/modules
  # /etc/modules: kernel modules to load at boot time.
  #
  # This file contains the names of kernel modules that should be loaded
  # at boot time, one per line. Lines beginning with "#" are ignored.
  # Parameters can be specified after the module name.
  #snd-bcm2835
  pps-gpio
  $

●PPSドライバの動作確認

Linux カーネルのPPSドライバが,GPSモジュールのPPSを読み取っているかを確認するには,pps-tools をインストールします.

  $ sudo apt-get install pps-tools
  $ ppstest /dev/pps0

GPSモジュールが測位している(PPS LEDが点滅している)と,ppstest ではそのPPS周期で出力を出していくはずです.

●NTPサーバの再ビルド

これも,http://ntpi.openchaos.org/pps_pi/ を参考にビルドします.

●NTPサーバの設定

ここからは,http://ntpi.openchaos.org/pps_pi/ で書いている方法とは異なります. http://ntpi.openchaos.org/pps_pi/ に記載している方法は,GPSモジュールからの情報はgpsd がまず読み取り,gpsd と ntpd が共有メモリで時刻情報を読み出す方式です.

私の方法は,gpsd を介さずに,ntpd が直接GPSモジュールから読み出す方法です. なぜこの方法にするのかと言うと,gpsd と ntpd 間での共有メモリ書き込み・読み取り誤差を無くして精度を上げるためです. しかし逆に gpsd を使いませんので,他の用途でGPSの位置情報を使うことができなくなります.

●/etc/udev/rules.d/09.pps.rules の作成

ntpd が,GPSモジュールのデバイスファイルを使用できるようにするため,/etc/udev/rules.d/09.pps.rules を作成します.

  $ cat /etc/udev/rules.d/09.pps.rules
  KERNEL=="ttyAMA0", SYMLINK+="gps0"
  KERNEL=="pps0", OWNER="root", GROUP="dialout", MODE="0660", SYMLINK+="gpspps0"
  $

また,vigr コマンドで,ntp ユーザを dialout グループに追加します. ここでラズパイを一旦再起動します.これで,以下の様になるはずです.

  • ラズパイを起動すると,/dev/gps0 が /dev/ttyAMA0 にシンボリックリンクされる.
    ntpd は,GPS モジュールからの読み取りは,/dev/gps* を前提とします.
  • また,同じく起動時に /dev/gpspps0 が作成される.
  • デバイスファイルのグループは dialout グループなので,ntp ユーザを dialout グループに加える事でntpd がGPSモジュールのデバイスファイルをアクセスできるようになる.

●ntp.conf の設定

まずは現在の ntp サーバ設定をバックアップします.

  $ sudo cp /etc/ntp.conf /etc/ntp_orig.conf

次に,ntp.conf を修正して,GPSモジュールからの情報を読めるようにします. 以下にその差分を貼ります.

https://gist.github.com/tosihisa/bd55fec0b706b2fb062e

重要な変更は以下の通りです.

  1. 元々あった server 行は全て無効にします.つまり外部のNTPサーバの時刻は使いません.
  2. server 127.127.20.0 mode 17 minpoll 4 maxpoll 4 prefer が,GPS モジュールからのGPS読み取り設定です.
  3. fudge 127.127.20.0 flag1 1 flag3 1 の設定で,PPS信号も使用するようにします.
  4. ntpd のログ情報を記録するようにします.ntpd のログ情報の内, loopstats と sysstats を記録するようにします.

●(2014-04-29)その他の設定

以下のURLの方も,同じようにラズパイによる NTP Stratum-1 Server に取り組んでおられます.こちらの方の情報を参考にさせて頂きました. http://nyanchew.com/jp/gps%E3%81%AEpps%E4%BF%A1%E5%8F%B7%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F-stratum-1-ntp%E3%82%B5%E3%83%BC%E3%83%90%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9

上記URLによりますと,Linux カーネルの設定以外に,以下の設定を行うと良さそうですので試します.

  • disable_pvt=1/boot/config.txt に追加する.
  • smsc95xx.turbo_mode=0/boot/cmdline.txt に追加する.
  • echo “performance” > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
    私は,/etc/init.d/ntp の start で上記処理を行うようにしました.
  • setserial /dev/ttyAMA0 low_latency
    私は,/etc/init.d/ntp の start で上記処理を行うようにしました.

●ntp サーバ動作確認

ここまで出来たら,ラズパイを再起動して,ntpd がGPSモジュールと同期できているかを確認します.

  $ ntpq -p
       remote           refid      st t when poll reach   delay   offset  jitter
  ==============================================================================
  oGPS_NMEA(0)     .GPS.            0 l    5   16  377    0.000    0.000   0.001
  $

なお,GPSモジュールとラズパイが完全に同期するには,数時間かかるようです.初めは,GPS_NMEA(0)の前が '*' ですが,PPS同期すると 'o' に変わるはずです. なのですぐに「おかしい?」と思わずに,数時間待ってみて確認すると良いです.

●NTP サーバ稼働状況

NTP サーバの稼働状況で,ntpd がGPSモジュールとどれくらいズレているのかは,ntpd のログ情報である loopstats から得られます.

loopstats ファイルはテキストファイルですので,gnuplot を使って簡単にグラフ化出来ます.

ntpd の loopstats ファイルを元に gnuplot でグラフ化出来るシェルスクリプトを以下に貼ります.

https://gist.github.com/tosihisa/7978b6497f57e506589e

以下の様に使います.

  $ loopstats_gnuplot.sh loopstats [レンジ範囲] [レンジメモリ]

以下に,ntpd の1日のGPSモジュールとの同期状態グラフを貼ります. 1日の内,初めの内は10マイクロ以上の変動が見られるのですが,その内収束して数マイクロ秒の差でGPSモジュールと同期しているのが確認できます.

1日のうちの初めの10マイクロ以上の変動は謎で,これは調査中ですが,これでラズパイが NTP Stratum 1 として動いていることが確認できます.

●(2014-04-29)NTP サーバ稼働状況(CONFIG_NO_HZ is not set 以降)

CONFIG_NO_HZ を無効にしたカーネルと,「●(2014-04-29)その他の設定」を実施した後のGPS同期状態グラフを以下に示します.

初めの±2マイクロ秒以上の offset は Linux カーネル変更と設定前です.

まだ24時間も稼働させていませんが同期精度が格段に向上しています.

上記のグラフではレンジが荒いので,±3マイクロ秒範囲でグラフにしたものを貼ります.時々1マイクロ秒を超えるオフセットがありますが,ナノ秒レベルで同期できています.

●NTPリフレクションアタックへの対応(2014-04-29)

2014年1月に大規模なNTPリフレクションアタックがあったようです.これは NTP の monlist 機能を悪用したものです. http://www.jpcert.or.jp/at/2014/at140001.html

この攻撃への対象方法は様々な Web サイトで紹介されておりますが,ここでは,以下のWebページを参考に,Linux の iptables で遮断しようと思います. http://packetpushers.net/one-liner-iptables-rule-to-filter-ntp-reflection-on-linux-hypervisor/

このページでは,パケット仲介する所での FORWARD チェーンで対策されています. これを参考に,NTPサーバで以下のコマンドを実行して INPUT チェーンで monlist パケットを弾くようにします.

  # iptables -A INPUT -i eth0 -p 17 -m multiport --ports 123 -m u32 --u32 "0>>22&0x3C@8&0xFF=42" -j DROP

本当に iptables で弾いているかどうか,試してみます. まず,NTPサーバで iptables の設定状況を確認します.

  # iptables -L INPUT -n -v
  Chain INPUT (policy ACCEPT 1949K packets, 162M bytes)
  pkts bytes target     prot opt in     out     source               destination
     0     0 DROP       udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            multiport ports 123 u32 "0x0>>0x16&0x3c@0x8&0xff=0x2a"
  #

次に,NTPサーバ以外から,以下のコマンドを実行してみます.

  $ ntpdc -nc monlist [NTPサーバ]
  [NTPサーバ]: timed out, nothing received
  ***Request timed out
  $

接続できませんでした.NTPサーバ側の iptables を再度確認します.

  # iptables -L INPUT -n -v
  Chain INPUT (policy ACCEPT 1951K packets, 162M bytes)
  pkts bytes target     prot opt in     out     source               destination
     1   220 DROP       udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            multiport ports 123 u32 "0x0>>0x16&0x3c@0x8&0xff=0x2a"
  #

パケットカウントがカウントされ,monlist を検出して弾いたことが確認できます. なお,このNTPサーバは,2014年3月以降,pool.ntp.org に登録しているのですが,これまで 122回ほど monlist のクエリを受けていたようです. 数は多くないと思いますが,依然 monlist によるリフレクションアタックは0では無いので,公開NTPサーバを構築されている方は依然注意が必要です.

  # iptables -L INPUT -n -v
  Chain INPUT (policy ACCEPT 369M packets, 28G bytes)
  pkts bytes target     prot opt in     out     source               destination
   122  6958 DROP       udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            multiport ports 123 u32 "0x0>>0x16&0x3c@0x8&0xff=0x2a"

●リンク集

  • Raspberry Pi Stratum 1 NTP server with PPS
    http://ntpi.openchaos.org/pps_pi/
    Raspberry Pi の Linux カーネルで GPIO 18 を PPS ドライバとして使えるパッチがこのページからたどれます.
  • rpi_gpio_ntp
    http://vanheusden.com/time/rpi_gpio_ntp/
    私は試していませんが,Linux カーネルや NTP サーバの再コンパイルなしにPPSを使えるようにするもののように見えます.
raspberrypi/log20140208_ntp_stratum_1.1427556539.txt.gz · 最終更新: 2015-03-29 00:28 by tosihisa@netfort.gr.jp