この文書は、筆者が2009年7月頃に NetBSD/xen を試したときの覚え書き。
大雑把な手順はこう:
pkgsrc/sysutils にある xenkernel3 と xentools3 をインストールする。:
# cd /usr/pkgsrc/sysutils # (cd xenkernel3 && make install) # (cd xentools3 && make install)
Xen カーネルは /usr/pkg/xen3-kernel/ 以下に置かれる。 ここにある xen.gz をルートディレクトリにコピーする。:
# cp /usr/pkg/xen3-kernel/xen.gz /
ソースからビルドするか NetBSD の配布物に含まれているバイナリを持ってきて ルートディレクトリに適当な名前で置く。
ここでは /netbsd-XEN3_DOM0 とする。
なお、通常のカーネルは圧縮されていてもブートできるが、 少なくとも現在のNetBSDの現状のブートローダからブートする場合、 圧縮形式は非対応につき伸長しておく必要あり。
ソースからビルドする例:
# cd /anywhere/to/build # config -b . -s /usr/src/sys /usr/src/sys/arch/i386/XEN3_DOM0 # make depend # make # cp netbsd /netbsd-XEN3_DOM0
マシンを再起動し、ブートローダのプロンプトに落ちた後、 以下のようにして起動する。:
> load /netbsd-XEN3_DOM0 console=pc # (デフォルトはシリアルっぽい) > boot /xen.gz dom0_mem=512M
あるいは、/boot.cfg に以下のようなメニューを追加すればメニュー番号に 対応する数字キーを押すだけで起動できるようになる。:
menu=Boot Xen:load /netbsd-XEN3_DOM0 console=pc;multiboot /xen.gz
ここで NetBSD カーネルの引数 console=pc はコンソールデバイスとして 通常通りVGAを使うことを意味する。 デフォルトはシリアル(com0)になるようである。
Xen カーネルの引数 dom0_mem=512M はドメイン0に割り当てるメモリ量を指定する。 デフォルトでは全メモリがドメイン0に割り当てられるようであるが、 ドメインU用のメモリを必ず残しておかなくてはならないので必須。
/usr/pkg/share/example/rc.d/ 以下にある xend、xenbackendd、xendomains を /etc/rc.d にコピーし、/etc/rc.conf に xend=YES と xenbackendd=YES を追加し、それぞれ起動すること。:
# cp /usr/pkg/share/example/rc.d/xen* /etc/rc.d # vi /etc/rc.conf # xend=YES、xenbackendd=YES を追加 # /etc/rc.d/xend start # /etc/rc.d/xenbackendd start
大雑把な手順はこう。
NetBSD のミラーサイトから NetBSD-5.0 の CD-ROM イメージをダウンロードする。:
# cd /home/xen # ftp ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0/iso/i386/i386cd-5.0.iso
CD-ROMイメージから、ドメインU用のカーネルを取り出す。以下の2種類が必要。
作業例:
# cd /home/xen # vnconfig vnd0 i386iso-5.0.iso # mount /dev/vnd0a /mnt # cp /mnt/i386/binary/kernel/netbsd-{INSTALL_,}XEN3_DOMU.gz . # umount /mnt # vnconfig -u vnd0
1GBのハードディスクイメージ dom1-hdd.img を作成する例:
# cd /home/xen # dd if=/dev/zero of=dom1-hdd.img bs=1m count=1024
ここでは、インストール用のドメインとメインのドメインの コンフィグファイルを別々に用意することにする。 本当は変数と条件分岐を使って1つにすれば良いと思うけど、 Python 知らないので書けないだけ。
ドメインコンフィグファイルは /usr/pkg/etc/xen 以下に置くことにする。 ここに置くと xm create で指定するファイル名のディレクトリ部分を省略できる。
インストール用 dom1-install:
kernel = "/home/xen/netbsd-INSTALL_XEN3_DOMU.gz" memory = 128 name = "dom1" vif = [ 'ip=192.168.201.254 script=vif-ip' ] disk = [ 'file:/home/xen/dom1-hdd.img,0x3,w', 'file:/home/xen/i386cd-5.0.iso,0x4,r' ]
メイン用 /usr/pkg/etc/xen/dom1:
kernel = "/home/xen/netbsd-XEN3_DOMU.gz" memory = 128 name = "dom1" vif = [ 'ip=192.168.201.254 script=vif-ip' ] disk = [ 'file:/home/xen/dom1-hdd.img,0x3,w', 'file:/home/xen/i386cd-5.0.iso,0x4,r' ]
以下のコマンドを実行するとNetBSDのインストーラが起動するので、 好きなようにインストールすること。:
# xm create dom1-install -c
なお、上のコンフィグファイルの場合、
という名前のデバイスファイルが割り当てられる。
インストールが完了したら、他の端末から:
# xm shutdown dom1-install
と入力して ドメインU を終了させる。 暴走して終了しない場合は:
# xm destroy dom1-install
で強制終了可能。
以下のコマンドによりインストールした NetBSD を起動する。:
# xm create dom1 -c
ところで、xm create コマンドの引数 -c はコンソールに接続すること を意味する。 -c を付けないとOSを起動したらすぐにプロンプトにもどる。 -c を使わずに以下のように入力しても同じ。:
# xm create dom1 # xm console dom1
NetBSD wiki によると、起動時にエラーを表示させないために ドメインU に以下の設定をすると良いらしい。
また、/etc/rc.conf に powerd=YES を追加して powerd を動かしておくと、 ドメイン0 から xm shutdown したときにドメインU側で自動的に シャットダウン処理を実行してくれるから安全である。
ドメインU 内でOSを普通に再起動するとコンソール接続が切れてプロンプトに 戻るようであるが、 xm list で確認するとドメインはまだ終了していない。 そのときは、 xm console dom1= とすれば再び接続可能。
各ドメインUのネットワークインタフェースは ドメイン0の仮想ネットワークインタフェースに一対一(Point-to-point)で 接続される。
ドメインU側のインタフェース名は xennet0、xennet1、xennet2、...、 ドメイン0側の仮想インタフェース名は xvif1.0、xvif1.1、xvif1.2、...となる。 ここで、 xvif の後の数字は接続先のドメインIDとそのドメインの インタフェース番号を意味する。 例えばドメインIDが4のドメインUの xennet2 は ドメイン0の xvif4.2 と接続されている。:
DomainU domid=1 Domain0 +------------+ +------------- | [xennet0]----------[xvif1.0] | [xennet1]----------[xvif1.2] | ... | | +------------+ | | DomainU domid=2 | +------------+ | | [xennet0]----------[xvif2.0] | [xennet1]----------[xvif2.2] | ... | | +------------+ | ... | +-------------
Xen 仮想マシンのネットワーク接続には以下の2種類の形態があるようである。
ドメインコンフィグファイルに以下のように vif を設定した場合、:
vif = [ 'ip=10.0.0.254, netmask=255.0.0.0.0, script=vif-ip' ]
/usr/pkg/etc/xen/script 以下にあるスクリプト vif-ip によって 仮想マシンのネットワークは下図のように接続される。:
DomainU "dom1" Domain0 +------------+ +-------------+ | | |10.0.0.254 | | [xennet0]----------[xvif1.0] | | ... | | | +------------+ +-------------+
ドメイン0側の仮想インタフェース xvif?.0 は vif-ip によって 自動的にIPアドレスが設定される。 ドメインU側のインタフェース xennet0 のIPアドレスはドメインUの中で 設定すること。 両者はそれぞれのIPアドレスを使ってIPで通信できるようになる。
ドメイン0が xvif?.0 と他のインタフェースとの間でIPパケットの転送を 行なうならば、ドメインUにとってドメイン0はIPルータである。
ドメインコンフィグファイルに以下のように`vif`を設定した場合、:
vif = [ 'bridge=bridge0, script=vif-bridge' ]
/usr/pkg/etc/xen/script 以下にあるスクリプト vif-bridge によって 仮想マシンのネットワークは下図のように接続される。:
DomainU "dom1" Domain0 +------------+ +---------------------------+ | | | | | [xennet0]----------[xvif1.0]--(bridge0)-- ... | | ... | | | +------------+ +---------------------------+
ここで、bridge0 は ドメイン0 の中に作られたMACブリッジである。 bridge0 に複数のネットワークインタフェースが接続されていれば ドメイン0 は bridge0 接続されたインタフェース間でイーサネットフレーム の転送を行なう。 ドメインU から見て ドメイン0 は ブリッジすなわちハブであるため、 xvif?.0 はIPアドレスを持たない。 xennet0 のIPアドレスは ドメインU の中で設定すること。
なお、vif-bridge はブリッジ自体の生成は行なわないので ドメインU を起動する前にドメイン0上にブリッジ bridge0 が存在していなければならない。 NetBSDでは ifconfig bridge0 create up と実行するか、 /etc/ifconfig.bridge0 に単に create と書いて /etc/rc.d/network restart を実行する。
ところで、もし実ネットワークに接続された物理インタフェースがブリッジに 接続されていれば、この ドメインU の仮想ホストが実ネットワークに接続された ことに等しい、はずである。 しかし、筆者の環境では今のところ上手く言ってない。 OS の不具合か設定が間違っているのか筆者の勘違いなのかは不明。
IP接続にしてもブリッジ接続にしても Xen 自体が行なうことは 「ドメインU のインタフェースと ドメイン0 の物理インタフェースを生成して 両者を仮想的なリンクで接続すること」だけのはず。 それだけを行ないたい、つまり ドメインU 起動時にはまだIPアドレスの設定も ブリッジへの接続も行なわずに仮想インタフェースの生成とリンクの確立だけ 行ないたい場合、コンフィグファイルにはどのように記述すれば良いのだろうか? スクリプトは必ず必要なのだろうか?
試しに vif = [ '' ] とか、 vif = [ 'script=/dev/null' ] とか 書いてみたが、 xm create するとすぐに固まる。
少々ややこしい仮想ネットワークを組んでみる。
この実験では下図のようなネットワーク構成にする。:
DomainU "dom1" Domain0 +-----------+ +-------------------------------+ | 10.0.0.1 | | +--------+ 10.0.0.254| 家庭内LAN | [xennet0]--------[xvif?.0]-| |-[tap0] | +-----------+ | | | | +------+ to the | |bridge0 | x.y.z.u | |Bridge| Internet DomainU "dom2" | | | [ath0]=======|Router|======= +-----------+ | |10.0.0.0| | |NAT | | 10.0.0.2 | | | /8 | | |DHCP | | [xennet0]--------[xvif?.0]-| | | +------+ +-----------+ | | | | | ... | ... | | | | ... | +--------+ | 他のマシン ... +-------------------------------+
ドメイン0 は実インタフェース ath0 から家庭内LANへ接続し、 DHCP を用いてIPアドレス、デフォルトルータ、ネームサーバなどの ネットワーク情報をマシン起動時に取得している。
各 ドメインU の仮想インタフェースは ドメイン0 内で作成したブリッジ bridge0 に接続する。 更に ドメイン0内で仮想インタフェース tap0 を作成し bridge0 に接続する。 ドメイン0は、tap0 と ath0 の間でIPパケットを転送する。
仮想ネットワークではIPアドレスはプライベートアドレス空間 10.0.0.0/8 を使用する。dom1 には 10.0.0.1、dom2 には 10.0.0.2 を割り当てる。 また、ドメインU の仮想インタフェース tap0 には 10.0.0.254 を割り当てる。
ドメイン0は、パケット転送を行なう際に NAT によりプライベートアドレスを ath0 に割り当てられたIPアドレスに変換する。 なお、NAT には IPFilter を使用する。
Xenとは関係ないが一応書いておく。
/etc/rc.conf に dhclient=YES と記述する。 /etc/rc.d/dhclient restart を実行するか再起動して dhclient が 起動すると、IPアドレス、ネームサーバ(in resolv.conf)、 デフォルトルータが自動的に設定される。
メモ: dhclient 使うと後述する tap0 のIPアドレス設定が 0.0.0.0 になって しまう。インタフェースを明示すれば良いのかも知れないけど試してない。 別方法として /etc/ifconfig.ath0 に dhcp とだけ書いておくと このインタフェース用に dhcpcd を起動してくれる。こっちの方が綺麗?
/etc/ifconfig.bridge0 に以下のように記述する。:
create !brconfig $int up
/etc/network restart を実行するか再起動により有効になる。
/etc/ifconfig.tap0 に以下のように記述する。:
create inet 10.0.0.254 !brconfig bridge0 $int
/etc/network restart を実行するか再起動により有効になる。
ところで、3行目はブリッジへの接続である。 ifconfig.bridge0 と ifconfig.tap0 のうち後に読まれる方にそれを 記述する必要があるが、ifconfig.tap0 が必ず後になるという保証はあるのか?
/etc/rc.d に ipnat=YES を追加する。 また /etc/ipnat.conf に以下のように記述する。:
map ath0 10.0.0.0/8 -> 0.0.0.0/32 portmap tcp/udp 50000:60000
/etc/rc.d/ipnat restart を実行するか再起動により有効になる。
0.0.0.0/32 は ドメイン0 に設定されている(たぶん ath0 の)IPアドレスに 置き換えられるようであるが、マニュアルに書いてなかったの自信ない。 ipnat -l により NAT の設定内容と現在のセッションエントリを確認できる。
仮想インタフェースを生成しブリッジ bridge0 に接続するため、 ドメイン0 上の各ドメインコンフィグファイル(/usr/pkg/etc/xen/dom1 など) の中の vif を以下のように設定する。:
vif = [ 'bridge=bridge0, script=vif-bridge' ]
以下は各ドメインUの中での設定。
NetBSDのドメインU "dom1" では以下のようにする。