仙石浩明の日記

2006年4月7日

adsl-stop

今朝未明、bフレッツのメンテナンス工事があって、 GCDの対外線が切れた。 切れたこと自体は事前に NTT からアナウンスがあったことだし 問題はないのだが、

bフレッツが切れたことにより PPPoE を行っている pppd が終了すると、 /etc/ppp/adsl-lost が実行される。 GCD の adsl-lost は次のようになっている:

#!/bin/sh
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
. /etc/rc.d/hostname
MASTER_FILE="/var/run/keepalived_vrrp.MASTER"
if [ -f $MASTER_FILE -a "$1" = "/etc/ppp/pppoe.conf" ]; then
    rm -f $MASTER_FILE
    ERROR_FILE="/var/run/keepalived_vrrp.ERROR"
    echo 2 >> $ERROR_FILE
    /command/svc -t /service/keepalived/
fi

つまり、/var/run/keepalived_vrrp.MASTER を削除したうえで keepalived を再起動する。 すると、keepalived は BACKUP 状態に移行する。 すると、

/etc/rc.d/vrrp_notify INSTANCE VI BACKUP

実行されて、vrrp_notify が adsl-stop を呼び出す。

そして、adsl-stop が adsl-connect が強制終了する。 こうして完全な BACKUP 状態になるはずだった。

ところが

今朝起きて見てみると、 ゲートウェイが両方とも BACKUP 状態になっていた。(*_*)

片方のゲートウェイは PPPoE がつながっていて、 インターネットに正常に接続しているのだが、 あいにく BACKUP 状態なので、 GCD LAN のデフォルトゲートウェイアドレスである 192.168.1.1 を 持っておらず、 GCD LAN の他のマシンからインターネットへ接続できない状態に 陥っていた。

どうしてこんな事態になってしまったのか考えるより、 まずは復旧が優先ということで、 PPPoE がつながっているのに BACKUP 状態となっている 中途半端なゲートウェイ上で adsl-connect プロセスを殺し、 keepalived を再起動させて、 完全な BACKUP 状態へ移行させた。

すると、もう片方のゲートウェイが自動的に MASTER へ昇格して、 無事正常な状態に戻った。

その後、原因を調べていると、 前述したように adsl-stop が adsl-connect を強制終了させることが できずに adsl-connect が走り続けていたことが原因と判明。 つまり、adsl-connect が走り続けたために、 BACKUP 状態であるにもかかわらず PPPoE のリトライを行っていた。 そして bフレッツのメンテナンス工事の終了にともなって PPPoE が成功、 BACKUP 状態なのに PPPoE でつながっている、という状態が発生した。 この状態では、正常にインターネットにつながっているために、 MASTER に昇格することはなく、BACKUP 状態が継続する。

一方、もう片方のゲートウェイは、MASTER に昇格しようとして PPPoE を試みても失敗してしまう。 つまり MASTER へ昇格できない。 したがって、両方のゲートウェイが BACKUP 状態のままになる。

というわけで問題は adsl-stop が adsl-connect を 終了させることができない点にありそうだと推測。 あらためて adsl-stop を読みなおすと...

    # Kill pppd, which should in turn kill pppoe
    if [ -r "$PPPD_PIDFILE" ] ; then
        PPPD_PID=`cat "$PPPD_PIDFILE"`
        $LOGGER -p daemon.notice "Killing pppd"
        echo "Killing pppd ($PPPD_PID)"
        kill $PPPD_PID > /dev/null 2>&1 || exit 1
    fi
    ....
    # Kill adsl-connect
    $LOGGER -p daemon.notice "Killing adsl-connect"
    echo "Killing adsl-connect ($PID)"
    kill $PID > /dev/null 2>&1

以前このスクリプトを読んだときは見落としていたのだが、 「kill $PPPD_PID」の後に「|| exit 1」がついている! なんだこれは!?

つまり、pppd プロセスが動いていなければ exit してしまうので、 adsl-connect を終了させないではないか! 誰だ、こんな頭悪いコードを書いた奴は。

adsl-connect は pppd が失敗すると、 リトライするまえに 5秒 sleep する。 つまりこの 5秒間は pppd プロセスが無い。 だから、運悪く sleep 中に adsl-stop を実行すると、 adsl-connect が強制終了されずに残ってしまう。

速攻で adsl-stop から「|| exit 1」の部分を削除した。 これで安心 (だといいな)。

Filed under: システム構築・運用 — hiroaki_sengoku @ 11:56

No Comments »

No comments yet.

RSS feed for comments on this post.

Leave a comment