Xenネットワーク (続き)

Xenネットワーク クイックレシピ

分からないところがあれば、多分、前項「Xenネットワークの操作とカスタマイズ」を読むと分かるだろう。基本的に、作業前にはすべてのゲストドメインをシャットダウンしておく。また、各例の説明の最後にはマシンを再起動することにしているが、マシンは立ち上げたまま、

root# service xend stop
root# service libvirtd restart
root# service xend start

で代用することができる場合もある。また、非Xenカーネルをインストールしていない場合、dom0 のネットワーク設定を変更するためには、その前にネットワークを仮想ブリッジの状態から実体の状態に戻しておく必要がある。手順をまちとめると、

root# /etc/xen/scripts/network-bridge stop <-- ネットワークインターフェイスの実体化
<-- ここで dom0 のネットワーク設定をいじる -->
root# service network restart  <-- dom0のネットワークの再起動(変更の反映)
root# /etc/xen/scripts/network-bridge start <-- ネットワークインターフェイスの仮想化

ただし、既に /etc/xen/xend-config.sxp ファイルの `(network-script xxxx)' を書き換えている場合は、`network-bridge' のところはそれに合わせて。(基礎知識は「xenbrX の追加と動作の明確化」で確認のこと)

なお、以下、ゲストドメインの定義を libvirt 形式 XMLファイルを使って調整する場合に、例として /etc/xen/xml/ というディレクトリを使用しているが、そんなサブディレクトリはデフォルトでは存在しない。同じにしたければ root 権限で作成しておけばいいが、他の任意の場所でもまったく構わない。

レシピ一覧

単一の単純ブリッジネットワーク

libvirtd の作る、CPU処理能力を浪費するマスカレードスイッチ virbr0 をやめ、マシン内部の仮想ネットワークを単純なひとつのサブネットとして形作る。

カスタマイズ方法も至って単純で、単に (1) xend 側ではゲストドメインそれぞれを xenbr0 につなぎ込ませるように定義を修正し、(2) libvirtd のオートスタートブリッジ "default" を無効にして、両サービスを再起動するかマシン自体をリブートするだけだ。

(1) ゲストドメインの xenbr0 へのつなぎ替え

virt-manager の言いなりで構築したゲストドメインは virbr0 につながっているので、ゲストドメインの定義を修正する。

[xm形式で調整する場合]

例えば、/etc/xen/centos51u ファイルの;

vif = [ "mac=00:16:3e:17:d4:87,bridge=virbr0" ]

という定義行を

vif = [ "mac=00:16:3e:17:d4:87,bridge=xenbr0" ]

に変える。

[libvirt 形式の XMLダンプファイル で調整する場合]

例えば /etc/xen/xml/centos51u.xml で修正するなら、

<interface type='bridge'>
  <mac address='00:16:3e:17:d4:87'/>
  <source bridge='virbr0'/>

という部分を

<interface type='bridge'>
  <mac address='00:16:3e:17:d4:87'/>
  <source bridge='xenbr0'/>

