Help us understand the problem. What is going on with this article?

改めて、ntpd が GPS 時刻を取れなくなった場合に必要なプログラムを再起動する

以前 GPS モジュールを見失ったら gpsd を再起動させる で対応しようとしたが上手くいかず暫く放置していたが、改めて考える。

考えられる GPS 時刻が取れなくなる原因

  1. GPS モジュールと gpsd が通信速度が合わずに通信できない
  2. gpsd 再起動後にセマフォを使った ntpd との通信が上手くいかなくなる

確認方法

  1. GPS モジュールと gpsd 間
    a) ntpshmmon で該当モジュールの出力があるか確認
    b) gpsmon で、該当モジュールの出力を確認
    gpsmon localhost:2947:/dev/ttyUSBn
    c) gpscat で、該当モジュールの出力を確認
    gpscat localhost:2947:/dev/ttyUSBn

  2. gpsd と ntpd 間<
    a) ntpq -p | grep SHM で、reach 欄が 0 でない
    b) ntpq -c associations で、対象の condition と last_event が「reject unreachable」になっていない (対象は ntpq -c apeer で assid を確認)

解消方法

  1. GPS モジュールと gpsd 間
    gpsd を再起動
  2. gpsd と ntpd 間
    ntpd を再起動

スクリプト化

  1. GPS モジュールと gpsd 間

検出 (gpsd)

# /home/pi/opt/gpsd-3.18.1/ntpshmmon -t 3
ntpshmmon version 1
#      Name Seen@                Clock                Real                 L Prec
sample NTP0 1568759552.858062790 1565059095.067431939 1565059095.000000000 0 -20
sample NTP2 1568759552.858158518 1568759552.001487029 1568759552.000000000 0 -30
sample NTP3 1568759552.858191018 1564716014.348685357 1564716014.000000000 0 -20
sample NTP4 1568759552.858222112 1564716015.000534782 1564716015.000000000 0 -20
sample NTP5 1568759552.858252476 1564716986.066649638 1564716986.000000000 0 -20
sample NTP6 1568759552.858282632 1564716986.996633827 1564716987.000000000 0 -20
sample NTP2 1568759553.001645576 1568759553.001487139 1568759553.000000000 0 -30
sample NTP2 1568759554.001593915 1568759554.001486051 1568759554.000000000 0 -30
sample NTP2 1568759555.001652722 1568759555.001486057 1568759555.000000000 0 -30

この 2行目の Name 欄を抜き出して uniq して 6行あれば全ての GPS レシーバと通信できている。

前回も載せたスクリプト

/root/bin/ntp_semaphore_check
#!/bin/sh

NTPSHMMON=/home/pi/opt/gpsd-3.18.1/ntpshmmon

count=`$NTPSHMMON -t 3 | grep sample | cut --delim=" " -f 2 | sort -u | wc -l`

if [ $count -ne 6 ]; then
        logger -p local0.notice "$0: ntpshm ckeck, error detected."
        echo | /root/bin/gpsd_restart
fi

/root/bin/gpsd_restart は gpsd を再起動するスクリプト。

再起動 (gpsd)

#!/bin/sh

SYSTEMCTL=/bin/systemctl
STTY=/bin/stty
GPSCTL=/home/pi/opt/gpsd-3.18.1/gpsctl
IPCRM=/usr/bin/ipcrm

MKTEMP=/bin/mktemp
LOCKDIR=/tmp/`basename $0`
LOCKPID=$LOCKDIR/pid

# SHM segments
# http://doc.ntp.org/4.2.8/drivers/driver28.html
clear_shm (){
# セマフォを削除します
# 通常、セグメントサイズを変更した場合のみ実行すればよい
# https://github.com/rnorris/gpsd/blob/master/SConstruct#LC1963
# 削除すると key は一緒でも shmid が変わるので ntpd の再起動が必要になる。やっちゃダメ。
#   for i in 0x4e545030 0x4e545031 0x4e545032 0x4e545033 0x4e545034 0x4e545035 0x4e545036 0x4e545037 0x47505344;do
#       $IPCRM -M $i
#   done
}

