GNU/LinuxホストにおけるSun xVM VirtualBoxのブリッジ接続の設定を見直し
以前、GNU/LinuxホストにおけるSun xVM VirtualBoxでのブリッジ接続を試して「VERR_HOSTIF_INIT_FAILED」のエラーが出たときに、「TUN/TAPのカーネルモジュールのソースを一部修正する」という、あまりよくない方法で問題を回避していたが、その後Gentoo LinuxからMandriva Linuxに乗り換えた後もこのエラーが出てしまい、カーネルをビルドするのも(Gentooではないため)色々面倒のもとになるため、付属マニュアルや他の備忘録などを参考にして試したところ、この修正をせずにブリッジ接続することは可能ということが分かった。
(2008/12/19)Sun xVM VirtualBoxのバージョン2.1.0からブリッジ接続が簡単になっている。「Sun xVM VirtualBoxの覚え書き(2008/12/19現在)」を参照。以下の内容はそれ未満のバージョンを対象としている。
一般ユーザでTUN/TAPを使用するための追加設定
ブリッジの作成・設定後にVBoxAddIFというコマンドを用いてsudo VBoxAddIF [TUN/TAPインターフェース名] $(whoami) [ブリッジ名]
のようにして一般ユーザがTUN/TAPデバイスを通じてブリッジを使用して通信できるように許可をする。ただ、仮想マシン設定のネットワークデバイス設定の「設定アプリケーション」などにこの記述を含んだシェルスクリプトを指定しても動かなかった。*1そのときのログは以下のようになった。
00:00:56.292 VirtualBox 2.0.4 r38406 linux.amd64 (Oct 23 2008 21:56:58) release log 00:00:56.292 Log opened 2008-11-12T11:29:42.893307000Z 00:00:56.292 OS Product: Linux 00:00:56.292 OS Release: 2.6.27.4-desktop-2mnb 00:00:56.292 OS Version: #1 SMP Thu Nov 6 13:36:39 EST 2008 00:00:56.292 Package type: LINUX_64BITS_GENERIC 00:00:56.462 SUP: Loaded VMMR0.r0 (/opt/VirtualBox-2.0.4/VMMR0.r0) at 0xffffffffa0f03b20 - ModuleInit at ffffffffa0f0fa00 and ModuleTerm at ffffffffa0f0fa60 00:00:56.462 SUP: VMMR0EntryEx located at ffffffffa0f103c0, VMMR0EntryFast at ffffffffa0f0fb00 and VMMR0EntryInt at ffffffffa0f0faf0 00:00:56.534 Failed to open the host network interface vbox0 00:00:56.534 ERROR [COM]: aRC=NS_ERROR_FAILURE (0x80004005) aIID={e3c6d4a1-a935-47ca-b16d-f9e9c496e53e} aComponent={Console} aText={Failed to open the host network interface vbox0} aWarning=false, preserve=false 00:00:56.537 ERROR [COM]: aRC=NS_ERROR_FAILURE (0x80004005) aIID={e3c6d4a1-a935-47ca-b16d-f9e9c496e53e} aComponent={Console} aText={Failed to initialize Host Interface Networking. 00:00:56.537 VBox status code: -3100 (VERR_HOSTIF_INIT_FAILED)} aWarning=false, preserve=false 00:00:56.553 Power up failed (vrc=VERR_HOSTIF_INIT_FAILED, hrc=NS_ERROR_FAILURE (0X80004005))
そのため、事前に個別のTUN/TAPインターフェースに対して許可するようにこのコマンドを実行しておく必要があった。実際には後述のスクリプトの中で実行している。
結局、2つの設定アプリケーションの欄は空にすることに。
準備と後始末を支援するスクリプトを書き直し
下のスクリプトは、以前書いたものと同様、ディストリのネットワーク設定を変更せずに一時的にSun xVM VirtualBoxでブリッジ接続ができるような状態に切り替えるためのもので、元に戻すこともできる。以前から変更した点は- スクリプト中の変数に設定を書かないで処理する方針
- 一般ユーザでTUN/TAPを使用するための処理を含めた(デバイスは「vbox[数字]」・複数*2可)
- 「eth0」などの元のインターフェース名をファイルに保存し、戻すときに使用する形にすることで、自動で名前を処理
- 一度開始(ブリッジに切り替え)したら次に実行したときには停止(ブリッジから元のインターフェースに戻す)し、「start」「stop」の指定は不要にした
- エラーになったときにどこで失敗したのかが分かるようにする
- DHCP使用時にクライアント(dhclientとdhcpcd)を検出して設定
など。getoptsを使用しているため、bash向け。
[任意]ファイル名: ~/bin/virtualbox-bridge-support.sh
#! /bin/bash ## virtualbox-bridge-support.sh ## Sun xVM VirtualBoxでブリッジ接続を使用する準備と後始末を行うスクリプト ## GNU/Linuxホスト・OS起動時にブリッジを使用しない使い方向け ## (ディストリのネットワーク設定は変更しない) ## (C) 2008 kakurasan ## ライセンス: GPL-3 PATH=/bin:/sbin:/usr/bin:/usr/sbin IFACEFILE=~/.VirtualBox/original_interface MODULES='tun bridge vboxdrv' usage() { ## 使用法表示 printf "Usage: %s ( [OPTION...] ) -b [bridge] Use [bridge] as bridge interface name (default br0) -h Print this help -m [mod1,mod2, ...] Load additional kernel module(s) -t [num] Set number of TUN/TAP interface (default 1)\n" $(basename ${0}) exit 0 } die() { ## エラー表示 echo "ERROR: "${1} >&2 exit 1 } start() { local i mod local orig_iface=$(netstat -rn | awk '/^0\.0\.0\.0/ { print $NF }') local ip_address=$(ifconfig ${orig_iface} | head -n 2 | tail -n 1 | cut -f 2 -d : | cut -f 1 -d \ ) local broadcast=$(ifconfig ${orig_iface} | head -n 2 | tail -n 1 | cut -f 3 -d : | cut -f 1 -d \ ) local net_mask=$(ifconfig ${orig_iface} | head -n 2 | tail -n 1 | cut -f 4 -d : | cut -f 1 -d \ ) local ifacefiledir=$(dirname ${IFACEFILE}) ## 必要なモジュールを読み込む for mod in ${MODULES}; do sudo modprobe -q ${mod} || die "Cannot load module \"${mod}\"" done ## 元のインターフェース名を保存するディレクトリ mkdir -p ${ifacefiledir} || die "Cannot create directory \"${ifacefiledir}\"" ## インターフェース名をファイルに書き出して保存 echo ${orig_iface} > ${IFACEFILE} || die "Cannot save network interface name to \"${IFACEFILE}\"" ## ブリッジの作成 sudo brctl addbr ${BRIDGE_IFACE} || die "Cannot create bridge \"${BRIDGE_IFACE}\"" ## ブリッジの設定 sudo brctl stp ${BRIDGE_IFACE} off || die "Cannot turn off Spanning-Tree Protocol" ## 元のインターフェースのIPアドレス割り当てを解除 sudo ifconfig ${orig_iface} 0.0.0.0 || die "Cannot unset IP address (${orig_iface})" ## ブリッジに元のインターフェースを追加 sudo brctl addif ${BRIDGE_IFACE} ${orig_iface} || die "Cannot add \"${orig_iface}\" to \"${BRIDGE_IFACE}\"" ## ブリッジにIPアドレスなどを設定して有効にする if [[ ${USE_DHCP} -eq 0 ]]; then sudo ifconfig ${BRIDGE_IFACE} ${ip_address} broadcast ${broadcast} netmask ${net_mask} up || die "Cannot up \"${BRIDGE_IFACE}\"" sudo route add default gw ${DEFAULT_GW} || die "Cannot set default gw (${DEFAULT_GW})" else ## IPアドレスの解放 sudo ${DHCP_CLIENT} ${RELEASE_OPT} ${orig_iface} || die "Cannot release IP address" ## 新しいインターフェースで取得 sudo ${DHCP_CLIENT} ${BRIDGE_IFACE} || die "\"${DHCP_CLIENT} ${BRIDGE_IFACE}\" failed" fi ## ユーザへの許可 for ((i=0; i<${NUM_TAP}; i++)); do sudo VBoxAddIF vbox${i} $(whoami) ${BRIDGE_IFACE} done } stop() { local i local orig_iface=$(cat ${IFACEFILE}) local bridge_iface=$(netstat -rn | awk '/^0\.0\.0\.0/ { print $NF }') local ip_address=$(ifconfig ${bridge_iface} | head -n 2 | tail -n 1 | cut -f 2 -d : | cut -f 1 -d \ ) local broadcast=$(ifconfig ${bridge_iface} | head -n 2 | tail -n 1 | cut -f 3 -d : | cut -f 1 -d \ ) local net_mask=$(ifconfig ${bridge_iface} | head -n 2 | tail -n 1 | cut -f 4 -d : | cut -f 1 -d \ ) ## ユーザへの許可を削除 local num_tap=$(ifconfig | egrep "vbox[0-9]+" | wc -l) for ((i=0; i<${num_tap}; i++)); do sudo VBoxDeleteIF vbox${i} done ## ブリッジを無効にする sudo ifconfig ${bridge_iface} down || die "Cannot down \"${bridge_iface}\"" ## ブリッジから元のインターフェースを削除 sudo brctl delif ${bridge_iface} ${orig_iface} || die "Cannot delete \"${orig_iface}\" from \"${bridge_iface}\"" if [ ${USE_DHCP} -eq 1 ]; then ## IPアドレスの解放 sudo ${DHCP_CLIENT} ${RELEASE_OPT} ${bridge_iface} || die "Cannot release IP address" fi ## ブリッジを削除 sudo brctl delbr ${bridge_iface} || die "Cannot delete \"${bridge_iface}\"" ## インターフェースを再設定 if [ ${USE_DHCP} -eq 0 ]; then sudo ifconfig ${orig_iface} ${ip_address} broadcast ${broadcast} netmask ${net_mask} || die "Cannot setup \"${bridge_iface}\"" sudo route add default gw ${DEFAULT_GW} || die "Cannot set default gw (${DEFAULT_GW})" else ## 新しいインターフェースで取得 sudo ${DHCP_CLIENT} ${orig_iface} || die "\"${DHCP_CLIENT} ${orig_iface}\" failed" fi ## モジュールを削除 sudo modprobe -qr ${MODULES_LIST} ## 元のインターフェース名を保存したファイルを削除 rm ${IFACEFILE} -f } ## 以下メイン処理 ## 引数の処理 NUM_TAP=1 BRIDGE_IFACE=br0 while getopts 'b:dht:m:' OPT do case ${OPT} in b) BRIDGE_IFACE=${OPTARG} ;; t) if echo ${OPTARG} | egrep "^[0-9]+$" > /dev/null; then NUM_TAP=${OPTARG} else die "Invalid number of TUN/TAP devices" fi ;; m) ## 引数で指定されたコンマ区切りの追加モジュール名をスペース区切りにして追加 MODULES="${MODULES} $(echo ${OPTARG} | tr , ' ')" ;; ?) usage ;; esac done shift $((${OPTIND} - 1)) ## DHCPクライアントのチェック USE_DHCP=0 if pgrep "^dhcpcd$" >/dev/null; then USE_DHCP=1 DHCP_CLIENT=dhcpcd RELEASE_OPT="-k" elif pgrep "^dhclient$" >/dev/null; then USE_DHCP=1 DHCP_CLIENT=dhclient RELEASE_OPT="-r" fi ## デフォルトゲートウェイの一時保存 DEFAULT_GW=$(route | grep default | awk -F\ '{printf $2}') ## インターフェース名の書き出されたファイルがなければ開始、あれば停止とする if [[ ! -f ${IFACEFILE} ]]; then start else stop fi ## EOF
(2008/11/13)DHCP関係の処理などを修正
Mandriva Linux 2009.0でのメモ
パッケージ
以前と同様で、以下のパッケージが必要。- bridge-utils(必須)
- sudo(上のスクリプトで使用)
TUN/TAP
Mandriva Linux 2009.0ではグループ「tun」のメンバは/dev/net/tunへ書き込む権限を持つので、「archivemountのMandriva Linux向けRPMパッケージを作成」の後半に書いた要領で、このグループに通常のユーザを追加しておく。更に「vboxusers」グループにも追加しておく必要がある。sudo
基本的な設定をした上で、下のように設定すると、グループ「vboxusers」のメンバが上のスクリプト中で管理者権限で使用する必要のあるコマンド群をパスワードなしで実行できるようになる。(略) # Cmnd alias specification Cmnd_Alias TUNTAP_BRIDGE=/sbin/modprobe, \ /sbin/ifconfig, \ /sbin/route, \ /sbin/dhclient, \ /sbin/dhcpcd, \ /usr/bin/VBoxTunctl, \ /usr/bin/VBoxAddIF, \ /usr/bin/VBoxDeleteIF, \ /usr/sbin/brctl (中略) %vboxusers ALL = NOPASSWD: TUNTAP_BRIDGE (以下略)
使用したバージョン:
- Sun xVM VirtualBox 2.0.4