と書き換えて、`virsh define /etc/xen/xml/centos51u.xml' によりドメイン定義プールに上書き登録。

(2) xenbr ブリッジの修正

より確実な xend のブリッジ作成動作を得るため /etc/xen/xend-config.sxp

(network-script network-bridge)

(network-script network-bridge-custom)

に書き換え、/etc/xen/scripts/network-bridge-custom というファイル (パーミション root:root 755) を作る。その内容が下記。この実装方法では IPフォワーディングは最小限に制限したいので、antispoofyes にする;

#!/bin/sh
dir=$(dirname $0)
 
${dir}/network-bridge "$@" vifnum=0 bridge=xenbr0 netdev=eth0 antispoof=yes
(3) "default"ブリッジの停止とオートスタート無効化

どのゲストドメインでも virbr0 を使うつもりがないのなら、virbr0 の自動起動を無効化する。

root# virsh net-destroy default
root# virsh net-autostart default --disable

最後に、マシン自体を再起動し、各ゲストドメイン上で eth0 の IP を適宜設定しなおす。

単純ブリッジと内部専用L2スイッチ

シンプルな単一サブネットの xend ブリッジの他に、敢えて外界とは通信できない内部専用サブネットワークを作る。 libvirt による virbrX はそれ自体がいわば dom0 のダミーインターフェイスなので、次に紹介する dummy0 を別途作成する方法よりも簡単に構築できる。なお、virbr をルータとして作る場合にはゲストOS自体のデフォルトゲートウェイは virbrX (ここでは virbr1) の IPアドレスとするものだが、当設定での virbr はルーティング機能を持たないので、マシンの物理インターフェイス peth0 の外にある本物のゲートウェイを指定することになる。

以下、第1 DomU の定義名が centos51u、第2 DomUcentos51u2 だと仮定して説明する

(1) ゲストドメインの仮想インターフェイス追加とブリッジ先の設定

[xm形式で調整する場合]

/etc/xen/centos51u ファイルの vif 定義行;

vif = [ "mac=00:16:3e:17:d4:87,bridge=xenbr0","mac=00:16:3e:17:d4:88,bridge=virbr1" ]

/etc/xen/centos51u2 ファイルの vif 定義行;

vif = [ "mac=00:16:3e:17:d4:97,bridge=xenbr0","mac=00:16:3e:17:d4:98,bridge=virbr1" ]

[libvirt 形式の XMLダンプファイル で調整する場合]

/etc/xen/xml/centos51u.xml<interface type='bridge'> ブロックを追加;

<interface type='bridge'>
  <mac address='00:16:3e:17:d4:87'/>
  <source bridge='xenbr0'/>
  <script path='vif-bridge'/>
</interface>
<interface type='bridge'>
  <mac address='00:16:3e:17:d4:88'/>
  <source bridge='virbr1'/>
  <script path='vif-bridge'/>
</interface>

/etc/xen/xml/centos51u2.xml<interface type='bridge'> ブロックを追加;

<interface type='bridge'>
  <mac address='00:16:3e:17:d4:97'/>
  <source bridge='xenbr0'/>
  <script path='vif-bridge'/>
</interface>
<interface type='bridge'>
  <mac address='00:16:3e:17:d4:98'/>
  <source bridge='virbr1'/>
  <script path='vif-bridge'/>
</interface>

そして、両 XML ファイルからゲストドメインを再登録;

root# virsh define /etc/xen/xml/centos51u.xml
root# virsh define /etc/xen/xml/centos51u2.xml
(2) xenbr ブリッジの修正

より確実な xend のブリッジ作成動作を得るため /etc/xen/xend-config.sxp

(network-script network-bridge)

(network-script network-bridge-custom)

に書き換え、/etc/xen/scripts/network-bridge-custom というファイル (パーミション root:root 755) を作る。その内容が下記。libvirt がどうしても設定したがる DNS, DHCP がらみのカーネルパケットフィルタがあるのでそのクリーンナップも盛り込む。ただし、antispoof=yes にすると FORWARD チェーンは network-bridge スクリプトが自ずと一旦フラッシュするので、わざわざクリアする必要はない。また、例のように、xenbr が作成された後に、この構成では必要のない IPフォワーディングカーネルパラメータを無効にしてもよい。

#!/bin/sh
dir=$(dirname $0)
libvirtbr=virbr1
 
# Some clean-up of iptables rules inserted by libvirtd.
iptables -D INPUT -i $libvirtbr -p udp -m udp --dport 53 -j ACCEPT &>/dev/null
iptables -D INPUT -i $libvirtbr -p tcp -m tcp --dport 53 -j ACCEPT &>/dev/null
iptables -D INPUT -i $libvirtbr -p udp -m udp --dport 67 -j ACCEPT &>/dev/null
iptables -D INPUT -i $libvirtbr -p tcp -m tcp --dport 67 -j ACCEPT &>/dev/null
 
${dir}/network-bridge "$@" vifnum=0 bridge=xenbr0 netdev=eth0 antispoof=yes

echo 0 >/proc/sys/net/ipv4/ip_forward
network-bridge-custom スクリプトセット (Ver.0.3.0)

前述の「xenbrX 仮想ルータの無駄を省く」なども盛り込んで汎用的なものにしたスクリプトを作った。

  • network-bridge-custom [root:root 755] (スクリプト本体)
  • network-bridge-util [root:root 644] (virbrX の無駄省きやルーティング設定を行うインクルードファイル)
  • virnetinfo.py [root:root 755] (上記 *-util の中で現在の libvirt ブリッジの設定を検出するための pythonスクリプト)
  • /etc/xen/route.conf [root:root 644] (オプション - 記述例)

共通ルーティンを別ファイルに分けたので、使用するには必ず network-bridge-customnetwork-bridge-util/etc/xen/scripts/ に置き、上記のようにパーミションに整える。また、virnetinfo.py を必ず PATH の通った場所 (/usr/local/bin/ など) に置いてほしい。設定や network-bridge 呼び出しの調整は network-bridge-custom の方で行い、それ以外はいじらなくてよい。

最後の route.conf は Linux のルーティングテーブルを設定するためのパラメータファイルで、ルーティング設定が不要ならなくても構わない。このファイルの中身は 、network-bridge-util の中の set_route() ファンクションに引数としてファイルのパスを付けてコールすることよって実行させることができる。使うのなら、route.conf には `ip route' または `ip rule' の後に続くコマンド文字列を並べておく。つまり、書き方は RedHat 系の /etc/sysconfig/network-scripts/route-eth*rule-eth* の古い書き方と同じだ。ただし、もうちょっと便利なように `#' で始まる行と空行は無視されるようにした。

具体的な使い方は、後述の「単純ブリッジとLAN用L3スイッチ(非NATのvirbrX)」のところで触れている。

(virnetinfo.py を使わない古いバージョンはこれ。)

更新履歴  
Ver.0.2.2->0.3.0 libvirt ブリッジ (virbrX ) のセッティングを自動検出するように変更し、そのためのユーティリティスクリプト virnetinfo.py を追加。
Ver.0.2.1->0.2.2: network-bridge-custom のみ好きなパスにシンボリックリンクを作れば、シンボリックリンク経由でも実行できるよう処理を追加。
`network-bridge-custom status' を使用可能に (システムの network-bridgeスクリプト自体が `status' 引数に対応していた場合)。
値のサンプル記述を現実的なものに修正。
(3) 新たな仮想L2スイッチの作成