stty_speed () {
    for i in /dev/ttyS0 /dev/ttyUSB0 /dev/ttyUSB1; do
        $STTY -F $i 115200
    done
}

# already running other process?
if [ -d $LOCKDIR ]
then
    # LOCKDIRがある
    if [ -f $LOCKPID ]
    then
        # PIDファイルがあってそのプロセスがない or ある
        kill -0 `cat $LOCKPID`
        if [ $? -ne 0 ]; then
            rm -rf $LOCKDIR && break
        else
            logger -p local0.notice "$0: still running."
            exit
        fi
    fi
fi

# make lock directory
mkdir $LOCKDIR
if [ $? -ne 0 ]; then
    logger -p local0.notice "$0: lockfile make error."
    exit
fi
echo $$ > $LOCKPID


while read LINE; do
    $SYSTEMCTL stop gpsd
    clear_shm
    /bin/sleep 1
    sync
    $SYSTEMCTL start gpsd
    logger -p local0.notice "$0: gpsd restart to me!"
done

# remove lock directory
rm -rf $LOCKDIR
  1. gpsd と ntpd 間

検出 (ntpd)

# ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
+ntp-a3.nict.go. .NICT.           1 u 1375  68m  377   10.311    0.431   1.508
+ntp-b2.nict.go. .NICT.           1 u  66m  68m  377   13.518    1.582   1.541
+ntp-b3.nict.go. .NICT.           1 u 1537  68m  377   13.007    1.783   2.277
*ntp-a2.nict.go. .NICT.           1 u  102  68m  377   12.483    1.370   1.337
-ats1.e-timing.n .PPS.            1 u  60m  68m  273   11.622    0.282   0.987
-cwa225.bai.ne.j 210.171.0.34     4 u  71m  68m  377    6.457    2.216   1.619
-cwa201.bai.ne.j 210.171.0.34     4 u  47m  68m  377    5.647    3.896   5.895
 SHM(0)          .NEMA.           0 l  47d    1    0    0.000  -61.442   0.000
 SHM(2)          .PPS.            0 l  47d    1    0    0.000    0.509   0.000
 SHM(3)          .NEMA.           0 l  47d    1    0    0.000  -75.459   0.000
 SHM(4)          .PPS.            0 l  47d    1    0    0.000   -0.529   0.000
 SHM(5)          .NEMA.           0 l  47d    1    0    0.000  -69.134   0.000
 SHM(6)          .PPS.            0 l  47d    1    0    0.000   -0.257   0.000

remote が SHM を含み、reach が 0 の項目があるかチェック。

ntpq -p | awk '($0~/SHM/ && $7==0){print "error";exit}'

再起動 (ntpd)

GPS モジュールの reach が 0 になっていたら gpsd が正常に動いているかを確認し、動いていなければ ntpd の再起動。

ntpq -p | awk '($0~/SHM/ && $7==0){print "error";exit 255}' || systemctl restart ntpd

スクリプトをまとめてみる

流れ
1. gpsd が GPS モジュールから時刻を取得できているか? (ntpshmmon)
→ できている 3
→ できていない 2
2. gpsd を再起動し終了
ntpd でも時刻が取得できていない筈だが、それで通信の可否は判定できない。
3. ntpd が gpsd から時刻を取得できているか? (ntpq)
→ できている (終了)
4. ntpd を再起動し終了

判断用とログ用でコマンドを 2回起動していたりしますがまぁ、
ただいま書換え中...

GPS_time_check
#!/bin/bash
# 初期設定
SYSTEMCTL=/bin/systemctl
STTY=/bin/stty
IPCRM=/usr/bin/ipcrm
LOGGER=/usr/bin/logger
TR=/usr/bin/tr
AWK=/home/pi/opt/bin/awk

NTPQ=/home/pi/opt/bin/ntpq
NTPSHMMON=/home/pi/opt/gpsd-3.18.1/ntpshmmon
PYTHONPATH=/home/pi/opt/lib/python2.7/site-packages:/usr/local/lib/python2.7/site-packages:/usr/lib/pypy/lib-python/2.7/site-packages
export PYTHONPATH

