batman-advを本番環境で6ヶ月運用して実際に起きたこと
2024年末に、自宅ラボと小規模なIoT環境にまたがるbatman-advメッシュを構築した。Raspberry Pi 4ノードが3台、接続デバイスが約40台、有線ゲートウェイが1台という構成だ。簡単にまとめると、予想以上に安定して動作した。ノードが落ちて、復帰して、経路を切り替える——すべて手動介入なしに。それだけで、この実験は十分な価値があった。
この記事では、batman-advを選ぶ前に何を比較したか、実際に上手くいくことと躓きやすい点、最終的に落ち着いた構成、そしてDebianやUbuntuシステムで再現するためのステップバイステップガイドをまとめる。
メッシュネットワーキングのアプローチ:何があるか
batman-advに決める前に、Linuxネイティブでオープンソースのメッシュ構成として現実的な3つの選択肢を検討した。
802.11s(IEEE標準メッシュ)
カーネルレベルの802.11sプロトコルはLinuxワイヤレススタックに組み込まれている。Hybrid Wireless Mesh Protocol(HWMP)を使ってMACレイヤーでパス選択を行う。セットアップはiwとwpa_supplicantで行う。理論上は最もクリーンな選択肢だ——完全に標準化されており、追加のカーネルモジュールも不要。
実際の使用感はもっと複雑だった。手元にはath9k、mt76、rtl8192euの3つのWi-Fiアダプターがあったが、安定してメッシュリンクをネゴシエートできたのは2つだけだった。3つ目はアソシエートはするものの、実際にはトラフィックを通さなかった。そのデバッグに、batman-advのセットアップをゼロから構築するより多くの時間を費やした。
batman-adv(B.A.T.M.A.N. Advanced)
batman-advはレイヤー2で動作する——物理ワイヤレスインターフェースの上に仮想イーサネットインターフェース(bat0)として現れる。ルーティングの判断は、リンク品質メトリクス(Transmit Quality、TQ)に基づいてカーネルモジュール内部で行われる。各ノードはOGM(Originator Messages)をブロードキャストして自身の存在を通知し、他のすべての到達可能なノードへのパス品質を測定する。
802.11sと異なり、batman-advはトランスポートに依存しない。Wi-Fi、イーサネット、またはその両方を同時に使って動かせる。有線のIoTノードと無線のIoTノードが混在する私の構成では、この柔軟性が決定的だった——メッシュはすべてのノードを同等に扱う。
OLSR / Babel
OLSR(Optimized Link State Routing)とBabelはレイヤー3ルーティングプロトコルだ。BGPやOSPFとの統合やIPレベルのルーティング制御が必要な大規模な展開では優れた選択肢だ。しかし、同一サブネット上にすべてのデバイスを置く透過的なレイヤー2ブリッジングが目的のホームラボやIoTメッシュでは、不要な複雑さが増えるだけで、結果は同じだ。動く部品が増えるのに、得られるものは変わらない。
batman-adv:率直なメリットとデメリット
上手くいくこと
- 自己修復ルーティング:ノードがダウンすると、トラフィックは素早く再ルーティングされる——私のテストでは通常3〜8秒。転送中にノードの電源を抜いても、セッションがきれいに回復するのを確認した。
- トランスポート非依存:同じ
bat0インターフェースがWi-Fi、イーサネット、または両方を同時に使って動作する。有線・無線混在ノードもそのまま機能する。 - レイヤー2の透過性:すべてのノードが同じブロードキャストドメインを共有する。DHCP、mDNS、ARP——追加のトンネリングやルーティング設定なしに通常通り機能する。
- カーネルモジュールの成熟度:batman-advはカーネル3.9からメインラインに含まれている。最近のUbuntu/Debianでは
modprobe一発で使える。 - 小型ハードウェアでの低オーバーヘッド:USBのWi-Fiアダプターを接続してbatman-advを動かしたRaspberry Pi 3BノードのCPU使用率は、通常のメッシュ動作中に8%未満だった。
不足している点
- WPA3メッシュ暗号化がネイティブに非対応:batman-adv自体はトラフィックを暗号化しない。リンクレイヤーの暗号化は別途対応が必要——基盤となるワイヤレスインターフェース上でWPA2を使うか、WireGuardのようなVPNオーバーレイを使う。
- デバッグに学習コストがかかる:
batctlツール自体は優秀だが、特定のパスが選ばれる理由を理解するにはTQ値とOGMテーブルを読み解く必要がある。最初の数回は直感的ではない。 - ブロードキャスト・マルチキャストのオーバーヘッド:大規模なメッシュ(20ノード以上)ではブロードキャストトラフィックがノイジーになりうる。小規模な構成では問題にならないが、スケールアップ時には監視すべき点だ。
- ドライバーの互換性:すべてのWi-Fiアダプターがbatman-advの依存するモニター/アドホックモードに対応しているわけではない。ath9kとmt76ドライバーは安定したサポートがあるが、安価なUSBアダプターの多くは対応していない。
推奨セットアップ
数週間の試行錯誤を経て、最終的に落ち着いた構成は以下の通りだ——それ以来、問題なく動作し続けている。
- ハードウェア:Raspberry Pi 4ノード(×3)、TP-Link TL-WN722N USBアダプター(ath9k_htcドライバー)、有線アップリンク付きのゲートウェイノード1台。
- OS:Ubuntu 22.04 LTS(全ノード同一イメージ)
- インターフェースモード:5GHz チャンネル36でアドホック(IBSS)、SSID
batman-mesh - batman-advバージョン:2021.4(カーネルモジュール)+対応バージョンのbatctl
- 暗号化:ノード間プライバシーのためのWireGuardオーバーレイ
- DHCP:ゲートウェイノード上の単一dnsmasqインスタンスが
bat0ブロードキャストドメイン全体に配信
実装ガイド
ステップ1:batman-advとbatctlをインストールする
# すべてのメッシュノードで実行
sudo apt update
sudo apt install batctl bridge-utils wireless-tools wpasupplicant
# batman-advカーネルモジュールを読み込む
sudo modprobe batman-adv
# 起動時に自動読み込みする設定
echo 'batman-adv' | sudo tee -a /etc/modules
ステップ2:ワイヤレスインターフェースをアドホックモードに設定する
wlan0は実際のインターフェース名に置き換えること。事前にip linkで確認しておく。
# モード変更前にインターフェースをダウンさせる
sudo ip link set wlan0 down
# アドホック(IBSS)モードに設定
sudo iwconfig wlan0 mode ad-hoc
sudo iwconfig wlan0 essid batman-mesh
sudo iwconfig wlan0 ap any
sudo iwconfig wlan0 channel 36
# インターフェースを起動する(IPアドレスなし — bat0経由でbatman-advがアドレスを管理)
sudo ip link set wlan0 up
ステップ3:batman-advにインターフェースを追加する
# wlan0をbatman-advのスレーブインターフェースとして追加
sudo batctl if add wlan0
# 有線インターフェースも含める場合:
sudo batctl if add eth1
# 確認
sudo batctl if
ステップ4:bat0インターフェースを起動する
# 仮想メッシュインターフェースを起動
sudo ip link set bat0 up
# ゲートウェイノードの場合: 固定IPを割り当てる
sudo ip addr add 10.10.10.1/24 dev bat0
# 他のすべてのノードの場合: DHCPを使う(ゲートウェイにdnsmasqが起動してから)
sudo dhclient bat0
ステップ5:systemdで自動化する(永続的な設定)
手動セットアップはテストには十分だ。本番環境では、起動スクリプトとsystemdユニットで紐付ける。/etc/systemd/system/batman-mesh.serviceを作成する:
[Unit]
Description=batman-adv メッシュネットワーク セットアップ
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/batman-mesh-up.sh
[Install]
WantedBy=multi-user.target
次に/usr/local/bin/batman-mesh-up.shを作成する:
#!/bin/bash
set -e
INTERFACE=wlan0
MESH_SSID=batman-mesh
CHANNEL=36
modprobe batman-adv
ip link set $INTERFACE down
iwconfig $INTERFACE mode ad-hoc
iwconfig $INTERFACE essid $MESH_SSID
iwconfig $INTERFACE channel $CHANNEL
ip link set $INTERFACE up
batctl if add $INTERFACE
ip link set bat0 up
sudo chmod +x /usr/local/bin/batman-mesh-up.sh
sudo systemctl enable batman-mesh
sudo systemctl start batman-mesh
ステップ6:batctlでメッシュの状態を監視する
batctlを使えば、メッシュが何をしているか実際に可視化できる。少なくとも2つのノードが起動したら:
# 到達可能なすべてのノード(オリジネーター)とそのTQスコアを一覧表示(0〜255、高いほど良い)
sudo batctl o
# アクティブなメッシュインターフェースを表示
sudo batctl if
# リアルタイムTQ監視(1秒ごとに更新)
sudo batctl o -w 1
# MACアドレスでノードにpingを送る(IPではなくレイヤー2のping)
sudo batctl ping aa:bb:cc:dd:ee:ff
# メッシュを通じてtracerouteを実行
sudo batctl traceroute aa:bb:cc:dd:ee:ff
3ノードメッシュでbatctl oを実行したときのサンプル出力:
[B.A.T.M.A.N. adv 2021.4, MainIF/MAC: wlan0/dc:a6:32:xx:xx:xx, mesh: bat0]
Originator last-seen (#/255) Nexthop [outif]
dc:a6:32:aa:bb:cc 0.132s (218) dc:a6:32:aa:bb:cc [wlan0]
e4:5f:01:11:22:33 0.420s (196) dc:a6:32:aa:bb:cc [wlan0]
e4:5f:01:44:55:66 0.890s (154) dc:a6:32:aa:bb:cc [wlan0]
TQ値が200以上であれば、直接リンクが安定している。100を下回ると、パスが複数のホップを経由しているか、リンク品質が低下している。ノードの動作が遅いと感じたときに最初に確認する数値がこれだ。
ステップ7:ゲートウェイノードにdnsmasqを設定する
sudo apt install dnsmasq
# /etc/dnsmasq.d/batman-mesh.conf
interface=bat0
dhcp-range=10.10.10.100,10.10.10.200,12h
dhcp-option=3,10.10.10.1 # デフォルトゲートウェイ
dhcp-option=6,1.1.1.1 # DNS
sudo systemctl restart dnsmasq
今なら変えるいくつかのこと
6ヶ月が経ち、構成は安定している——しかし、最初からやり直すなら変えたいことが2つある。1つ目:後付けではなく、最初からノード間にWireGuardを入れること。メッシュオーバーレイの暗号化は簡単で、Ansibleで全ノードへの鍵交換をスクリプト化すれば1時間もかからない。2つ目:最初から5GHzを使うこと。最初の2.4GHz構成では干渉の問題が頻発したが、チャンネル36に移った瞬間に解消した。
IoT向けに特に言及する価値があることがもう1つある。batman-advのレイヤー2透過性のおかげで、Zigbeeコーディネーター、MQTTブローカー、Home AssistantはメッシュノードをまたいでmDNSで互いを見つけられる——追加のルーティング設定は一切不要だ。レイヤー3アプローチで同じ動作を実現しようとすると、mDNSプロキシやavahiフォワーディングと格闘することになる。そのトラブルを回避できただけで、この選択は十分正当化される。