/etc/virnet/virnet1.xml ファイルをテキストエディタで新規に作成する。

<network>
  <name>virnet1</name>
  <bridge name="virbr1" stp="off" forwardDelay='0' />
  <ip address="192.168.200.1" netmask="255.255.255.0">
  </ip>
</network>
root# virsh net-define /etc/virnet/virnet1.xml
root# virsh net-autostart virnet1
(4) "default"ブリッジの停止とオートスタート無効化

どのゲストドメインでも virbr0 を使うつもりがないのなら、virbr0 の自動起動を無効化する。

root# virsh net-destroy default
root# virsh net-autostart default --disable

最後に、マシン自体を再起動する。そして各ゲストを起動させるのだが、ゲストが RedHat系OS (特に Red Hat Enterprise Linux) の場合は起動途中で kudzu が新しい仮想NIC を発見して「どうするか」と訊いてくることがある。その時は y キーを叩いて eth1 を設定してやりたいので、ドメインの起動は virt-manager から行ったほうがよい。起動したら、各ゲストドメイン上で eth0, eth1 のネットワーク設定ファイル類をきちんと整える。

単純ブリッジと内部専用単純ブリッジ(複数の物理NIC装着時にも応用可能)

これは他の記事でよく目にする構築法だが、構築するのに手間がかかる、ちょっと時代遅れのやり方。実インターフェイスの存在しない xenbr を作らせるためには、あらかじめホストOS上でダミーインターフェイスをデバイスとして作成しておかなければならないからだ。結果的に得られる動作は、構築のラクな前記の「単純ブリッジと内部専用L2スイッチ」と同じだ。

このサンプルは、本当に NIC が 2枚差しのマシンでも、dummy0 を作る過程を省くだけで作業の見本になるはずだ。

第1 DomU の定義名が centos51u、第2 DomUcentos51u2 だと仮定して話を進める。

(1) ホストOS上でのダミーインターフェイス作成

きっぱりとマシンを再起動して、非Xenカーネルで立ち上げる。そしてまず、ホストOS の /etc/modprobe.conf に下記の定義を加える。こういう時のため (だけじゃないが) に dummy.ko というカーネルネットワークモジュールが存在する。

alias dummy0 dummy
options dummy numdummies=1

次に /etc/sysconfig/network-scripts/ifcfg-dummy0 ファイルを下記の要領で作成する。MACADDR の値は、 00:00:00:00:00:00 などにしてしまうと eth1 を通じたゲストドメインと dom0 との通信が成り立たない。実在の機器の MACアドレスとぶつからないよう、xenmacgen.py スクリプトを使ってランダムに発生させた XenSource 管轄範囲のアドレスを使用するといいだろう。