GPSTTYS="/dev/ttyS0 /dev/ttyUSB0 /dev/ttyUSB1"

# debug
trap 'echo "[${BASH_SOURCE:-$0}:$LINENO] - "$BASH_COMMAND" abnomal status"' ERR

# 二重起動防止 (ロック)
MKTEMP=/bin/mktemp
LOCKDIR=/tmp/`basename $0`
LOCKPID=$LOCKDIR/pid

if [ -d $LOCKDIR ]; then
    # LOCKDIRがある
    if [ -f $LOCKPID ]; then
        # PIDファイルがあってそのプロセスがない or ある
        kill -0 `cat $LOCKPID`
        if [ $? -ne 0 ]; then
            rm -rf $LOCKDIR
        else
            $LOGGER -p local0.notice "$0: still running."
            exit
        fi
    else
        rmdir $LOCKDIR
    fi
fi

# make lock directory
trap 'rm -rf $LOCKDIR' 1 2 3 15
trap 'rm -rf $LOCKDIR' EXIT
mkdir $LOCKDIR
if [ $? -ne 0 ]; then
    $LOGGER -p local0.notice "$0: lockfile make error."
    exit
fi
echo $$ > $LOCKPID

stty_speed () {
    echo -n $GPSTTYS | xargs -d " " -n 1 -i'{}' $STTY -F '{}' 115200
}

# セマフォを削除
# http://doc.ntp.org/4.2.8/drivers/driver28.html
# セグメントサイズを変更した場合のみ実行すればよい
# https://github.com/rnorris/gpsd/blob/master/SConstruct#LC1963
# 削除すると key は一緒でも shmid が変わるので ntpd の再起動が必要になる。普段はやっちゃダメ。
clear_shm (){
    echo shemapho clear
    for i in 0x4e545030 0x4e545031 0x4e545032 0x4e545033 0x4e545034 0x4e545035 0x4e545036 0x4e545037 0x47505344; do
        $IPCRM -M $i
    done
}

check_gpsd (){
    RESULT="`$NTPSHMMON -t 3 | $TR '\n' @`"
    if [ `echo $RESULT | $TR @ '\n' | $AWK '/NTP[0-9]/{print $2}' | sort -u | wc -l` -ne 6 ]; then
        echo "$NTPSHMMON error detected"
        echo $RESULT | $TR @ '\n'
        echo $RESULT | $TR @ '\n' | $AWK '/NTP[0-9]/{print $2}' | sort -u
        $SYSTEMCTL stop gpsd
        stty_speed
        /bin/sleep 1
        $SYSTEMCTL start gpsd
        $LOGGER -p local0.notice "$0: gpsd restart to me!"
        echo 'gpsd: Restart done!'
        exit 255
    fi
}

check_ntpd (){
    RESULT="`$NTPQ -p | $TR '\n' @`"
    echo "$RESULT" | $TR @ '\n' | $AWK '($0~/SHM/ && $7==0){exit 255}' || \
    ( echo "ntpd error detected" ;\
      echo "$RESULT" | $TR @ '\n' | $AWK '($0~/SHM/ && $7==0){print}' ;\
      $SYSTEMCTL restart ntp ;\
      $LOGGER -p local0.notice "$0: ntpd restart to me!";\
      exit 255 )
}

check_gpsd && check_ntpd

定期的に起動してチェックする

crontab
*/10 * * * * /root/bin/gps_time_check

rsyslog で ntp 関連のログを別ファイルに保存する

/etc/rsyslog.conf
# ntpd & gpsd logging
# 出力の書式
template (name="ntp_mess" type="string" string="%timereported% %hostname% %syslogfacility-text%.%syslogseverity-text% %syslogtag% %msg%\n")

# 出力ファイル名
template (name="NtpLogfile" type="string" string="/var/log/ntp.log_%$year%%$month%")

