第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
してみましょう。
X520-DA2はSFP+ポートを2ポート持ちます。上記では各ポートがそれぞれ表示されています。続いてip
コマンドでネットワークインタフェースを見てみましょう。
ネットワークインタフェース名は環境によって異なり、筆者の環境ではenp4s0f0
、enp4s0f1
となっています。
SR-IOV対応のPCIeデバイスにおいて、これらの物理的なデバイスは「Physical Function」と呼ばれます。これに対し、SR-IOVで作成する仮想的なデバイスは「Virtual Function」と呼ばれます。では実際にこのPhysical Functionの下に複数のVirtual Functionを作成してみましょう。
IntelのSR-IOV対応10GbEカードを使用する場合は、親になるPhysical Functionを事前にインタフェースアップしておきます[1]。この例ではenp4s0f0
を親とします。
Physical FunctionのstateがUPになっていることを確認します。
Virtual Functionを作成します。Ubuntuを含む、最近の主要なLinuxディストリビューションのkernelであれば、sysfsからVirtual Functionを作成可能です[2]。SR-IOV対応のネットワークデバイスの場合、下記のパスにVirtual Function設定用のファイルが存在します。
筆者の環境では、/sys/class/net/enp4s0f0/device/sriov_numvfs
になります。
このsriov_numvfs
ファイルにroot権で数字を書き込むことで、その数だけVirtual Functionが作成されます。とりあえず2
を書き込んでVirtual Functionを2個作ってみましょう。
lspci
コマンドでPCIeデバイス情報を見てみましょう。
「Intel Corporation 82599 Ethernet Controller Virtual Function」という名前でVirutal Functionが2つ作成されていることがわかります。ネットワークインタフェースも見てみましょう。
enp4s16
、enp4s16f2
の2つのネットワークインタフェースが作成されています。この内のenp4s16
にIPアドレス172.16.1.20/24
を設定してみましょう。
10GbEのネットワークの対向に位置するIPアドレス172.16.1.11
のマシンと通信してみましょう[3]。
通信できていますね。
ホストマシンからVirtual Functionを削除する場合は、sriov_numvfs
ファイルに0
を書き込みます。
コンテナからSR-IOVデバイスを利用する
今度はLXDからSR-IOV対応のネットワークデバイスを利用してみましょう。こちらもIntel 10GbEカードを使用する環境では事前に親Physical Functionをインタフェースアップしておきます[4]。
lxc config device add
コマンドでコンテナにnic
デバイスを追加します。この際、nictype=sriov
を指定することで、Virtual Functionがコンテナにネットワークインタフェースとして追加されます。
各項目の詳しい説明はUbuntu weekly recipeの535回、およびLXDのドキュメントを参照してください。
nictype=sriov
を指定する場合、parent=
に親となるPhysical Functionを指定します。LXDがこのPhysical Functionを調べ、Virtual Functionが未作成であれば作成し、未使用のVirtual Functionをコンテナに割り当てます。LXDがVirtual Functionを作成・設定してくれるため、lxdグループに所属するユーザーアカウントであれば、コンテナを介してSR-IOV対応のネットワークデバイスを利用できます。
parent=
にSR-IOV未対応のネットワークインタフェースを指定した場合や、ネットワークインタフェースの最大Virtual Function数[5]を超過した場合などは、lxc
コマンドがエラーを返します。
実際に試してみましょう。この例ではubuntu:18.04イメージからnadeshiko
という名前でコンテナを作成、起動しています。
コンテナnadeshiko
にVirtual Functionをネットワークインタフェースeth1
として追加します(※6、※7)。
コンテナnadeshiko
内でip
コマンドを実行して確認してみましょう[8]。ここではホスト上からlxc exec
コマンド経由で実行しています。
コンテナnadeshiko
のeth1
にIPアドレス172.16.1.12/24
を設定し、インタフェースアップします。
lxc list
コマンドでもnadeshiko
のeth1
にIPアドレスが振られていることが確認できます。
対向のIPアドレス172.16.1.11
のマシンと通信してみましょう。
コンテナnadeshiko
と対向のマシンにネットワークスループット計測用ソフトウェアのiperf3
をインストールし、転送スピードを計測してみます。
Bandwidthの値をみると9.42 Gbit/secの転送スピードが出ていることがわかります。
複数のコンテナでSR-IOVデバイスを利用する
もう一台コンテナを作成して、同じPhysical Function enp4s0f0
を親に持つ別のVirtual Functionを割り当ててみましょう。コンテナ名はshimarin
とします。
コマンドはnadeshiko
にeth1
を割り当てた時とコンテナ名が異なるだけです。LXDが未使用のVirtual Functionを選んでコンテナに割り当てるため、ユーザーはVirtual Functionの利用状況を意識せずに済みます。
コンテナshimarin
のeth1
にはIPアドレス172.16.1.13/24
を設定します。
shimarin
にもiperf3
をインストールし、nadeshiko
とshimarin
の2台で対向のIPアドレス 172.16.1.11
のマシン間のスループットを計測してみましょう。対向のマシンではサーバーモードのiperf3
を2プロセス、それぞれポート5201、5202で待ち受けさせています。nadeshiko
からポート5201宛に、shimarin
からポート5202宛に、iperf3
のクライアントモードで同時に接続します。実行タイミングがずれると正確な転送スピードが測れないため、ここではsystemd-run
コマンドを使用してホスト上のsystemd(systemd.timer)から同時刻にiperf3
を実行してみます。
--user --timer-property=AccuracySec=1s --on-calendar='2018-09-25 22:55:00 JST'
までがsytemd.timerの設定です。--user
でユーザー権限での登録、--timer-property=AccuracySec=1s
でタイマー精度を1秒に指定(デフォルトは1分)、--on-calendar='2018-09-25 22:55:00 JST'
でコマンドの実行開始時刻を指定しています。lxc exec
以降が各コンテナ内でのiperf3
実行部分です。コンテナ内でiperf3
の出力をファイルにリダイレクトする都合上、/bin/sh
コマンドの-c
オプションでシェルプロセスとして実行しています。
指定した実行開始時刻になると、ホスト上のsystemd.timerから各lxc exec
コマンドが実行されます。実行終了まで待って結果を見てみましょう。
コンテナnadeshiko
の実行結果です。
コンテナshimarin
の実行結果です。
nadeshiko
とshimarin
のどちらも4.71 Gbits/sec程度、合計9.42 Gbits/secの転送スピードが出ています。10GbEのほぼ全帯域を2コンテナで半分ずつ利用できていることがわかります。
コンテナからSR-IOVデバイスを削除する
コンテナからSR-IOVデバイスを削除する方法は、他の種類のデバイスを削除する場合と変わりません。
nictype=sriov
のデバイスを削除すると、そのコンテナに割り当てられていたVirtual FunctionはLXDによりリリースされ、他のコンテナから利用可能になります。同様に、コンテナ自体を削除した場合も、LXDが自動的にVirtual Functionを回収してくれます。