DEVICE=dummy0
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.200.1
NETMASK=255.255.255.0
MACADDR=00:16:3e:6f:5c:17
USERCTL=no
IPV6INIT=no
PEERDNS=no

インターフェイスが立ち上がることを確認する;

root# ifup dummy0
root# ifconfig dummy0
(2) xenbr ブリッジの追加定義

引き続き非XenカーネルのホストOS上で行う。 /etc/xen/xend-config.sxp

(network-script network-bridge)

(network-script network-bridge-custom)

に書き換え、/etc/xen/scripts/network-bridge-custom というファイル (パーミション root:root 755) を作る。内容が下記。この実装方法では IPフォワーディングは最小限に制限したいので antispoofyes にする。また、例のように、xenbr が作成された後に、この構成では不要の IPフォワーディングカーネルパラメータを無効にしてもよい。

#!/bin/sh
dir=$(dirname $0)
 
${dir}/network-bridge "$@" vifnum=0 bridge=xenbr0 netdev=eth0 antispoof=yes
${dir}/network-bridge "$@" vifnum=1 bridge=xenbr1 netdev=dummy0 antispoof=yes

echo 0 >/proc/sys/net/ipv4/ip_forward
(3) ゲストドメインの仮想インターフェイス追加とブリッジ先の設定

[xm形式で調整する場合]

/etc/xen/centos51u ファイルの vif 定義行;

vif = [ "mac=00:16:3e:17:d4:87,bridge=xenbr0","mac=00:16:3e:17:d4:88,bridge=xenbr1" ]

/etc/xen/centos51u2 ファイルの vif 定義行;

vif = [ "mac=00:16:3e:17:d4:97,bridge=xenbr0","mac=00:16:3e:17:d4:98,bridge=xenbr1" ]

[libvirt 形式の XMLダンプファイル で調整する場合]

/etc/xen/xml/centos51u.xml<interface type='bridge'> ブロックを追加;

<interface type='bridge'>
  <mac address='00:16:3e:17:d4:87'/>
  <source bridge='xenbr0'/>
  <script path='vif-bridge'/>
</interface>
<interface type='bridge'>
  <mac address='00:16:3e:17:d4:88'/>
  <source bridge='xenbr1'/>
  <script path='vif-bridge'/>
</interface>

/etc/xen/xml/centos51u2.xml<interface type='bridge'> ブロックを追加;

<interface type='bridge'>
  <mac address='00:16:3e:17:d4:97'/>
  <source bridge='xenbr0'/>
  <script path='vif-bridge'/>
</interface>
<interface type='bridge'>
  <mac address='00:16:3e:17:d4:98'/>
  <source bridge='xenbr1'/>
  <script path='vif-bridge'/>
</interface>

両 XML ファイルからゲストドメインを再登録;

root# virsh define /etc/xen/xml/centos51u.xml
root# virsh define /etc/xen/xml/centos51u2.xml
(4) "default"ブリッジの停止とオートスタート無効化

どのゲストドメインでも virbr0 を使うつもりがないのなら、virbr0 の自動起動を無効化する。

root# virsh net-destroy default
root# virsh net-autostart default --disable

仕上げにマシン自体を再起動する。今度はもちろん Xenカーネルで立ち上げる。そして各ゲストを起動させるのだが、ゲストが RedHat系OS の場合 (特に Red Hat Enterprise Linux) は、起動途中で kudzu が新しい仮想NIC を発見して「どうするか」と訊いてくることがある。その時に y キーなどを叩いて eth1 を設定してやれるよう、ドメインの起動は virt-manager から行ったほうがよい。起動したら、各ゲストドメイン上で eth0, eth1 のネットワーク設定ファイル類をきちんと整える。

bondingインターフェイスの単純ブリッジと通常の単純ブリッジ

bonding によって冗長化した dom0 のネットワークインターフェイスを、単純ブリッジとしてゲストドメインに提供する。せっかくなので、ここでは物理マシンに NIC が 3つ装備されていると仮定し、eth0eth2 との bonding インターフェイス bond0 をメイン仮想ブリッジ、単体の eth1 をサブ的なブリッジ (いわば裏LAN) としてゲストに提供するシナリオにする。

第1 DomU の定義名が centos51u、第2 DomUcentos51u2 だと仮定して話を進める。

