Help us understand the problem. What is going on with this article?

【※追記 2015/03/05】Software Switch用のKVMゲスト同士をLayer-2で直接接続する(For LLDPの送受信)

More than 5 years have passed since last update.

序文

KMV環境において同一ホスト上ののVM~VM間、VM~ホストVeth間の通信には、多くの場合Linux-Bridgeや
Open vSwitchなど、ブリッジデバイスを利用します。
そして多くの場合はこのようなBride経由のVM接続で何ら支障はありません。

ただ、VM上でS/W仮想スイッチを稼働させて、それを複数台に相互接続、LLDPやIGMPの送受信を
させたいような場合、間にブリッジデバイスが介在する事が障害となる場合があります。
(※今回試していないが、IPv6のLink-Localフレームも同様では?)


ときに、私はOpenFlow 1.3対応のスイッチ群でトポロジアウェアな経路制御コントローラを実装しようと
思い立っておりました。
そして、この実装手段の一つにLLDPによるトポロジ検知を検討したのです。

そこで、取り急ぎKVM間を安易にLinux-Bridgeで接続したところLLDPの授受が適いませんでした。

こうした経緯で、KVM間のLayer-2直結(物理で言えば、機器間のイーサネットケーブル直結)の方法を模索し、
その成功結果を共有したいと思った次第です。


手順としては
 ・ ホストOS上でのvethペアの作成
 ・ 各KVMのホスト側tapデバイスを、上記のvethの片側へmacvtapデバイスとして接続
 ・ vethペアデバイス、macvtapデバイスのすべてをUplink状態、Promiscuous許可に設定
この流れで実施し、成功しました。

なお、LLDP受信の確認にはLADVDパッケージのLLDPエージェントを利用しました。



macvtap_vs_bridge.png


手順の解説に先立って、まずMacvtapデバイスの概要を説明します。

Macvtapとは

Macvtapデバイスとは、仮想マシン稼働のLinuxカーネルにて、VMとホストOS外部(ホストOSのカーネル以外)との
Layer-2での通信を可能とするために登場した、比較的新しい仮想デバイスです。

上で「ホストOS外部」の言葉で想定しているものは、
 - ホストOSの物理サーバ外部のNW機器
 - 同一のホストOS上で動作する別のVMやNWスタック利用のプロセス
などとなります。


このデバイスTypeは先んじてLinuxカーネルに実装されていたMacvlanデバイスとTapデバイスの2つを組み合わせて、
目的の動作を実現しています。

MacvlanデバイスはLinuxカーネル上の既存NWデバイスに異なるMACアドレスを持つ、新たなLayer-2デバイスを
追加作成する事が出来ます。
そして、この新規生成のデバイスは、追加元のNWデバイスの通信機能を利用して、外部のNWとの通信を行う事が
できるのです。

Macvtapデバイスでは、このMacvlanデバイスを既存デバイス上に生成し、その外部との通信機能を利用します。


次いでTapデバイスの利用についても説明します。

Tapデバイスは、ホストOSのLinuxカーネル ネットワークスタックと、そのLinux上のプロセスとが
Layer-2レベルのNW通信を行うために利用する仮想NWデバイスです。

すなわち、VMゲストが自身のNICへのR/Wを行うと、その入出力Layer-2フレームは対応するTapデバイスへの
入出力として、ホストOS上でR/Wされる事になります。

Macvtapデバイスでは、ホストOS上に生成されるTapデバイスをMacvlanデバイスとして既存NWデバイスに
アタッチし、ゲストOSの通信フレームを既存のNWデバイスの通信機能を利用して、外部と入出力します。


参考:
 http://seravo.fi/2012/virtualized-bridged-networking-with-macvtap

Macvtapの動作モード

Macvtap デバイスの動作モードは4 種類のモードから成っています。
明示指定しない場合、「vepa」がデフォルトのモードとなります。

今回はLink-LocalなLayer-2フレームをKVMゲスト間で送受信する事が目的なので、Bridgeモードは避け、
vepaモードでの接続を実施しました。

他のモードや各モードの仕様に関しては、下に参考のURLを記載します。

参考:
 https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/6/html/Virtualization_Administration_Guide/sect-attch-nic-physdev.html

技術的な手順

  • ホストOSでのVethペア作成
@ホストOS
[root@fedo21]# ip lin add name veth0_a type veth peer name veth0_b

[root@fedo21]# ip -d link sh dev veth0_a
81: veth0_a: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether de:db:ee:3d:55:ba brd ff:ff:ff:ff:ff:ff promiscuity 2 
    veth 
[root@fedo21]# ip -d link sh dev veth0_b
80: veth0_b: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether b2:6e:02:a8:d4:e2 brd ff:ff:ff:ff:ff:ff promiscuity 2 
    veth 
[root@fedo21]# ethtool -S veth0_a
NIC statistics:
     peer_ifindex: 80
  • KVMのNICをvethにmacvtapとして接続
@ホストOS
[root@fedo21]# virsh list
 Id    Name                           State
----------------------------------------------------
 14    nfv-ubu-cpqd                   running
 15    nfv-ubu-tedge                  running


