Debian GNU/Linux 8.8(jessie)の KVM で仮想マシンのネットワークインターフェースに macvtap を使用するために調べたことと libvirt のネットワークをおさらいした時のメモです。
はじめに
KVM の仮想マシンをホストと同じネットワークに接続するためにホスト OS のネットワークインターフェースをブリッジ化していましたが、Linux kernel の macvlan 機能を使用した macvtap を使うことでホスト OS の負荷が下がりパフォーマンスが良くなるらしいことを知りました。
参照先の文書を眺めただけではいまいちどのようなものか分かりませんでしたが、同じ著者による LXC の連載記事で macvlan について詳しい説明がありました。
これらを参考に手元の KVM 環境で libvirt の仮想ネットワークについて再確認したことと macvlan を試して分かったこをまとめます。libvirtの仮想ネットワークおさらい
libvirt(virt-manager)で仮想マシンの仮想ネットワークインターフェースのネットワークソースとして指定できる以下の項目について確認します。
- 仮想ネットワーク(NAT)※
- 共有デバイス名を指定(ブリッジ)
確認に使用するネットワーク環境と libvirt のバージョンは以下を想定しています。
- ホスト OS には物理 NIC がひとつ(eth0)
- IP アドレスは 192.168.1.X/24
- デフォルトゲートウェイは 192.168.1.1
# virsh version Compiled against library: libvirt 1.2.9 Using library: libvirt 1.2.9 Using API: QEMU 1.2.9 Running hypervisor: QEMU 2.1.2
仮想ネットワーク(NAT)
libvirt をインストールすると default という仮想ネットワークが作成されます。具体的には 192.168.122.1/24 のプライベート IP アドレスが割り当てられた virbr0 という仮想ブリッジがホスト OS に作成され、仮想ネットワークから外部へ通信する際に送信元 IP アドレスをホスト OS のものに変換する iptables の MASQUERADE が設定されます。仮想ブリッジに紐ついた dnsmasq プロセスも起動されますが今回は関係ないので説明は省きます。
仮想マシンを起動すると仮想 NIC に対応する疑似 Ethernet デバイス(tap デバイス)が作成され仮想ブリッジに接続されます。ゲスト OS は仮想ブリッジをゲートウェイとすることで外部ネットワークと通信できるようになります。
仮想ネットワーク(NAT)を使用する場合のネットワーク構成は以下のようになります。
仮想マシンのネットワーク定義は以下のようになります。
# virsh dumpxml guest1 | awk '/<interface/,/interface>/' <interface type='network'> <mac address='52:54:00:74:b4:1e'/> <source network='default'/> <model type='virtio'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface>
仮想マシンを2つ起動した後のネットワークインターフェースの状態。
# ip -d link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 link/ether 28:92:4a:2f:0c:66 brd ff:ff:ff:ff:ff:ff promiscuity 0 3: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether fe:54:00:3b:85:b8 brd ff:ff:ff:ff:ff:ff promiscuity 0 bridge 4: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UNKNOWN mode DEFAULT group default qlen 500 link/ether fe:54:00:3b:85:b8 brd ff:ff:ff:ff:ff:ff promiscuity 1 tun bridge_slave 5: vnet1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UNKNOWN mode DEFAULT group default qlen 500 link/ether fe:54:00:74:b4:1e brd ff:ff:ff:ff:ff:ff promiscuity 1 tun bridge_slave仮想ブリッジの状態。
# brctl show virbr0 bridge name bridge id STP enabled interfaces virbr0 8000.fe54003b85b8 yes vnet0 vnet1iptable の状態。
# iptables -nL -v Chain INPUT (policy ACCEPT 30053 packets, 4614K bytes) pkts bytes target prot opt in out source destination 4 250 ACCEPT udp -- virbr0 * 0.0.0.0/0 0.0.0.0/0 udp dpt:53 0 0 ACCEPT tcp -- virbr0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:53 0 0 ACCEPT udp -- virbr0 * 0.0.0.0/0 0.0.0.0/0 udp dpt:67 0 0 ACCEPT tcp -- virbr0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:67 Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 2 168 ACCEPT all -- * virbr0 0.0.0.0/0 192.168.122.0/24 ctstate RELATED,ESTABLISHED 2 168 ACCEPT all -- virbr0 * 192.168.122.0/24 0.0.0.0/0 0 0 ACCEPT all -- virbr0 virbr0 0.0.0.0/0 0.0.0.0/0 0 0 REJECT all -- * virbr0 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable 0 0 REJECT all -- virbr0 * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable Chain OUTPUT (policy ACCEPT 27251 packets, 8486K bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT udp -- * virbr0 0.0.0.0/0 0.0.0.0/0 udp dpt:68
# iptables -t nat -nL -v Chain PREROUTING (policy ACCEPT 620 packets, 89432 bytes) pkts bytes target prot opt in out source destination Chain INPUT (policy ACCEPT 522 packets, 86192 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 474 packets, 36717 bytes) pkts bytes target prot opt in out source destination Chain POSTROUTING (policy ACCEPT 474 packets, 36717 bytes) pkts bytes target prot opt in out source destination 8 551 RETURN all -- * * 192.168.122.0/24 224.0.0.0/24 0 0 RETURN all -- * * 192.168.122.0/24 255.255.255.255 0 0 MASQUERADE tcp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535 0 0 MASQUERADE udp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535 2 168 MASQUERADE all -- * * 192.168.122.0/24 !192.168.122.0/24
外部ネットワークからゲスト OS と通信できるようにするには、ホスト OS の特定のネットワークポート宛てのパケットをゲスト OS 宛てに変換する iptables の DNAT を設定したり、仮想ネットワークのゲートウェイとしてホスト OS の IP アドレスを外部のルータなどに設定する必要があります。
共有デバイス名を指定(ブリッジ)
ゲスト OS をサーバ用途で使用する場合に仮想ネットワークが NAT ですと外部ネットワークから利用しづらいですので、ホスト OS の物理 NIC が接続しているネットワークを仮想マシンで共有できるように仮想ブリッジを作成します。
手元の環境ではホスト OS のネットワークインターフェースは1つしかありませんので仮想ブリッジに IP アドレスを割り当てて利用します。
共有デバイス名を指定(ブリッジ)する場合のネットワーク構成は以下のようになります。
仮想ブリッジの作成と物理 NIC の接続、物理 NIC に割り当てていた IP アドレスを仮想ブリッジに割り当てるには以下のようなコマンドを実行します。
# brctl addbr br0 # brctl addif br0 eth0 # ip addr del 192.168.1.X/24 dev eth0 # ip addr add 192.168.1.X/24 dev br0 # ip link set eth0 down # ip link set eth0 up # ip link set br0 up # ip route add default via 192.168.1.1リモートからの接続で IP アドレスの割り当てを切り替える場合はコマンドを1行にまとめて実行すると少し安心できると思います。
# ip addr del 192.168.1.X/24 dev eth0; ip addr add 192.168.1.X/24 dev br0; ip link set eth0 down; ip link set eth0 up; ip link set br0 up; ip route add default via 192.168.1.1永続化する場合は
/etc/network/interfaces
に記載します。
auto br0 iface br0 inet static address 192.168.1.X netmask 255.255.255.0 gateway 192.168.1.1 bridge_ports eth0 bridge_stp off bridge_fd 0 bridge_waitport 0
また、仮想ブリッジを通過するパケットにも iptables が適用されますので、FORWARD チェーンのデフォルト・ターゲットを DROP にしている場合などは通信を許可する必要があります。
# iptables -A FORWARD -m physdev --physdev-is-bridged -j ACCEPT仮想ブリッジを通過するパケットに iptables を適用しないようにするにはカーネル・パラメータを変更します。
/etc/sysctl.conf
に以下を追加して反映します。
net.bridge.bridge-nf-call-arptables = 0 net.bridge.bridge-nf-call-ip6tables = 0 net.bridge.bridge-nf-call-iptables = 0
# sysctl -p
仮想マシンのネットワーク定義は以下のようになります。
# virsh dumpxml guest1 | awk '/<interface/,/interface>/' <interface type='bridge'> <mac address='52:54:00:3b:85:b8'/> <source bridge='br0'/> <model type='virtio'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface>
仮想マシンを2つ起動した後のネットワークインターフェースの状態。
# ip -d link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master br0 state UP mode DEFAULT group default qlen 1000 link/ether 28:92:4a:2f:0c:66 brd ff:ff:ff:ff:ff:ff promiscuity 1 bridge_slave 3: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 28:92:4a:2f:0c:66 brd ff:ff:ff:ff:ff:ff promiscuity 0 bridge 4: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br0 state UNKNOWN mode DEFAULT group default qlen 500 link/ether fe:54:00:3b:85:b8 brd ff:ff:ff:ff:ff:ff promiscuity 1 tun bridge_slave 5: vnet1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br0 state UNKNOWN mode DEFAULT group default qlen 500 link/ether fe:54:00:74:b4:1e brd ff:ff:ff:ff:ff:ff promiscuity 1 tun bridge_slave
仮想ブリッジの状態。
# brctl show br0 bridge name bridge id STP enabled interfaces br0 8000.28924a2f0c66 no eth0 vnet0 vnet1
macvlan/macvtapについて
macvlan については以下の記事でわかりやすいです。
macvlan は MAC アドレスベースの仮想 Ethernet デバイスで、その機能を KVM(qemu) 等のソフトウェアから扱えるように tap インターフェースとして実装したものが macvtap のようです。Linux kernel のコミットメッセージや Kconfig に説明がありましたので引用します。
- [NET]: Add macvlan driver
Add macvlan driver, which allows to create virtual ethernet devices based on MAC address.
- macvlan: implement bridge, VEPA and private mode
This allows each macvlan slave device to be in one of three modes, depending on the use case: MACVLAN_PRIVATE: The device never communicates with any other device on the same upper_dev. This even includes frames coming back from a reflective relay, where supported by the adjacent bridge. MACVLAN_VEPA: The new Virtual Ethernet Port Aggregator (VEPA) mode, we assume that the adjacent bridge returns all frames where both source and destination are local to the macvlan port, i.e. the bridge is set up as a reflective relay. Broadcast frames coming in from the upper_dev get flooded to all macvlan interfaces in VEPA mode. We never deliver any frames locally. MACVLAN_BRIDGE: We provide the behavior of a simple bridge between different macvlan interfaces on the same port. Frames from one interface to another one get delivered directly and are not sent out externally. Broadcast frames get flooded to all other bridge ports and to the external interface, but when they come back from a reflective relay, we don't deliver them again. Since we know all the MAC addresses, the macvlan bridge mode does not require learning or STP like the bridge module does.
- net: macvtap driver
In order to use macvlan with qemu and other tools that require a tap file descriptor, the macvtap driver adds a small backend with a character device with the same interface as the tun driver, with a minimum set of features. Macvtap interfaces are created in the same way as macvlan interfaces using ip link, but the netif is just used as a handle for configuration and accounting, while the data goes through the chardev. Each macvtap interface has its own character device, simplifying permission management significantly over the generic tun/tap driver.
- Kconfig\net\drivers - kernel/git/torvalds/linux.git - Linux kernel source tree
config MACVLAN tristate "MAC-VLAN support" ---help--- This allows one to create virtual interfaces that map packets to or from specific MAC addresses to a particular interface. Macvlan devices can be added using the "ip" command from the iproute2 package starting with the iproute2-2.6.23 release: "ip link add link <real dev> [ address MAC ] [ NAME ] type macvlan" To compile this driver as a module, choose M here: the module will be called macvlan. config MACVTAP tristate "MAC-VLAN based tap driver" depends on MACVLAN depends on INET select TAP help This adds a specialized tap character device driver that is based on the MAC-VLAN network interface, called macvtap. A macvtap device can be added in the same way as a macvlan device, using 'type macvtap', and then be accessed through the tap user space interface. To compile this driver as a module, choose M here: the module will be called macvtap.
仮想ネットワークのブリッジ接続にmacvtapを使用する
仮想ネットワーク(NAT)や共有デバイス(ブリッジ)と異なり、macvtap を仮想ネットワークのブリッジ接続に使用する上で特別な準備は必要ありません。
macvtap が実装された Linux kernel バージョン 2.6.34 以上であれば使用可能です。このバージョンのリリースは 2010年 5月のようですので、主要な Linux ディストリビューションであれば最新、またはそれよりも前のバージョンでも対応していると思われます。
- Linux 2 6 34 - Linux Kernel Newbies
- Package search: linux version greater or equal to 2.6.34 in the latest release - DistroWatch.com: Put the fun back into computing. Use Linux, BSD.
後述の作業で ip コマンドを使用して macvlan インターフェースを作成しますので iproute2 パッケージはバージョン 2.6.23 以上のものが必要です。
手元の環境(Debian/GNU Linux 8)はどちらも満たしています。
# cat /etc/os-release PRETTY_NAME="Debian GNU/Linux 8 (jessie)" NAME="Debian GNU/Linux" VERSION_ID="8" VERSION="8 (jessie)" ID=debian HOME_URL="http://www.debian.org/" SUPPORT_URL="http://www.debian.org/support" BUG_REPORT_URL="https://bugs.debian.org/"
# uname -srv Linux 3.16.0-4-amd64 #1 SMP Debian 3.16.43-2 (2017-04-30)
# apt-show-versions iproute2 iproute2:amd64/jessie 3.16.0-2 uptodate
macvlan はインタフェースに複数の MAC アドレスを割り当てる機能ですので仮想ブリッジに設定することも出来ますが、メリットがなさそうなのでシンプルに物理 NIC に設定します。
ホストデバイス(macvtap)を使用する場合のネットワーク構成は以下のようになります。
ここでは仮想ネットワークを共有デバイス(ブリッジ)からホストデバイス(macvtap)に切り替えることを想定します。まず仮想ブリッジに割り当てた IP アドレスを物理 NIC に戻すために以下のようなコマンドを実行します。仮想ブリッジは不要になるので削除します。
# ip addr del 192.168.1.X/24 dev br0 # ip addr add 192.168.1.X/24 dev eth0 # brctl delif br0 eth0 # ip link set br0 down # brctl delbr br0 # ip link set eth0 down # ip link set eth0 up # ip route add default via 192.168.1.1仮想ブリッジから物理 NIC に IP アドレスを割り当てなおす場合は仮想ブリッジから eth0 を切断するまでは通信ができなくなりますので、リモートから接続している場合はコマンドを1行でまとめて実行すると安心できます。
# ip addr del 192.168.1.X/24 dev br0; ip addr add 192.168.1.X/24 dev eth0; brctl delif br0 eth0; ip link set br0 down; brctl delbr br0; ip link set eth0 down; ip link set eth0 up; ip route add default via 192.168.1.1
仮想マシンのネットワーク定義は以下のようになります。
# virsh dumpxml guest1 | awk '/<interface/,/interface>/' <interface type='direct'> <mac address='52:54:00:3b:85:b8'/> <source dev='eth0' mode='bridge'/> <model type='virtio'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface>
仮想マシンを2つ起動した後のネットワークインターフェースの状態。
# ip -d link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 link/ether 28:92:4a:2f:0c:66 brd ff:ff:ff:ff:ff:ff promiscuity 0 3: macvtap0@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 500 link/ether 52:54:00:3b:85:b8 brd ff:ff:ff:ff:ff:ff promiscuity 0 macvtap mode bridge 4: macvtap1@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 500 link/ether 52:54:00:74:b4:1e brd ff:ff:ff:ff:ff:ff promiscuity 0 macvtap mode bridgemacvlan/macvtap の状況を確認する方法は分かりませんが、カーネルモジュールが読み込まれている事は確認できます。
# lsmod | grep ^macv macvtap 17526 5 vhost_net macvlan 18315 1 macvtap
# modinfo macvlan filename: /lib/modules/3.16.0-4-amd64/kernel/drivers/net/macvlan.ko alias: rtnl-link-macvlan description: Driver for MAC address based VLANs author: Patrick McHardy <kaber@trash.net> license: GPL depends: intree: Y vermagic: 3.16.0-4-amd64 SMP mod_unload modversions
# modinfo macvtap filename: /lib/modules/3.16.0-4-amd64/kernel/drivers/net/macvtap.ko license: GPL author: Arnd Bergmann <arnd@arndb.de> alias: rtnl-link-macvtap depends: macvlan intree: Y vermagic: 3.16.0-4-amd64 SMP mod_unload modversions
macvtap使用時の考慮事項1. ホストOSとゲストOSが通信できない(回避策あり)
仮想ネットワークに共有デバイス名を指定(ブリッジ)した際には、仮想ブリッジに接続したネットワークインターフェースはホスト OS では利用できませんでした。しかし macvtap を設定した場合は MAC アドレスが異なりますのでホスト OS のネットワークインターフェースは利用可能です。ただし virt-manager で警告があるとおり、そのインターフェースを通じてホスト OS とゲスト OS は直接の通信ができません。
Red Hat Enterprise Linux のマニュアルにも記載があります。
私が理解しているイメージが以下になります。macvlan の bridge モードが有効となっているインターフェースでひとつの VLAN のようなものが構成されていますので、そこに接続していないホスト OS のネットワークインターフェースからではゲスト OS に通信できません。
ゲスト OS が外部ネットワークと通信できれば困らないかも知れませんが少し不便です。そこでホスト OS のインターフェースを macvlan の bridge として作成することでゲスト OS との通信が可能になるよ、という事が書かれていた記事が冒頭に紹介したものです。
その場合の構成は以下のようなイメージになるでしょうか。
物理 NIC(eth0)に macvlan インターフェース(macvlan0)をブリッジモードで作成して IP アドレスを割り当てます。
# ip link add dev macvlan0 link eth0 type macvlan mode bridge # ip addr del 192.168.1.X/24 dev eth0 # ip addr add 192.168.1.X/24 dev macvlan0 # ip link set macvlan0 up # ip route add default via 192.168.1.1 dev macvlan0例によってリモート接続から実行する場合はコマンドを1行にまとめて実行します。
# ip addr del 192.168.1.X/24 dev eth0; ip addr add 192.168.1.X/24 dev macvlan0; ip link set macvlan0 up; ip route add default via 192.168.1.1 dev macvlan0
永続化する場合は /etc/network/interfaces
に記載します。
auto eth0 iface eth0 inet manual auto macvlan0 iface macvlan0 inet static address 192.168.1.X netmask 255.255.255.0 gateway 192.168.1.1 pre-up ip link set eth0 up pre-up ip link add link eth0 name $IFACE type macvlan mode bridge post-down ip link delete $IFACE type macvlan
仮想マシンを2つ起動した後のネットワークインターフェースの状態。
# ip -d link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 link/ether 28:92:4a:2f:0c:66 brd ff:ff:ff:ff:ff:ff promiscuity 0 3: macvlan0@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether ae:69:46:86:b0:02 brd ff:ff:ff:ff:ff:ff promiscuity 0 macvlan mode bridge 4: macvtap0@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 500 link/ether 52:54:00:3b:85:b8 brd ff:ff:ff:ff:ff:ff promiscuity 0 macvtap mode bridge 5: macvtap1@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 500 link/ether 52:54:00:74:b4:1e brd ff:ff:ff:ff:ff:ff promiscuity 0 macvtap mode bridge外部ネットワークから見たホスト OS のインターフェースは macvlan で物理 NIC とは異なる MAC アドレスになりますので、運用管理面で使用できないケースがあるかも知れません。その場合はホスト OS からゲスト OS にアクセスするためのネットワークインターフェースを別途追加するか、ゲスト OS でシリアルコンソール接続の設定をするなどの対応が必要になります。
macvtap使用時の考慮事項2. NetworkManagerとの相性が悪い
手元の環境では macvtap を設定した仮想マシンを一度停止すると、次回起動時に macvtap インターフェースがリンクアップしない事象が発生しました。
以下は仮想マシンを初回に起動した時の NetworkManager のログとホスト OS のインターフェースの状態。これは問題ありません。
<info> (macvtap0): link connected <info> (macvtap0): carrier is ON <info> (macvtap0): new Macvlan device (driver: 'unknown' ifindex: 3) <info> (macvtap0): exported as /org/freedesktop/NetworkManager/Devices/2 <info> devices added (path: /sys/devices/virtual/net/macvtap0, iface: macvtap0) <info> device added (path: /sys/devices/virtual/net/macvtap0, iface: macvtap0): no ifupdown configuration found. <info> (macvtap0): device state change: unmanaged -> unavailable (reason 'connection-assumed') [10 20 41] <info> (macvtap0): device state change: unavailable -> disconnected (reason 'connection-assumed') [20 30 41] <info> Activation (macvtap0) starting connection 'macvtap0' <info> Activation (macvtap0) Stage 1 of 5 (Device Prepare) scheduled... <info> Activation (macvtap0) Stage 1 of 5 (Device Prepare) started... <info> (macvtap0): device state change: disconnected -> prepare (reason 'none') [30 40 0] <info> Activation (macvtap0) Stage 2 of 5 (Device Configure) scheduled... <info> Activation (macvtap0) Stage 1 of 5 (Device Prepare) complete. <info> Activation (macvtap0) Stage 2 of 5 (Device Configure) starting... <info> (macvtap0): device state change: prepare -> config (reason 'none') [40 50 0] <info> Activation (macvtap0) Stage 2 of 5 (Device Configure) successful. <info> Activation (macvtap0) Stage 3 of 5 (IP Configure Start) scheduled. <info> Activation (macvtap0) Stage 2 of 5 (Device Configure) complete. <info> Activation (macvtap0) Stage 3 of 5 (IP Configure Start) started... <info> (macvtap0): device state change: config -> ip-config (reason 'none') [50 70 0] <info> Activation (macvtap0) Stage 5 of 5 (IPv6 Commit) scheduled... <info> Activation (macvtap0) Stage 3 of 5 (IP Configure Start) complete. <info> Activation (macvtap0) Stage 5 of 5 (IPv6 Commit) started... <info> (macvtap0): device state change: ip-config -> ip-check (reason 'none') [70 80 0] <info> Activation (macvtap0) Stage 5 of 5 (IPv6 Commit) complete. <info> (macvtap0): device state change: ip-check -> secondaries (reason 'none') [80 90 0] <info> (macvtap0): device state change: secondaries -> activated (reason 'none') [90 100 0] <info> Activation (macvtap0) successful, device activated.ネットワークリンクの状態。
# ip -d link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 link/ether 28:92:4a:2f:0c:66 brd ff:ff:ff:ff:ff:ff promiscuity 0 3: macvtap0@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 500 link/ether 52:54:00:3b:85:b8 brd ff:ff:ff:ff:ff:ff promiscuity 0 macvtap mode bridge
仮想マシン停止時の NetworkManager のログ。
<info> (macvtap0): device state change: activated -> unmanaged (reason 'removed') [100 10 36] <info> (macvtap0): deactivating device (reason 'removed') [36] <info> devices removed (path: /sys/devices/virtual/net/macvtap0, iface: macvtap0)
次に問題となる仮想マシンを2回目に起動した時の NetworkManager のログとネットワークリンクの状態。warn レベルのメッセージとして ip-config-unavailable
が出力されて macvtap インターフェースがリンクアップしません。
<info> (macvtap0): link connected
<info> (macvtap0): carrier is ON
<info> (macvtap0): new Macvlan device (driver: 'unknown' ifindex: 4)
<info> (macvtap0): exported as /org/freedesktop/NetworkManager/Devices/3
<info> devices added (path: /sys/devices/virtual/net/macvtap0, iface: macvtap0)
<info> device added (path: /sys/devices/virtual/net/macvtap0, iface: macvtap0): no ifupdown configuration found.
<info> (macvtap0): found matching connection 'macvtap0'
<info> (macvtap0): device state change: unmanaged -> unavailable (reason 'connection-assumed') [10 20 41]
<info> (macvtap0): device state change: unavailable -> disconnected (reason 'connection-assumed') [20 30 41]
<info> Activation (macvtap0) starting connection 'macvtap0'
<info> Activation (macvtap0) Stage 1 of 5 (Device Prepare) scheduled...
<info> Activation (macvtap0) Stage 1 of 5 (Device Prepare) started...
<info> (macvtap0): device state change: disconnected -> prepare (reason 'none') [30 40 0]
<info> Activation (macvtap0) Stage 2 of 5 (Device Configure) scheduled...
<info> Activation (macvtap0) Stage 1 of 5 (Device Prepare) complete.
<info> Activation (macvtap0) Stage 2 of 5 (Device Configure) starting...
<info> (macvtap0): device state change: prepare -> config (reason 'none') [40 50 0]
<info> Activation (macvtap0) Stage 2 of 5 (Device Configure) successful.
<info> Activation (macvtap0) Stage 3 of 5 (IP Configure Start) scheduled.
<info> Activation (macvtap0) Stage 2 of 5 (Device Configure) complete.
<info> Activation (macvtap0) Stage 3 of 5 (IP Configure Start) started...
<info> (macvtap0): device state change: config -> ip-config (reason 'none') [50 70 0]
<info> (macvtap0): device state change: ip-config -> failed (reason 'ip-config-unavailable') [70 120 5]
<warn> Activation (macvtap0) failed for connection 'macvtap0'
<info> Activation (macvtap0) Stage 3 of 5 (IP Configure Start) complete.
<info> (macvtap0): device state change: failed -> disconnected (reason 'none') [120 30 0]
<info> (macvtap0): deactivating device (reason 'none') [0]
<info> (macvtap0): device state change: disconnected -> unmanaged (reason 'none') [30 10 0]
<info> (macvtap0): link disconnected
# ip -d link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 link/ether 28:92:4a:2f:0c:66 brd ff:ff:ff:ff:ff:ff promiscuity 0 4: macvtap0@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 500 link/ether 52:54:00:3b:85:b8 brd ff:ff:ff:ff:ff:ff promiscuity 0 macvtap mode bridge
検索してみると同じような事象がみつかりました。
NetworkManager を再起動すればこの状態(一度リンクダウンした macvtap がリンクアップしない)はリセットされるようですが、仮想マシンを2度目に起動するたびに NetworkManager を再起動するのは何か違いますので回避策を探します。回避策1. NetworkManagerを無効にする
試した限りこれが一番確実です。
# systemctl stop NetworkManager # systemctl disable NetworkManagerですが少し乱暴な気がしますので NetworkManager を無効にする以外の方法を探します。
回避策2. IPv6を無効にする
ip-config-unavailable
で検索すると以下の記事が見つかりました。
# sysctl net.ipv6.conf.all.disable_ipv6=1NetworkManager のログ。
<info> (macvtap0): link connected <info> (macvtap0): carrier is ON <info> (macvtap0): new Macvlan device (driver: 'unknown' ifindex: 3) <info> (macvtap0): exported as /org/freedesktop/NetworkManager/Devices/2 <info> devices added (path: /sys/devices/virtual/net/macvtap0, iface: macvtap0) <info> device added (path: /sys/devices/virtual/net/macvtap0, iface: macvtap0): no ifupdown configuration found.IPv6 を使用していない環境であれば割り切って無効にしてしまっても良いのかも知れません。
回避策3. macvtapインターフェースをNetworkManagerで管理しないようにする
NetworkManager では管理しないインターフェースを定義できるようですので、そこに macvtap インターフェースを指定します。
/etc/NetworkManager/NetworkManager.conf の[keyfile]
セクションに unmanaged-devices
として記述すればよいようです。使用しているバージョンが異なるせいかマニュアルに記載してあるワイルドカードが機能しませんでしたので利用する可能性のある macvtap インターフェースの数だけ列挙しています。
# NetworkManager --version 0.9.10.0
[keyfile] unmanaged-devices=interface-name:macvtap0;interface-name:macvtap1;interface-name:macvtap2;interface-name:macvtap3;interface-name:macvtap4;interface-name:macvtap5ちなみに Debian/GNU Linux の場合は /etc/network/interfaces ファイルに記載のあるインターフェースは NetworkManager の管理対象外となるようです。
気になる性能
仮想ネットワークに macvtap を使用した場合に仮想ブリッジと比較してどの程度の差があるのか iperf コマンド実行時のリソース使用状況を Munin で確認してみました。
確認環境
手元に KVM ホスト以外で使用できそうな端末が NAS しかないので、NAS にパッケージ(ipkg)として提供されていた iperf を使用して KVM ゲストを iperf サーバに、NAS を iperf クライアントとして実行しました。
- KVM ホスト
- Debian GNU/Linux 8 (linux kernel 3.16.0-4-amd64)
- CPU: AMD Turion™ II NEO N54L(2.2GHz)
- NIC: Broadcom NetXtreme BCM5723 Gigabit Ethernet(tg3)
- iperfサーバ(KVM ゲスト)
- vCPU 1
- Debian GNU/Linux 8 (linux kernel 3.16.0-4-amd64)
- iperf 2.0.5
- iperfクライアント
- QNAP QTS 4.2.6 (linux kernel 3.4.6)
- iperf 2.0.4 (ipkg)
# iperf -sクライアントではひたすら一定期間(約50分)サーバに対して計測を繰り返します。
# while :; do iperf -c 192.168.1.XX; done ------------------------------------------------------------ Client connecting to 192.168.1.XX, TCP port 5001 TCP window size: 22.5 KByte (default) ------------------------------------------------------------ [ 3] local 192.168.1.YY port 56409 connected with 192.168.1.XX port 5001 [ ID] Interval Transfer Bandwidth [ 3] 0.0-10.0 sec 1.09 GBytes 932 Mbits/sec
リソース使用状況
グラフ右側の 12:00 くらいから、左から順に iperf サーバを起動した時の条件は次のとおり。
- KVM ゲスト(br0)
- KVM ゲスト(macvtap)
- KVM ゲスト(br0)※vhost-net zero-copy無効
- KVM ゲスト(macvtap)※vhost-net zero-copy無効
- KVM ホスト(eth0)
- CPU 使用率は macvtap 利用時のほうがわずかに user% が多いように見えますが guest% などと合わせると同じ程度。ホストが忙しいとグラフが欠けるのが謎(4時頃はバックアップ処理が動作中)
- ネットワーク転送速度は、どのパターンでも 900MB/s ほど出ています
- 割り込みとコンテキストスイッチは macvtap のほうが多い
おわりに
仮想環境を扱う上でネットワーク仮想化は非常に重要なコンポーネントですが、 virt-manager でエイヤっ!と作っていてあまり理解していなかったところを macvtap の動作を確認するついでに復習できました。今後は Open vSwitch による仮想ブリッジや各種オーバーレイネットワークを調べてみようと思います。
参考資料
文中にも幾つか記載しましたが、分かった気になるまで何度も参照した資料をまとめます。
- Slides | LinuxCon Japan 2014 | Linux Conferences and Linux Events | The Linux Foundation
- Virtual switching technologies and Linux bridge
VLAN using not 802.1Q tag but mac address
この説明がとても明解。
- Virtual switching technologies and Linux bridge
- Internet Week 2012 D1 パケットフォワーディングを支える技術 - JPNIC
- 極める!KVM
KVM 環境における物理 NIC と仮想 NIC の接続方法(bridge/openvswitch/macvtap)と仮想 NIC の実装(e1000/virtio-net/vhost-net)の説明とそれぞれの組合せでの性能計測。
- 極める!KVM
- Internet Week 2011 S9 仮想化時代のパケットフォワーディング - JPNIC
- 仮想化環境におけるパケットフォワーディング
仮想 NIC の実装毎の送受信処理や仮想ネットワークの構成の図がとても理解の助けになりました - 『KVM徹底入門 Linuxカーネル仮想化基盤構築ガイド』
- 『プロのためのLinuxシステム・ネットワーク管理技術』
- Virtualized bridged networking with MacVTap - Seravo
- Some notes on macvlan/macvtap « \1
- TipAndDoc/network/macvlan – lab
勉強になる情報をご紹介いただきありがとうございます。
返信削除当方も記事にご紹介されているようなものと同じセットアップでMacvlan/macvtapの動きの検証をしているのですが、動きを確認出来ない箇所が2点ありまして、お知恵をお借りできませんでしょうか。
(1) macvtapがns内から自分自身へPingを飛ばせない
ip link add br-macvlan0 link eth0 type macvlan mode bridge
ip addr add 192.168.1.X1/24 dev br-macvlan0
ip link set br-macvlan0 up
ip link add macvtap0 link br-macvlan0 type macvtap mode bridge
ip netns add test
ip link set macvtap0 netns test
ip netns exec test ip link set macvtap0 up
ip netns exec test ip addr add 192.168.1.X2/24 dev macvtap0
ip netns exec test ip route add 192.168.1.0/24 dev macvtap0
(2)KVMのゲスト(Windows7)にMacvtapインターフェースをアサインし、ホストのMacvlanブリッジとの
通信を試みたものの、ゲストでもルーティングを行っており、同一セグメントで異なるアドレスにもかかわらず通信できていない。
よろしくお願いします。