ホストOS 上での bonding インターフェイス作成については、ここでは細かく触れない。kernel-doc パッケージをインストールするとコピーされる /usr/share/doc/kernel-doc-x.x.x/Documentation/networking/bonding.txt を読むといいだろう。ここにも、CentOS 5.3 (kernel-2.6.18-164.el5) の bonding.txt のコピーを置いておく。

(1) ホストOS上でのbondingインターフェイス作成

きっぱりとマシンを再起動して、非Xenカーネルで立ち上げる。そして、bonding インターフェイスを作成、設定しておく。

(2) bond0 ブリッジの追加定義

引き続き非XenカーネルのホストOS上で行う。 /etc/xen/xend-config.sxp

(network-script network-bridge)

(network-script network-bridge-custom)

に書き換え、/etc/xen/scripts/network-bridge-custom というファイル (パーミション root:root 755) を作る。内容が下記。この実装方法では IPフォワーディングは最小限に制限したいので antispoofyes にする。また、例のように、Xenブリッジが作成された後に、この構成では不要の IPフォワーディングカーネルパラメータを無効にしてもよい。

#!/bin/sh
dir=$(dirname $0)
 
${dir}/network-bridge-bonding "$@" bridge=bond0 netdev=bond0 antispoof=yes
${dir}/network-bridge "$@" bridge=xenbr0 netdev=eth1 antispoof=yes

echo 0 >/proc/sys/net/ipv4/ip_forward
(3) ゲストドメインの仮想インターフェイス追加とブリッジ先の設定

[xm形式で調整する場合]

/etc/xen/centos51u ファイルの vif 定義行;

vif = [ "mac=00:16:3e:17:d4:87,bridge=bond0","mac=00:16:3e:17:d4:88,bridge=xenbr0" ]

/etc/xen/centos51u2 ファイルの vif 定義行;

vif = [ "mac=00:16:3e:17:d4:97,bridge=bond0","mac=00:16:3e:17:d4:98,bridge=xenbr0" ]

[libvirt 形式の XMLダンプファイル で調整する場合]

/etc/xen/xml/centos51u.xml<interface type='bridge'> ブロックを追加;

<interface type='bridge'>
  <mac address='00:16:3e:17:d4:87'/>
  <source bridge='bond0'/>
  <script path='vif-bridge'/>
</interface>
<interface type='bridge'>
  <mac address='00:16:3e:17:d4:88'/>
  <source bridge='xenbr0'/>
  <script path='vif-bridge'/>
</interface>

/etc/xen/xml/centos51u2.xml<interface type='bridge'> ブロックを追加;

<interface type='bridge'>
  <mac address='00:16:3e:17:d4:97'/>
  <source bridge='bond0'/>
  <script path='vif-bridge'/>
</interface>
<interface type='bridge'>
  <mac address='00:16:3e:17:d4:98'/>
  <source bridge='xenbr0'/>
  <script path='vif-bridge'/>
</interface>

両 XML ファイルからゲストドメインを再登録;

root# virsh define /etc/xen/xml/centos51u.xml
root# virsh define /etc/xen/xml/centos51u2.xml
(4) "default"ブリッジの停止とオートスタート無効化

どのゲストドメインでも virbr0 を使うつもりがないのなら、virbr0 の自動起動を無効化する。

root# virsh net-destroy default
root# virsh net-autostart default --disable

仕上げにマシン自体を再起動する。今度はもちろん Xenカーネルで立ち上げる。そして各ゲストを起動させるのだが、ゲストが RedHat系OS の場合 (特に Red Hat Enterprise Linux) は、起動途中で kudzu が新しい仮想NIC を発見して「どうするか」と訊いてくることがある。その時に y キーなどを叩いて eth1 を設定してやれるよう、ドメインの起動は virt-manager から行ったほうがよい。起動したら、各ゲストドメイン上で eth0, eth1 のネットワーク設定ファイル類をきちんと整える。

単純ブリッジとLAN用L3スイッチ(非NATのvirbrX)

下図のような構造を実現する。構築はかなり面倒くさいが、それだけの価値はある。まずはとにかく図を見ていただこう。これは Fedora Core 8 を dom0 にしたものなので、RHEL/CentOS 5.x をホストOS にする場合は eth0xenbr0 に読み替えるなどしていただきたい。

実マシンには NIC がふたつある。第1 NIC はインターネットへのゲートウェイになっている NAT ルータにつながり、第2 NIC は内部 LAN の諸セグメントとのルーティングを行う非NAT ルータ (現実的には L3 スイッチ等) につながっているとする。

