7
6

More than 5 years have passed since last update.

VirtualBox intnet と NIC と promisc の話

Last updated at Posted at 2017-06-29

一般的な使い方では、自分の 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 onpromisc を操作するけれども、これは pfnSetPromiscuousMode を通じて virtualbox__intnetIntNetR0IfSetPromiscuousModeIntNetR0IfSetPromiscuousModeReq に伝わる。

ip link set eth0 addr 00:11:22:33:44:55 で同様に virtualbox__intnetIntNetR0IfSetMacAddressIntNetR0IfSetMacAddressReq に伝わればよかった。これが無い。

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
7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6