今朝未明、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」の部分を削除した。 これで安心 (だといいな)。