TenForward

技術ブログ。はてなダイアリーから移転しました

SR-IOV を有効にする (2)

前回の続編.

  1. lspciでデバイスの情報を調べます.Intel 82576 を積んだ NIC ですので
    $ lspci | grep 82576
    01:00.0 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
    01:00.1 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
    02:10.0 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:10.1 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:10.2 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:10.3 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:10.4 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:10.5 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:10.6 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:10.7 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:11.0 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:11.1 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:11.2 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:11.3 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:11.4 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
    02:11.5 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
  2. libvirt 上での情報を取得.とりあえず Virtual Function(VF) の一つ目のを使うとして,BUS の番号 "02" をキーワードに.
    $ virsh nodedev-list | grep 02
    pci_0000_00_02_0
    pci_0000_02_10_0 <-これかな?
    pci_0000_02_10_1
      : (snip)
    pci_0000_02_11_4
    pci_0000_02_11_5
      : (snip)
  3. 2で当たりをつけた "pci_0000_02_10_0" をキーワードに libvirtxml を取得します.
    $ virsh nodedev-dumpxml pci_0000_02_10_0
    <device>
    <name>pci_0000_02_10_0</name>
    <parent>pci_0000_00_1c_0</parent>
    <driver>
    <name>igbvf</name>
    </driver>
    <capability type='pci'>
    <domain>0</domain>
    <bus>2</bus>
    <slot>16</slot>
    <function>0</function>
    <product id='0x10ca'>82576 Virtual Function</product>
    <vendor id='0x8086'>Intel Corporation</vendor>
    <capability type='phys_function'>
    <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
    </capability>
    </capability>
    </device>
  4. 目的のVFをゲストから使えるようにホストから dettach します.
    $ virsh nodedev-dettach pci_0000_02_10_0
    Device pci_0000_02_10_0 dettached
    このコマンドを実行した後,ホストで ip link show とかしてみると,対応するデバイスが見えなくなっていました.
  5. おもむろに対応するVMの設定ファイルを編集します.
    $ virsh edit VM01
    <device>セクションの最後に以下のように対象となるデバイスの設定を追加します.
        <hostdev mode='subsystem' type='pci' managed='yes'>
    <source>
    <address bus='0x02' slot='0x10' function='0x0'/>
    </source>
    </hostdev>
    bus, slot, function は 3 で調べた xml のそれぞれの要素の値を 16 進数にしたものです.

これで VM を起動すると,きちんと認識されています.igbvfドライバが 82576 の VF 用のドライバ,e1000 は元々VMに作成してあった仮想NICです.

[    2.102129] e1000: Intel(R) PRO/1000 Network Driver - version 7.3.21-k8-NAPI
[    2.119907] e1000: Copyright (c) 1999-2006 Intel Corporation.
[    2.156948] igbvf 0000:00:07.0: Intel(R) 82576 Virtual Function
[    2.173402] igbvf 0000:00:07.0: Address: 3e:5c:08:cf:17:f3
[    2.189737] igbvf 0000:00:07.0: MAC: 1
[    2.237890] ACPI: PCI Interrupt Link [LNKC] enabled at IRQ 10
[    2.254417] e1000 0000:00:03.0: PCI INT A -> Link[LNKC] -> GSI 10 (level, high) -> IRQ 10
[    2.271023] e1000 0000:00:03.0: setting latency timer to 64
[    2.590602] e1000 0000:00:03.0: eth1: (PCI:33MHz:32-bit) 52:54:00:7f:98:80
[    2.624792] e1000 0000:00:03.0: eth1: Intel(R) PRO/1000 Network Connection

おまけ

さて,設定を終えてパフォーマンスを測定してみようかと思ったのですが,手元に 100M のスイッチしかありません.仕方ないのでVMが稼働しているホスト上からゲストOSに向けてnetperfを実行してみました.とりあえずのテストだったので,以下のような感じで実行しています.

$ netperf -H 172.16.44.12

テスト対象は

  • e1000
  • virtio-net
  • vhost-net (ホスト上で vhost_net ドライバをロードしておいてVMを起動すればコレで動作します)
  • SR-IOV

でやってみました.

結果は「vhost-net > virtio-net > SR-IOV > e1000」で,「あれ?意外に SR-IOV 遅いぞ」とつぶやいていたら @peo3 さんから

その構成だとvirtioはオンメモリ処理だけど、SR-IOVだとパケットがNICまで行ってUターンしてくるのでvirtioに負けるのも仕様がない気がします

https://twitter.com/#!/peo3/status/144749113496449024

とリプライを.そりゃそうだ.ありがとうございました.

ちゃんとした測定はまた後日...

SR-IOV を有効にする

Ubuntu Linux 11.10 で SR-IOV を有効にするメモ.

ホストは 日本HP Redirect 日本HP 旧モデル情報 8100 Elite SF−スペック (Directplusモデル)Core i5 でメモリ 8GB 積んだマシンです.

# lspci | grep 82576
01:00.0 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
01:00.1 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)

こんなチップを載せたカード.