[root@fedo21]# virsh dumpxml 14
<domain type='kvm' id='14'>
  <name>nfv-ubu-cpqd</name>

  (##### Truncated #####)

    </interface>
    <interface type='direct'>
      <mac address='52:54:00:74:e2:c3'/>
      <source dev='veth0_a' mode='vepa'/>
      <target dev='macvtap0'/>
      <model type='virtio'/>
      <alias name='net1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
    </interface>

  (##### Truncated #####)
</domain>

macvtap.png


  • KVMを起動し、I/FのLinkupとPromiscuous許可を設定
@ホストOS
[root@fedo21]# ip lin set up veth0_a
[root@fedo21]# ip lin set up veth0_b

[root@fedo21]# ip lin set promisc on veth0_a
[root@fedo21]# ip lin set promisc on veth0_b
[root@fedo21]# ip lin set promisc on macvtap0
[root@fedo21]# ip lin set promisc on macvtap1
  • KVMの片割れでLLDPエージェント起動、対向KVMでのキャプチャ確認
@KVM①
root@ubu-01:~# apt-get install ladvd
root@ubu-01:~# ladvd -m 192.168.10.2 -n -f -a eth1 &
@KVM②
root@ubu-02:~# tcpdump -v -i eth1
tcpdump: listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes
08:46:37.129285 LLDP, length 298
    Chassis ID TLV (1), length 7
      Subtype MAC address (4): 52:54:00:ab:0d:1a (oui Unknown)
    Port ID TLV (2), length 5
      Subtype Interface Name (5): eth1
    Time to Live TLV (3), length 2: TTL 180s
    Port Description TLV (4), length 24: Red Hat, Inc Device 0001
    System Name TLV (5), length 7: nfv-ubu
    System Description TLV (6), length 93
      Ubuntu 14.04.1 LTS Linux 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014 x86_64
    System Capabilities TLV (7), length 4
      System  Capabilities [Router] (0x0010)
      Enabled Capabilities [none] (0x0000)
    Management Address TLV (8), length 12
      Management Address length 5, AFI IPv4 (1): 192.168.10.2
      Interface Index Interface Numbering (2): 3
    Organization specific TLV (127), length 6: OUI IEEE 802.3 Private (0x00120f)
      Max frame size Subtype (4)
        MTU size 1522
    Organization specific TLV (127), length 17: OUI ANSI/TIA (0x0012bb)
      Inventory - hardware revision Subtype (5)
      Hardware revision pc-i440fx-2.1
    Organization specific TLV (127), length 26: OUI ANSI/TIA (0x0012bb)
      Inventory - firmware revision Subtype (6)
      Firmware revision 1.7.5-20140709_153950-
    Organization specific TLV (127), length 21: OUI ANSI/TIA (0x0012bb)
      Inventory - software revision Subtype (7)
      Software revision 3.13.0-32-generic
    Organization specific TLV (127), length 8: OUI ANSI/TIA (0x0012bb)
      Inventory - manufacturer name Subtype (9)
      Manufacturer name QEMU
    Organization specific TLV (127), length 36: OUI ANSI/TIA (0x0012bb)
      Inventory - model name Subtype (10)
      Model name Standard PC (i440FX + PIIX, 1996
    End TLV (0), length 0
^C
1 packet captured
1 packet received by filter
0 packets dropped by kernel


追記 2015/03/05

Vethで直結したKVM間でのLLDP送受信には成功したが、実際にOpenFlowスイッチを検証し始めると、
2台のKVM(それぞれOpenFlowスイッチ)を跨いだDockerコンテナ間の疎通ができない事が判明した。

パケットキャプチャによる切り分けや、Web情報の調査の結果、MacvtapとNICの接続点で、ARPリプライが
中継されない仕様(バグ?)が存在するようです。

以下の図のPing用コンテナ①からPing用コンテナ②へのICMPに先立つARP解決で、①からのリクエストに
②が返したARPリプライが、戻り経路のVeth~Macvtap接続点で中継されない事象が生じました。

なお、以下の策もワークアラウンドとはなりませんでした。
 - MacvtapやVethのNamespaceをホストOSのデフォルトと変更する
 - 同上のインタフェイスにてマルチキャスト関連のフラグなどをonにする(ip link setコマンド)

macvtap_malfunc.png



結局、妥協した迂回策として、Veth直結していた部分をOpen vSwitchとし、そのOVSに2アームのインタフェイス間を
相互に素通しする「仮想パッチパネル」設定を、StaticなOpenFlowルールとして設定する事で、LLDPに加えてICMP等の
通常のEnd-to-End通信も疎通可能な状況を実現できました。

ただ、解決策としてエレガントさを欠くので、継続して他のワークアランドも検討したいと思っています。

virtpatch.png

仮想パッチパネル用OpenFlow設定@ホストOS
[root@fedo21]# ovs-ofctl add-flow ovbr0 in_port=1,action=output:2
[root@fedo21]# ovs-ofctl add-flow ovbr0 in_port=2,action=output:1

[root@localhost ~fedo21]# ovs-ofctl dump-flows ovbr0
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=284.702s, table=0, n_packets=9, n_bytes=2806, idle_age=6, priority=0 actions=NORMAL
 cookie=0x0, duration=68.381s, table=0, n_packets=0, n_bytes=0, idle_age=68, in_port=1 actions=output:2
 cookie=0x0, duration=2.384s, table=0, n_packets=0, n_bytes=0, idle_age=2, in_port=2 actions=output:1
YohKmb
ネットワーク、セキュリティのエンジニア。CISSP。
https://github.com/YohKmb
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away