2012 Kernel/VM Advent Calendar 21 日目 @hdk_2: VDE のお話

カーネル/VM Advent Calendar 2012 : ATND 2012-12-21

去年、一昨年に引き続き参加してみます。今回は、ちょっと高いレイヤーの VDE のお話です。Kernel/VM ということで、一応、VM にこじつけてみます。

VDE とは、知っている人も多いと思いますが、Virtual Distributed Ethernet の略です。仮想イーサネットと言っていいのかどうかわかりませんが、ソフトウェアで実現したイーサネット、みたいな。SoftEther とかを思い出す人もいるかも知れませんが、独自の認証機能などがあるわけではなく、Unix ドメインソケットを利用した、ずっとシンプルなものです。

Debian では vde2 というパッケージになっています。

vde_switch - 仮想的なスイッチングハブ

vde_switch コマンドは、仮想的なスイッチングハブとして機能します。

$ vde_switch -s /tmp/hoge

このように実行すると、他のプログラムから /tmp/hoge という名前を使ってこのスイッチングハブに仮想的なケーブルを接続したりできます。

Debian の vde2 パッケージには、起動時に自動的に開始する設定方法があります。この方法では、/etc/network/interfaces に以下のように記述します。

auto vde0

iface vde0 inet manual

vde2-switch -

このように書くと、ifup/ifdown コマンドで vde_switch の開始・停止ができ、auto の記述により起動時に自動的に開始されるようになります。名前は /var/run/vde2/vde0.ctl という名前になっており、接続には vde2-net グループの権限が必要です。

vde_plug2tap - vde_switch と tap デバイスの間にケーブルを接続する

vde_plug2tap コマンドは、vde_switch にケーブルを接続し、その先を仮想的なネットワークインターフェイスである tap デバイスに接続します。

# vde_plug2tap -s /tmp/hoge tap0

このように実行すると、tap0 インターフェイスと /tmp/hoge のスイッチングハブが接続されます。ifconfig tap0 10.11.12.13 などと設定して使いましょう。(といっても、スイッチングハブに一本ケーブルを接続しただけでは何もできませんが...)

Debian の vde2 パッケージで /etc/network/interfaces に記述する場合は以下のようになります。

iface tap0 inet static

address 10.11.12.13

netmask 255.0.0.0

vde2-switch -

この場合の vde_switch の名前は /var/run/vde2/tap0.ctl となります。

dpipe と vde_plug - ふたつの vde_switch の間にケーブルを接続する

dpipe コマンドと vde_plug コマンドを使用して、ふたつの vde_switch の間にケーブルを接続することができます。

$ dpipe vde_plug /var/run/vde2/tap0.ctl = vde_plug /tmp/hoge

これは、/var/run/vde2/tap0.ctl と /tmp/hoge のスイッチングハブの間をケーブルで接続します。

$ dpipe vde_plug -s /tmp/hoge = ssh hoge vde_plug -s /tmp/hoge

これは、遠隔ホストとの間で接続する例です。使い方次第で、VPN にもなります。

Debian の vde2 パッケージで /etc/network/interfaces に記述する場合は以下のように書けるらしいです。

iface tap0 inet static

address 10.11.12.13

netmask 255.0.0.0

vde2-switch -

vde2-plug ssh hoge vde_plug /var/run/vde2/tap0.ctl

VirtualBox の仮想マシンと vde_switch の間にケーブルを接続する

知っている人も多いと思いますが、VirtualBox の Linux 版と FreeBSD 版は VDE に対応しています。以前のバージョンでは OSE 版でのみ利用可能で、GUI での設定が可能でした。現在は generic という選択肢になっており、VBoxManage コマンドで設定を行います。

$ VBoxManage modifyvm MyVM --nic1 generic

$ VBoxManage modifyvm MyVM --nicgenericdrv1 VDE

$ VBoxManage modifyvm MyVM --nicproperty1 network=/tmp/hoge

QEMU/KVM の仮想マシンと vde_switch の間にケーブルを接続する

こちらもご存知の方は多いと思いますが、QEMU も VDE に対応しています。

$ qemu -net nic -net vde,sock=/tmp/hoge

Lguest の仮想マシンと vde_switch の間にケーブルを接続する

Linux kernel source に Lguest のサンプルとして入っている Documentation/virtual/lguest/lguest.c.gz は VDE に対応していません。そのため、簡単な改造が必要です。

まず、ヘッダーファイルの include 文を追加します。

#include <libvdeplug.h>

次に、setup_tun_net() 関数を書き換えます。get_tun_device() の行の代わりに、以下のプログラムを書きます。

int s[2];

socketpair(PF_UNIX,SOCK_DGRAM,0,s);

net_info->tunfd=s[0];

if(!fork()){

struct vde_open_args a;

VDECONN*conn;

char buf[2048]="\0\0\0\0\0\0\0\0\0\0";

int l;

close(s[0]);

a.port=0;a.group=NULL;a.mode=0700;

conn=vde_open(arg,"lguest:",&a);

if(!fork())for(;;){

l=vde_recv(conn,buf+10,sizeof buf-10,0);

if(l<=0)

err(1,"vde_recv");

write(s[1],buf,l+10);

}

for(;;){

l=read(s[1],buf,sizeof buf);

if(l<=0)

err(1,"read");

vde_send(conn,buf+10,l-10,0);

}

}

close(s[1]);

あとは、この下のほうにある socket() から configure_device() までと、close(ipfd); は消します。

最後に、Makefile でオプションを指定します。

CFLAGS+=`pkg-config --cflags vdeplug`

LDFLAGS+=`pkg-config --libs vdeplug`

Debian 環境でコンパイルするときは libvdeplug2-dev パッケージを入れておきます。

使い方は、以下のように --tunnet オプションで vde_switch の名前を指定するだけです。

$ ./lguest 64 vmlinux --initrd initrd --tunnet=/tmp/hoge

おわりに

そんなわけで、VDE のコマンドの一部と、VDE 対応の仮想マシンソフトウェアと、プログラムから VDE の API を使う例を紹介してみました。Unix らしいシンプルなツール群と API になっているのがわかると思います。ここで紹介したもの以外にもコマンドがいくつかあって、いろいろ遊べるようになっているみたいなので、ネットワーク好きな人にはお勧めです。