hostapdによる無線アクセスポイント
PCIeパススルーでNUC本体の無線LANユニットを接続し、hostapdによるアクセスポイントに成功した。
基本的な手順は下記を参照した。
hostapd を使用した簡単な方法で WiFi に強力な暗号化を実装する
confファイルについては、zypperでインストールする際に追加されたもののデバイス名だけ書き換えることで動いた。
上記のサイトではドライバをnl80211にすると書いてあるが、デフォルトのままで動作した。
これでMACアドレスごとに事前交換鍵が異なるアクセスポイントができた。
ルーターなどの共通鍵よりちょっとセキュアなのと、MACアドレスフィルタリング相当もできたことになる。
MACアドレスは偽造可能なので、微妙だけど…
ホストデバイス接続
ネットワークなどは仮想化インターフェースでいいとして、無線LANアダプタを取り込んでアクセスポイントにするために仮想マシン側にPCIデバイスを直結するPCIパススルーを試す。
PCIパススルーに必要なIOMMUは標準でONにならないので、カーネル引数に下記を追加する。
intel_iommu=on
ただ、Leapの場合上記を追加してVt-dが有効な状態で起動させるとカーネルパニックが起きてしまう。
カーネルパニックが起きるようになってしまっても、起動だけならUEFI設定でVt-dを無効化することで行えるが、それは本末転倒なので、結局Tumbleweedに戻した。
不安定だったのはKDEのせいということにして、Minimal Xで使うことにした。
上記設定を適用した後、Virt-managerでホストデバイスを選んで追加し、仮想マシンを起動させればアクセスが可能となる。
同時にホストデバイスからはデバイスが切断される。
下調べしていた時はホスト側であらかじめ切り離す処理などを入れる必要があるのかと考えていたが、特に必要なかった。
OVMF による PCI パススルー - ArchWiki
ただ、blacklistに入れてドライバがロードされないようにしておいた方が良さげ。
準仮想化ドライバ
ゲストOS側が対応していればNICやBlockデバイスを準仮想化ドライバVirtIOにすることで性能向上が図れるということなのでやってみた。
特に難しいことはなく、ディスクの場合は接続方式をデフォルトのIDEからVirtIOに変更し、NICの場合はe1000からVirtIOに変更するして再起動すれば問題なく動作した。
"準"というのは既存ハードウェアを完全に模擬するのではなく、仮想化ホストと効率よく通信できるようなデバイスを定義して効率を上げると理解した。
下記のサイトを参考にした。
virtio: Linux の I/O 仮想化フレームワーク
https://www.nic.ad.jp/ja/materials/iw/2012/proceedings/d1/d1-Asama.pdf
現時点で性能は測ってないが、悪くなる道理はないので安定するようならこのまま使う。
追記
VirtIOに変更するとディスクデバイス名がsda→vdaに変わる。
SUSEはfstabやgrubの設定はUUIDベースで行っているので、VirtIOに変更したとしても自動追従するが、カーネル引数だけresume=/dev/sda2と決め打ちで書いてある箇所があり、起動が遅くなることがある。
仮想マシンではレジュームを使わないので、この引数は削除した。
仮想マシン起動&監視デーモン
ルーターとしての用途を考えると、電源が入った時点で仮想マシンが起動している必要がある。
virshにはautostartというオプションがあるが、これは起動順番などは制御できないようなので、自前で起動スクリプトを書いて、初期化時に呼び出すことにした。
下記を参考にした。
[ThinkIT] 第4回:virshコマンドで仮想化を管理する! (2/3)
これで作ったスクリプトをboot.localから呼び出せば自動起動…と思ったのだが、libvirtに必要なサービスが起動していないらしく、起動に失敗した。
試行錯誤の結果、作成した監視スクリプトをsystemdのサービスとして登録し、依存関係を登録してやればうまく動くことが分かった。
まず監視スクリプト。
#!/bin/bash # Must be root if test "`/usr/bin/id -u`" != 0 ; then echo "$0: You must be root to run this script" >& 2 exit 1 fi SLEEPTIME=10 boot_vm () { if test "`virsh domstate $1`" != "running" ; then virsh start $1 rc=$? [ $rc -ne 0 ] && exit $rc sleep $SLEEPTIME fi } halt_vm () { if test "`virsh domstate $1`" != "shut off" ; then virsh shutdown $1 rc=$? [ $rc -ne 0 ] && exit $rc sleep $SLEEPTIME fi } exit_service () { halt_vm leap-router-dmz-int halt_vm leap-router-ext-dmz } trap "exit_service" EXIT while true do boot_vm leap-router-ext-dmz boot_vm leap-router-dmz-int sleep 120 done
pingによる監視なども入れたいと思ったが、とりあえず最低限の起動順序制御・落ちた場合の再起動・ホスト終了時のシャットダウン処理のみ。
これによって、特に操作しなくても自動的にルーター用のVMが起動するようになる。
呼び出すためのsystemdサービス定義。
[Unit] Description = KVM router startup After=network.target libvirt-guests.service libvirtd.service Requires=network.target libvirt-guests.service libvirtd.service [Service] ExecStart = /usr/local/sbin/vm-router-service Restart = always Type = simple [Install] WantedBy = multi-user.target
これによって必要なサービスの準備が終わってから起動するようになる。