一般的な使い方では、自分の IP アドレスは MAC アドレス 1 つと対応している。Ethernet の普通の使い方では、そのアドレスについてだけ効率よく情報処理してれば、それでよい。
ところが色々な理由により、自分自身に初期設定される MAC アドレス以外のアドレスも扱えたほうが便利なケースが出てくる。すると先ほどの「MAC アドレス 1 つだけ」という限定を解除できると便利だし、できるようになっている。これは promiscuous mode と呼ばれる。
最近の NIC は、これまた様々な理由により、結果的に MAC アドレスは起動時に読みだして設定して使っているものが多い。この手の NIC はドライバの機能で、後から OS 側から別の MAC アドレスを設定できるようになっていたりする。大昔の NIC には、設定できないものもあったらしい。
新しい MAC アドレスで通信できるようにしたい、という要求には、どうやら情報がごっちゃになって理解されて、promiscuous mode でなければならないと思われている場合がある様子。確かに promiscuous にすればパケット送受信はできるけれど、普通の今どきの NIC なら MAC アドレスを再設定するだけで大丈夫。
Vagrant / VirtualBox
ネットワークまわりの構成デモに Vagrant を使うケースが結構ある。例えばこんな感じに。
Vagrant.configure("2") do |config|
config.vm.box = "minimal/xenial64"
config.vm.synced_folder ".", "/vagrant", disabled:true
config.vm.define :box1 do |node|
node.vm.network "private_network", ip: "192.168.5.1", virtualbox__intnet: "A"
node.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"]
end
end
config.vm.define :box2 do |node|
node.vm.network "private_network", ip: "192.168.5.2", virtualbox__intnet: "A"
node.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"]
end
end
end
vagrant 用語の virtualbox__intnet
は、virtualbox の internal network に対応している。この internal network が予想の斜め上に機能がついているので、注意が必要。独自の機能として、「未知の MAC アドレスは通さない」という制御機能がデフォルトで有効。これは上記で設定している nicpromisc
で制御できて、allow-all
にすれば、一般的な Ethernet switch のように任意の MAC アドレスが通るようになる。
何も指定しなければ e1000
互換仕様の仮想 NIC が準備される。これは MAC アドレスを再設定できる。ところが MAC アドレスを再設定すると、ineternal network はパケットを遮断する。理由は後述。これは一般的な動作とは異なるので大変混乱する。
さらに続けて NIC を promiscuous mode にすると、新しい MAC アドレスで通信できるようになる。ここで 2 回目の混乱をする。
原因
virtualbox の internal network は、仮想 NIC のアドレスが一致しているかどうか、あるいは promiscuous mode になっているかどうか、を判断基準にしてパケットを通すかどうかを決めている。ここまではいい。
困ったことに guest OS 側で NIC の MAC アドレスを再設定しても hypervisor 側にそれが伝わらないようになっている。ものすごく具体的に言うと、virtualbox のソースコードで PDMINETWORKUP
に MAC アドレスの変更を伝えるインターフェースが無い。
ip link set eth0 promisc on
は promisc
を操作するけれども、これは pfnSetPromiscuousMode
を通じて virtualbox__intnet
の IntNetR0IfSetPromiscuousMode
や IntNetR0IfSetPromiscuousModeReq
に伝わる。
ip link set eth0 addr 00:11:22:33:44:55
で同様に virtualbox__intnet
の IntNetR0IfSetMacAddress
や IntNetR0IfSetMacAddressReq
に伝わればよかった。これが無い。
virtualbox__intnet
自体は、本来は MAC アドレス更新が通知されれば、正しく動作するように作られているようだ。
promiscuous mode を設定すると通信できるようになるのは、こちらは guest OS の設定が internal network に反映されるから、ということのようだ。
MAC アドレスの変更が伝わらないのは、おそらく意図的なもののように思える。伝わるように変更するにしても、そこそこ大きなパッチを書かないといけない見通しなので、いったん見送る。
VirtualBox NIC
ちなみにデフォルトで選択される e1000
である「Intel PRO/1000」系列や virtio
である「virtio-net」は MAC アドレスを再設定できるが、「PCnet-PCI II」や「PCnet-FAST III」は MAC アドレスを変更しようとすると EBUSY
を返された。
vbox Patch
Doxygen が正しく生成されないことに気が付いてしまったので、仕方なく作成したパッチ。
diff --git a/Makefile.kmk b/Makefile.kmk
index 6cc3a3f73f..025c164293 100644
--- a/Makefile.kmk
+++ b/Makefile.kmk
@@ -460,7 +460,7 @@ VBOX_CORE_DOXYFILE_INPUT_DIRS = \
src/VBox/Devices/Graphics \
src/VBox/Devices/Graphics/BIOS \
src/VBox/Devices/Input \
- src/VBox/Devices/Networking \
+ src/VBox/Devices/Network \
src/VBox/Devices/PC \
src/VBox/Devices/PC/BIOS \
src/VBox/Devices/Parallel \
vbox build Vagrantfile
https://www.virtualbox.org/wiki/Linux%20build%20instructions から次のような Vagrantfile を作った。
Vagrant.configure("2") do |config|
config.vm.box = "debian/jessie64"
config.vm.synced_folder ".", "/vagrant", disabled:true
config.vm.provider "virtualbox" do |vm|
vm.memory = 2048
end
config.vm.provision "shell", inline: <<-SHELL
dpkg --add-architecture i386
apt-get update
apt-get -y install gcc g++ bcc iasl xsltproc uuid-dev zlib1g-dev libidl-dev \
libsdl1.2-dev libxcursor-dev libasound2-dev libstdc++5 \
libpulse-dev libxml2-dev libxslt1-dev \
libssl-dev doxygen yasm wine mscgen \
python-dev libqt4-dev qt4-dev-tools libcap-dev \
libxmu-dev mesa-common-dev libglu1-mesa-dev \
linux-kernel-headers libcurl4-openssl-dev libpam0g-dev \
libxrandr-dev libxinerama-dev libqt4-opengl-dev makeself \
libdevmapper-dev default-jdk \
texlive-latex-base \
texlive-latex-extra texlive-latex-recommended \
texlive-fonts-extra texlive-fonts-recommended
apt-get -y install gcc-multilib g++-multilib
apt-get -y install kbuild genisoimage libvpx-dev linux-headers-`uname -r`
apt-get -y install git
git clone https://github.com/mirror/vbox
cd vbox
./configure --disable-hardening
kmk docs
SHELL
end