dom0eth0 (RHEL/CentOS 5.x では xenbr0) は Xennetwork-bridge によって作り、virbr0libvirt を使って作る。

virbr0NAT ルータにしてしまえば構築は非常にラクだが、そもそも NAT ルータには、送信元アドレスが化ける という欠点がある。図の `To/From other segments' の向こう側にいるサーバなりクライアントなりが centos51u の例えば HTTPD にアクセスしてきた場合、centos51u のログには全て「192.168.122.1 からのアクセス」として記録されてしまうのだ。それではログの用を成さない。また、iptables なりでアクセス制限を掛けようとする際にも困る。そこで、virbr0 は非NAT のルータ (L3スイッチ) として生成し、 dom0 内でルーティングテーブルを操って dom0Linux ルータ として機能させようという仕業だ。上図の [FORWARD] で示した点線からも分かるように、ゲストドメインの eth0eth1 とでは用途を分離し、下記のようなアクセス規則となることを目指す;

dom0のIF   domUのIF 通信可否
eth0 <--> eth0 可能
eth0 <--> eth1 不能
eth1 <--> eth0 不能
eth1 <--> eth1 可能

Xen ドメインのデフォルトゲートウェイは以下のように定義することにする。DomU#N として示したゲストドメインは、ゲストドメイン centos51u と同様に拡張可能という意味で付け加えたにすぎず、説明からは省く;

ドメイン Default GW 各ドメインにとっての GW Dev
dom0 192.168.1.254 eth0
centos51u 192.168.1.254 eth0

ただでさえ話が込み入っているので、少しでも単純化するため、筆者の作成した network-bridge-custom セットをベースに説明を進める。
当例に則った作成済みセット+設定ファイル類:

(1) virbr0 の作成 (virnet0.xml)

肝心なのは <forward> ブロックの mode 属性 (バージョンによっては `type')。

<forward mode='route' dev='eth1'/>

これによって、virbr0NAT ルータでなく、いわゆる L3スイッチとなる。より正確に言うと、ブリッジの素性は mode='nat' の時と違いがあるわけではないのだが、生成時に iptablesMASQUERADE ルールが登録されず、eth1 <--> virbr0FORWARDACCEPT ルールだけが登録されるようになる。ファイルが作成できたら、定義プールに登録 (あるいは再登録) するとともに、libvirtd 起動時に自動的に生成されるようにする。

既に virbr0 (virnet0) が稼働している場合はまず

root# virsh net-destroy virnet0

を行ってから、

root# virsh net-define /etc/virnet/virnet0.xml
root# virsh net-autostart virnet0
(2) domU 定義ファイル (centos51u.xml)

domU 定義ファイル centos51u.xml/etc/xen/xml/ (ディレクトリパスは任意) に作る。肝心なのはふたつの <interface> ブロック。

<interface type='bridge'>        <--WAN用インターフェイス生成ブロック
  <source bridge='eth0'/>
  <mac address='00:16:3e:5c:00:26'/>
  <script path='/etc/xen/scripts/vif-bridge'/>
</interface>
<interface type='bridge'>        <--LAN用インターフェイス生成ブロック
  <source bridge='virbr0'/>
  <mac address='00:16:3e:56:b2:5a'/>
  <script path='/etc/xen/scripts/vif-bridge'/>
</interface>

LAN用インターフェイスのほうも <script>path 属性は vif-bridge にする。vif-route にすると、幾つかのルーティングテーブルエントリ (未解析...) が登録されるとともに、sysctl の値 /proc/sys/net/ipv4/conf/vif1.1/proxy_arp1 にセットされるが、有効にしたところでルーティング設定が極めて単純になるというわけでもないので、 vif-bridge にしておいたほうがすっきりする。proxy_arp の説明はこの後の 「(3-2) dom0のルーティング設定」参照。

定義ファイルが完成したら、ドメイン定義プールに登録する;

root# virsh define /etc/xen/xml/centos51u.xml
(3-1) network-bridge-customセット - 主スクリプト

network-bridge-custom の内容を項目ごとに順を追って説明しよう。

function do_bridge () {
    ## This is the very heart of network-bridge script.
    ${dir}/network-bridge "$@" bridge=eth0 netdev=eth0 antispoof=no
}

network-bridge-custom の最も中心的な仕事がこれ。xend ブリッジの作成だ。bridge= は RHEL/CentOS 5.x では xenbr0 を指定しなければならない。各ブリッジは自ホスト発でないパケットも扱うことになるため antispoofno

