hnwの日記

Raspberry Pi の Wi-Fi パワーマネジメントモードについて調べた

さいきんRaspberry Pi 4を買ったんですが、Wi-Fiだけで運用したときにRaspberry Piへのアクセスがイマイチ不安定、ということがありました。ネットの情報を調べるとLinuxの無線ネットワークの「パワーマネジメントモード」をオフにすれば平和になるような話が見つかるんですが、その挙動を解説した記事が見つからなかったので自分なりに調べてみました。

パワーマネジメントモードの確認

パワーマネジメントモードの有効無効はiwコマンドで調べられます。たしかにwlan0で有効になっていますね。

$ iw dev wlan0 get power_save
Power save: on

パワーマネジメントモードの無効化

下記のようにすればパワーマネジメントモードを無効にできます。

$ sudo iw dev wlan0 set power_save off

この設定はOSを再起動すると元に戻ってしまうので、私は以下の/etc/dhcpcd.exit-hookWi-Fi設定時にパワーマネジメントモードを無効化しています。これはdhcpcdのフック機能を利用しています(参考:dhcpcd-run-hooks(8))。

if [ "$reason" = "PREINIT" -a "$interface" = "wlan0" ]]; then
    iw dev wlan0 set power_save off
fi

パワーマネジメントモード有効のときの挙動を確認する (1)ping

パワーマネジメントモードを有効にしていると、無線インターフェースが無通信時にスリープに入るような挙動になります。

$ while true ; do ping -c4 192.168.1.168 ; sleep 15; done
PING 192.168.1.168 (192.168.1.168): 56 data bytes
Request timeout for icmp_seq 0
64 bytes from 192.168.1.168: icmp_seq=0 ttl=64 time=1793.757 ms
64 bytes from 192.168.1.168: icmp_seq=1 ttl=64 time=790.571 ms
64 bytes from 192.168.1.168: icmp_seq=2 ttl=64 time=2.760 ms
64 bytes from 192.168.1.168: icmp_seq=3 ttl=64 time=6.573 ms

--- 192.168.1.168 ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 2.760/648.415/1793.757/734.991 ms
PING 192.168.1.168 (192.168.1.168): 56 data bytes
64 bytes from 192.168.1.168: icmp_seq=0 ttl=64 time=703.300 ms
64 bytes from 192.168.1.168: icmp_seq=1 ttl=64 time=3.618 ms
64 bytes from 192.168.1.168: icmp_seq=2 ttl=64 time=9.246 ms
64 bytes from 192.168.1.168: icmp_seq=3 ttl=64 time=9.187 ms

--- 192.168.1.168 ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 3.618/181.338/703.300/301.364 ms
PING 192.168.1.168 (192.168.1.168): 56 data bytes
Request timeout for icmp_seq 0
64 bytes from 192.168.1.168: icmp_seq=0 ttl=64 time=1549.241 ms
64 bytes from 192.168.1.168: icmp_seq=1 ttl=64 time=545.393 ms
64 bytes from 192.168.1.168: icmp_seq=2 ttl=64 time=2.565 ms
64 bytes from 192.168.1.168: icmp_seq=3 ttl=64 time=9.234 ms

--- 192.168.1.168 ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 2.565/526.608/1549.241/630.164 ms
PING 192.168.1.168 (192.168.1.168): 56 data bytes
64 bytes from 192.168.1.168: icmp_seq=0 ttl=64 time=455.575 ms
64 bytes from 192.168.1.168: icmp_seq=1 ttl=64 time=3.466 ms
64 bytes from 192.168.1.168: icmp_seq=2 ttl=64 time=9.315 ms
64 bytes from 192.168.1.168: icmp_seq=3 ttl=64 time=3.040 ms

他マシンから15秒おきにpingを打ってみると、1回目のレスポンスだけ極端に遅く、2回目または3回目からレスポンスが安定します。最初の2秒くらいスリープしているかのような挙動です。おそらくスリープ時にNICの一部回路だけでパケットを監視し、自分宛のパケットが届いたら無線インターフェース全体をwake upするような仕組みになっているのでしょう。

この状態でSSH越しに作業しているとたまに秒単位のレイテンシが発生するものの、wake up後は爆速になるので、これで省電力になるならアリかな?と思ってしまうかもしれません。

パワーマネジメントモード有効のときの挙動を確認する (2)ARP

パワーマネジメントモードを有効にしたときの問題点は、スリープ時にブロードキャストパケットが来てもスリープしたまま無視されてしまう点です。具体的にはARPやmDNSに対して返事を返しません。これは次のようにARPテーブルをクリアしてからRaspberry PiIPアドレスに対してpingを打つことで確認できます。

$ sudo arp -d -a
192.168.1.1 (192.168.1.1) deleted
192.168.1.168 (192.168.1.168) deleted
224.0.0.251 (224.0.0.251) deleted
$ ping -c1 192.168.1.168
PING 192.168.1.168 (192.168.1.168): 56 data bytes

--- 192.168.1.168 ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss

tcpdumpで確認してみましたが、無線インターフェースがスリープしているタイミングではARPのリプライは返ってきません。偶然Raspberry Pi内部から通信が発生したタイミング(wake upしたタイミング)でARP問い合わせを投げると返答があり、そこでようやくIPアドレスベースで通信ができるようになります。

率直に言って、この設定は多くの利用者にとって混乱の元だと思います。別マシンからリモートログインするような状況を考えると、久々にログインする際にARP問い合わせをして運悪く返事がなかったらIPでの通信すら成立しないわけですから、さすがに不便すぎると思います。

まとめ

  • Raspberry Pi では無線のパワーマネジメントモードがデフォルトでオンになっている
  • パワーマネジメントモードがオンだと無通信時に無線インターフェースがスリープする、省電力の観点で有利
  • 自分がパケットを出すとき、または自分宛のパケットが届いたときに無線インターフェースが自動的にwake upするので、条件が整っていればスリープ時も通信できる
  • ブロードキャストパケットに対しては自動wake upの仕組みが働かない模様、特にARPに反応できないのは致命的で実用性は疑問

IoTの文脈で間欠的にセンサー値を外部サーバに送信するような状況であれば有用だと思いますが、それ以外の状況では無条件にオフにした方がいいんじゃないでしょうか。