# lspci -v -s 01:00.0
01:00.0 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
	Subsystem: Intel Corporation Gigabit ET Dual Port Server Adapter
	Flags: bus master, fast devsel, latency 0, IRQ 16
	Memory at f0800000 (32-bit, non-prefetchable) [size=128K]
	Memory at f0000000 (32-bit, non-prefetchable) [size=4M]
	I/O ports at 1100 [size=32]
	Memory at f0840000 (32-bit, non-prefetchable) [size=16K]
	[virtual] Expansion ROM at f8000000 [disabled] [size=4M]
	Capabilities: [40] Power Management version 3
	Capabilities: [50] MSI: Enable- Count=1/1 Maskable+ 64bit+
	Capabilities: [70] MSI-X: Enable+ Count=10 Masked-
	Capabilities: [a0] Express Endpoint, MSI 00
	Capabilities: [100] Advanced Error Reporting
	Capabilities: [140] Device Serial Number 00-1b-21-ff-ff-a5-72-48
	Capabilities: [150] Alternative Routing-ID Interpretation (ARI)
	Capabilities: [160] Single Root I/O Virtualization (SR-IOV)
	Kernel driver in use: igb
	Kernel modules: igb

SR-IOV 機能搭載.この機能を有効にするために /etc/default/grub で以下のように起動オプションを与えます.

GRUB_CMDLINE_LINUX="intel_iommu=on pci=assign-busses"

update-grub コマンドを実行してから,リブート.

# modprobe -r igb && modprobe igb max_vfs=7
# lspci | grep 82576
01:00.0 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
01:00.1 Ethernet controller: Intel Corporation 82576 Gigabit Network Connection (rev 01)
02:10.0 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:10.1 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:10.2 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:10.3 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:10.4 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:10.5 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:10.6 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:10.7 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:11.0 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:11.1 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:11.2 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:11.3 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:11.4 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)
02:11.5 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01)

使ってないけどたくさんインターフェースが見えますね.ホストからもこういう風に見えるんだ...

$ ip addr show | egrep "eth[0-9]*:"
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br100 state UP qlen 1000
8: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
9: eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
10: eth3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
11: eth4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
12: eth5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
13: eth6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
14: eth7: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
15: eth8: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
16: eth9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
17: eth10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
18: eth11: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
19: eth12: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
20: eth13: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
21: eth14: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
22: eth15: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
23: eth16: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000

Redhat の文書だと intel_iommu=on のカーネルオプションのみ記載されていたりしますが,これだけだと

SR-IOV: bus number out of range

こんなエラーが出たりしていました.

virt-manager の LXC サポート (3)

前回,

コンテナ上でシャットダウンすると,なぜかホストが突然死します.

http://d.hatena.ne.jp/defiant/20111101/1320146265

なんてことを書いていましたが,ログを見ると

lxcContainerDropCapabilities:1012 : libcap-ng support not compiled in, unable to clear capabilities

なんてログが出ていました.良く意味が分かりませんが,capability の話なので,じゃあ libcap-ng を入れてみようということで,libcap-ng を入れて libvirt を再コンパイルしたら,無事シャットダウンされるようになりました.もちろんホストは無事ですww

CAP_SYS_BOOT が落ちてないコンテナが動いていた,ということのようですね.

/dev/ptmx でハマり道

lxc を使用する際,仮想端末回りをセキュアにするために newinstance オプションを付けて devpts をマウントするのは,以前 紹介ずみです.ココでも少しハマりましたが,またハマったのでメモっておきます.

devpts の newinstance オプション

カーネル付属文書を読んでみると

To workaround this and have strict isolation, all mounts of devpts,
including the mount in the root container, should use the newinstance
option.

と書かれており,前回やったようなホスト側だけでなく,コンテナ側でも newinstance オプションを付けるのが良いようです.最近の lxc だと,src/lxc/conf.c 内に

        if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL,
                  "newinstance,ptmxmode=0666")) {
                SYSERROR("failed to mount a new instance of '/dev/pts'");
                return -1;
        }

というようなコードがあるため,コンテナ側は自動的にそのようにマウントされるようです.これは libvirt の lxc ドライバでも同様のようです(私は未確認).

ホスト側での newinstance 付きマウント

ホスト側では /etc/fstab で

none    /dev/pts        devpts  gid=5,mode=620,newinstance,ptmxmode=0666        0       0

という感じで記述し,既存の /dev/ptmx を カーネル付属文書にあるように,

        $ chmod 0666 /dev/pts/ptmx
        $ rm /dev/ptmx
        $ ln -s pts/ptmx /dev/ptmx

というような処理を /etc/rc.d/rc.local で行っていました.

が,このままコンテナ内で udevd が普通に起動するように設定されたコンテナを起動すると,普通にホスト側にも

KERNEL[1320669272.186163] add /devices/virtual/tty/ptmx (tty)
UDEV_LOG=3
ACTION=add
DEVPATH=/devices/virtual/tty/ptmx
SUBSYSTEM=tty
DEVNAME=ptmx
DEVMODE=0666
SEQNUM=2128
MAJOR=5
MINOR=2

なんてカーネルイベントが飛んできていました.そこで udev のデフォルトのルール 50-udev-default.rules内の

KERNEL=="ptmx",                 GROUP="tty", MODE="0666"

というルールが発動し,/dev/ptmx が見事に復活し,ホストで仮想端末が開けなくなるとか,色々と問題が起きてしまってました.(;_;)

ホスト側で問題が起きない設定

この設定ではダメな事がわかったので,どうしたかというと,コンテナ起動時にホスト側にも ptmx の add されるイベントが飛んできてるわけですから,それをそのまま利用する形で,udev のルールに前述のシンボリックリンクが作成されるようなルールを書きました.

50-udev-default.rules より早く読み込まれる必要があるため,例えば 00-ptmx.rules というようなファイルを /etc/udev/rules.d/ 以下に置きます.内容は

KERNEL=="ptmx", NAME="pts/%k", SYMLINK+="%k"

というのでとりあえず問題なく動いています.

以上,間違いがあれば指摘プリーズ!