disable_ipfwd

/proc/sys/net/ipv4/ip_forward の値を `0' にするルーティン。 今回はもちろん `1' のままになっていなければならないが、このファンクションは mode=nat または mode=routelibvirt ブリッジが存在する場合は発動されないので、特にコメントアウトする必要はない。

"# Additional routing configuration" のセクションは次項にて。

(3-2) dom0 のルーティング設定 (route.conf)

network-bridge-custom

set_route /etc/xen/route.conf

によって、/etc/xen/route.conf ファイルが set_route() ファンクションに読み取られてルーティングテーブルが設定される (set_route()network-bridge-util の中で定義してあるシェルファンクション)。見てもらえば分かるように、route.conf に並べてあるのは iproute2 のコマンド `ip route replace' または `ip rule add' の後ろに嵌め込むコマンド文字列だ。この構築例での route.conf は、パケットの送信元ネットワーク毎のルーティングテーブル (wanside, lanside, virside の 3つ) を作って、それぞれの中にパケットの宛先毎のルーティング規則を登録している。

Linux のルーティング操作に馴染みのない人は "Linux Advanced Routing & Traffic Control HOWTO" の 第4章 だけでも読んでおくといいだろう。JF に日本語訳もある。

route.conf に書いてある引数が `ip route' の引数なのか `ip rule' の引数なのかを調べる条件式 (network-bridge-util の中) は、筆者が自分で使うであろうコマンドやその記述慣習に基づいたもので、使用するコマンドやパラメータの書き方の癖によっては合わないかもしれない。set_route() ファンクションの条件部分を適宜調整してほしい。

ルーティング設定は /etc/sysconfig/network-scripts/route-<IF_NAME> ファイルや rule-<IF_NAME> に書いておく方法もあるが、それらが実行されるシステム起動時には virbrX はまだ存在しないということをお忘れなく。

dom0 によるネットワークトラフィックの扱いには、sysctl のネットワーク関連カーネルパラメータも関係してくる。そのひとつが、network-bridge-custom の最後に書いてある次の行だ;

sysctl -w net.ipv4.conf.eth1.rp_filter=1 &>/dev/null