# kernel メッセージで ppp や、usb, ch341 (sub-serial インターフェイス) が含まれていたらロギング
if $syslogfacility-text == 'kern' and (
        re_match($msg,'pps pps[0-9]+:') or ($msg contains "usb") or ($msg contains "ch341")
    )
then {
    action(type="omfile" template="ntp_mess" dynaFile="NtpLogfile")
}

# systemd からのメッセージで gps や ntp という文字列が含まれる場合はロギング
if ($syslogtag contains 'systemd') and ($msg contains_i 'gps' or $msg contains_i 'ntp')
then {
    action(type="omfile" template="ntp_mess" dynaFile="NtpLogfile")
}

# プログラム名に ntpd や gpsd という文字列が含まれる場合はロギング
if ($programname == 'ntpd') or ($programname == 'gpsd')
then {
    action(type="omfile" template="ntp_mess" dynaFile="NtpLogfile")
}

# メッセージ部分に再起動スクリプトのファイル名が含まれていたらロギング
if ($msg contains '/root/bin/gps_time_check')
then {
    action(type="omfile" template="ntp_mess" dynaFile="NtpLogfile")
}

rsyslog の設定を反映させる

> sudo systemctl restart rsyslog

その後

> bash -c 'while true; do date; ntpq -p; echo; sleep 10; done'
2019年  9月 22日 日曜日 16:10:26 JST
     remote                                   refid      st t when poll reach   delay   offset   jitter
=======================================================================================================
-ntp-a3.nict.go.jp                       .NICT.           1 u  192  256  377   9.7247   0.7944   4.4669
-ntp-b2.nict.go.jp                       .NICT.           1 u  185  256  377   8.9898   0.2955   1.4627
-ntp-b3.nict.go.jp                       .NICT.           1 u  191  256  377   9.9750   0.9161   0.8876
-ntp-a2.nict.go.jp                       .NICT.           1 u  180  256  377   9.0554   0.4391  21.2595
-61-114-187-55.secomtrust.net            .PPS.            1 u  185  256  377  10.5863   0.6503   1.6526
-cwa225.bai.ne.jp                        210.171.0.34     4 u  193  256  377   2.3816   0.3855   3.1480
-cwa201.bai.ne.jp                        210.171.0.34     4 u  216  256  377   1.3140   0.3483   1.5777
xSHM(0)                                  .NEMA.           0 l    -    1  377   0.0000 -48.3162   0.9223
+SHM(2)                                  .PPS.            0 l    1    1  377   0.0000   0.5475   0.0349
xSHM(3)                                  .NEMA.           0 l    -    1  377   0.0000 -61.3037   1.6150
+SHM(4)                                  .PPS.            0 l    1    1  377   0.0000  -0.2275   0.0460
xSHM(5)                                  .NEMA.           0 l    -    1  377   0.0000 -61.7563  18.4702
*SHM(6)                                  .PPS.            0 l    1    1  377   0.0000  -0.2266   0.0295

相変わらず jitter が小さいですねぇ。これで安定するかな? (いや、再起動してたら安定してないけど)

ntpviz でグラフ化してみた

GPS を常に見るようになって offset (青) は小さくなりましたね。ただ、pps 信号が毎秒チェックするので Frequency Offsets (赤) の変動が凄い。
local-offset.png
作成方法:> ntpviz -d ntpstats/ -n Ras1 -p 31 -o ./htdocs で html ドキュメントを作成
※Raspberry Pi だと全然終わらない (140分以上) ので Windows Subsystem for Linux で入れた Debian GNU/Linux へログをコピーして実行 (3分)。Debian で gnuplot, NTPsec のインストール済み。

NICT 群とのずれを比較しようとしたけど、GPS を見てない間は更新頻度が低いのか、点線で描かれてしまい読み難くて判断がつかない。いくらか良くなってるかな?
nict.png
作成方法:> ntpviz --peer-offsets "133.243.238.163,133.243.238.164,133.243.238.243,133.243.238.244" -d ntpstats/ -n Ras1 -p 31 -g > htdocs/nict.png

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away