Ubuntu Weekly Recipe

第539回 LXDのコンテナからSR-IOV対応デバイスを利用する

この記事を読むのに必要な時間:およそ 8 分

第521回でのLXD 3.0の基本的な使い方,第532回でのLXDコンテナからGPUを利用する方法,第535回でのLXDのネットワーク設定を取り上げました。それらに続き,今回はUbuntu 18.04.1 LTSのLXD 3.0.1にて,SR-IOV対応の10ギガビット・イーサーネットカードをコンテナから利用してみます。

SR-IOV

SR-IOV (Single Root I/O Virtualization) はPCI Expressの仕様の一つで,PCIeデバイスを複数の仮想的なデバイスとして見せる機能です。

ハードウェア側でデバイスを仮想的に分割するため,コンテナや仮想マシンが直接デバイスにアクセスでき,ホストOS上でソフトウェア的に一つのデバイスを共有する場合に比べて少ないオーバーヘッドでI/Oが可能になります。

とても魅力的な機能ですが,利用するにはPCIeデバイスがハードウェアレベルで対応している必要があります。10ギガビット・イーサーネット(10GbE)カードやInfiniBandといった広帯域のネットワークカードは対応しているものが多いようです。また,BIOS(UEFI)もSR-IOVをサポートしている必要があります。

基本的なSR-IOVデバイスの利用方法

まずはSR-IOVがどのようなものか簡単に試してみましょう。少し古いPCIeデバイスですが,筆者の手元にある10GbEカードのIntel X520-DA2がSR-IOVに対応していましたので,これをUbuntu 18.04.1 LTSのマシンに搭載してみます。

lspciコマンドでマシン上のPCI(PCIe)デバイスを一覧表示できます。X520-DA2のコントローラー名82599でgrepしてみましょう。

$ lspci | grep 82599
04:00.0 Ethernet controller: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)
04:00.1 Ethernet controller: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)

X520-DA2はSFP+ポートを2ポート持ちます。上記では各ポートがそれぞれ表示されています。続いてipコマンドでネットワークインタフェースを見てみましょう。

$ ip address
(略)
4: enp4s0f0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:1b:21:bc:04:a2 brd ff:ff:ff:ff:ff:ff
5: enp4s0f1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:1b:21:bc:04:a3 brd ff:ff:ff:ff:ff:ff

ネットワークインタフェース名は環境によって異なり,筆者の環境ではenp4s0f0enp4s0f1となっています。

SR-IOV対応のPCIeデバイスにおいて,これらの物理的なデバイスは「Physical Function」と呼ばれます。これに対し,SR-IOVで作成する仮想的なデバイスは「Virtual Function」と呼ばれます。では実際にこのPhysical Functionの下に複数のVirtual Functionを作成してみましょう。

IntelのSR-IOV対応10GbEカードを使用する場合は,親になるPhysical Functionを事前にインタフェースアップしておきます※1)⁠この例ではenp4s0f0を親とします。

※1
Intelの10GbEカードは親Physical FunctionがインタフェースダウンしているとVirtual Functionがインタフェースアップできないようです。Mellanoxの10GbEカードは親のインタフェースアップは不要らしく,このあたりの挙動はデバイスによって若干異なるようです。
$ sudo ip link set dev enp4s0f0 up

Physical FunctionのstateがUPになっていることを確認します。

$ ip address show enp4s0f0
4: enp4s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:1b:21:bc:04:a2 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::21b:21ff:febc:4a2/64 scope link 
       valid_lft forever preferred_lft forever

Virtual Functionを作成します。Ubuntuを含む,最近の主要なLinuxディストリビューションのkernelであれば,sysfsからVirtual Functionを作成可能です※2)⁠SR-IOV対応のネットワークデバイスの場合,下記のパスにVirtual Function設定用のファイルが存在します。

※2
正確には,kernel 3.8以降であればsysfsからVirtual Functionを作成可能です。
/sys/class/net/ネットワークインタフェース名/device/sriov_numvfs

筆者の環境では,/sys/class/net/enp4s0f0/device/sriov_numvfsになります。

$ ls -l /sys/class/net/enp4s0f0/device/sriov_numvfs
-rw-rw-r-- 1 root root 4096 Sep 22 19:39 /sys/class/net/enp4s0f0/device/sriov_numvfs

$ cat /sys/class/net/enp4s0f0/device/sriov_numvfs
0

このsriov_numvfsファイルにroot権で数字を書き込むことで,その数だけVirtual Functionが作成されます。とりあえず2を書き込んでVirtual Functionを2個作ってみましょう。

$ sudo sh -c 'echo 2 > /sys/class/net/enp4s0f0/device/sriov_numvfs'

lspciコマンドでPCIeデバイス情報を見てみましょう。

$ lspci | grep 82599
04:00.0 Ethernet controller: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)
04:00.1 Ethernet controller: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)
04:10.0 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
04:10.2 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)

「Intel Corporation 82599 Ethernet Controller Virtual Function」という名前でVirutal Functionが2つ作成されていることがわかります。ネットワークインタフェースも見てみましょう。

$ ip address
(略)
4: enp4s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:1b:21:bc:04:a2 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::21b:21ff:febc:4a2/64 scope link
       valid_lft forever preferred_lft forever
5: enp4s0f1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:1b:21:bc:04:a3 brd ff:ff:ff:ff:ff:ff
6: enp4s16: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 62:b5:c8:8f:2b:ce brd ff:ff:ff:ff:ff:ff
7: enp4s16f2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 86:92:1a:8a:a6:f1 brd ff:ff:ff:ff:ff:ff

enp4s16enp4s16f2の2つのネットワークインタフェースが作成されています。この内のenp4s16にIPアドレス172.16.1.20/24を設定してみましょう。

$ sudo ip address add 172.16.1.20/24 dev enp4s16 
$ sudo ip link set dev enp4s16 up
$ ip address show enp4s16
6: enp4s16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 62:b5:c8:8f:2b:ce brd ff:ff:ff:ff:ff:ff
    inet 172.16.1.20/24 scope global enp4s16
       valid_lft forever preferred_lft forever
    inet6 fe80::60b5:c8ff:fe8f:2bce/64 scope link 
       valid_lft forever preferred_lft forever

10GbEのネットワークの対向に位置するIPアドレス172.16.1.11のマシンと通信してみましょう※3)⁠

※3
筆者は10GbE対応のスイッチを所有していないため,この環境ではIntel X520-DA2を2台のマシンに搭載してDirect-Attach Copperケーブルで直結しています。
$ ping -c 4 172.16.1.11
PING 172.16.1.11 (172.16.1.11) 56(84) bytes of data.
64 bytes from 172.16.1.11: icmp_seq=1 ttl=64 time=0.323 ms
64 bytes from 172.16.1.11: icmp_seq=2 ttl=64 time=0.197 ms
64 bytes from 172.16.1.11: icmp_seq=3 ttl=64 time=0.133 ms
64 bytes from 172.16.1.11: icmp_seq=4 ttl=64 time=0.198 ms

--- 172.16.1.11 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3049ms
rtt min/avg/max/mdev = 0.133/0.212/0.323/0.071 ms

通信できていますね。

ホストマシンからVirtual Functionを削除する場合は,sriov_numvfsファイルに0を書き込みます。

$ sudo sh -c 'echo 0 > /sys/class/net/enp4s0f0/device/sriov_numvfs'

著者プロフィール

大田晃彦(おおたあきひこ)

Ubuntuでアニメを録画したり積んだりしながら暮らしています。全体的に浅いです。

コメント

コメントの記入