ここで eth1 に対して有効にしている rp_filter (Reverse Patch filter ) パラメータは、実際のパケットの送信元アドレスがルーティングテーブルに定義してあるネットワークインターフェイスとその取り扱いアドレスにきちんと合致し、なお且つこちらからの返答パケットがその同じインターフェイスから出て行くことが妥当かどうか検査し、合致しなければパケットを破棄するというもの。Oskar Andreasson の Ipsysctl Tutorial に解説されている。dom0 のルーティングに大きく関係する sysctl 変数には、この他に、少なくとも以下のものがある。(<IF_NAME> は `eth0' のようなそれぞれのインターフェイスデバイス名を指す);

net.ipv4.ip_forward
カーネルのパケットフォワーディング機能の有効/無効。当構築例では少なくとも eth1 <--> virbr0 のパケットの橋渡しが行われる必要があるので、有効 (`1') でなければならない。virbrXnatroute モードで作れば libvirtd が自動的に `1' にする。
net.ipv4.conf.<IF_NAME>.proxy_arp
proxy_arp (代理APR回答) が有効になっていると、幾つか先にあるホストやゲートウェイの MAC アドレスを Linux の ARP テーブルキャッシュが既に知っている時、例えば vif1.1 が、あたかもその MAC アドレスを持っているかのように ARP リクエストに対して「それはオレだよ。そのパケットはオレによこしなよ」と手を挙げる。Ipsysctl Tutorial では この節 に説明がある。
net.ipv4.conf.<IF_NAME>.accept_redirects
ICMP のリダイレクト応答に従うかどうか。これについては Ipatables チュートリアルの中の説明が分かりやすかったので引用する:
ICMP リダイレクト パケットが使用されるケースはひとつしかない。こういう場合を考えてみよう。ここに、何台かのクライアントやサーバとふたつのゲートウェイを持つネットワーク (192.168.0.0/24) があるとする。ゲートウェイのひとつは 10.0.0.0/24 のネットワーク、もうひとつのゲートウェイはその他のインターネット全般へつながっている。さてここで、 192.168.0.0/24 内に、デフォルトゲートウエイは知っているが 10.0.0.0/24 へのルートを知らない 1台のホストがあったとしよう。そのホストはパケットをデフォルトゲートウェイへ送る。デフォルトゲートウエイは当然 10.0.0.0/24 ネットワークの存在を知っている。デフォルトゲートウエイは、そのパケットはどうせ 10.0.0.0/24 のインターフェイスから出入りすることになるのだから、直接 10.0.0.0/24 用のゲートウェイへ送ったほうが早いと判断することができる。そこでデフォルトゲートウエイは、正しいゲートウェイを知らせる ICMP リダイレクトパケットをホストへと送り、パケットは 10.0.0.0/24 のゲートウェイへ渡す。これによって先ほどのホストは 10.0.0.0/24 ゲートウェイという近道を知るので、次回からはもしかするとそちらを使うようになるかもしれないというわけだ。」

Fedora Core 8 で調べたところ、accept_redirects は全てのインターフェイスで有効 (`1') になっていた。これはこれでいいのだが、近くのルータの向こう側のホストやネットワークが信頼できない環境では、悪意を持って恣意的なリダイレクト応答を返してくるノードがあるかもしれない。そういった環境では、accept_redirects を `0' にするか、ICMP リダイレクトパケットの送信元を限定するような iptables ルールを併用したほうがいいだろう。リダイレクトパケットの ICMP Type番号は 5 だ。つまり、例えば 192.168.0.0/24 からのリダイレクトパケットだけを受け入れるようにするには、

-A INPUT -p icmp --icmp-type 5 -s 192.168.0.0/24 -j ACCEPT
-A INPUT -p icmp --icmp-type 5 -j DROP

といったルールを設定すればいいだろう。ただし、ESTABLISHED, RELATED なパケットを許可するルールがある場合には、それよりも前に置いておかなければ意味がない。

値を設定するには、例の rp_filter のように network-bridge-custom に書くか、/etc/sysctl.conf に書いておく。 ちなみに、proxy_arpaccept_redirects の値をインターフェイス毎にひとつひとつ調べるのは面倒くさいが、下記のようにコマンドすればいっぺんに分かる;

root# grep [0-9] /proc/sys/net/ipv4/conf/*/proxy_arp

もうひとつ、事前に必ずやっておかなければならないことがある。ルーティングテーブルの入れ物を作っておく作業だ。当設定例においては、以下の行を /etc/iproute2/rt_tables ファイルに追加しておく。ただし ID番号はこの通りである必要はない;

100    wanside
101    lanside
102    virside

ここまでの作業を全てやり終えたら、ホストマシンを一旦リブートする。ホストOS が再び立ち上がり libvirtdxend が活性化された後には、Xen ブリッジ eth0 (または xenbr0) と libvirt ブリッジ virbr0 ができ、必要なルーティングテーブルも出来上がっているはずだ。当例に関係のあるルーティングテーブルを確認するためのコマンドは;

root# ip route show
root# ip rule show
root# ip route list table wanside
root# ip route list table lanside
root# ip route list table virside
(3-3) domU のルーティング設定

最初の図解のところで示した通り、ゲストドメイン centos51u 自体のデフォルトゲートウェイは WAN側ルータを向いている。そうでなくデフォルトゲートウェイを virbr0 (192.168.122.1) にしている場合、この作業は不要だ。

設定は簡単。そのゲストドメインがオートスタートになっていない場合は `virsh start centos51u' などで立ち上げておく。そしてゲストドメインに仮想コンソールでログイン;

root# virsh console centos51u

そうしたら、ゲストドメイン自体の /etc/sysconfig/network-scripts/route-eth1 ファイル (root:root 644) を、下記の内容で作成する;

192.168.0.0/24 dev eth1 via 192.168.122.1

設定を反映するため、ゲストドメイン上で `service network restart' でネットワークだけを再起動するか、そのゲストドメインをリブートする。

(4) LAN側 物理スイッチへのルーティング追加

の左上の [LAN Switch] にあたるものには、「ゲストドメイン (192.168.122.0/24) へ行くには 192.168.0.3 (dom0eth1) をゲートウェイにせよ」というルーティングエントリが必要だ。今スイッチがなく、暫定的に単独の Linux PC で試してみたければ、その試験PC をハブ等で Xen物理マシンの eth1 と接続しておき、試験PC に下記のようにしてルートを追加してやればいい;

root# ip route add 192.168.122.0/24 via 192.168.0.3