DPDK の環境構築
DPDKはLinuxやBSDのカーネルをバイパスし、NICをユーザランドから直接触ることにより 従来の通信ソフトウェアと比べはるかに高性能に通信を行うことを可能にしたライブラリである。
近年ではDPDKを用いたソフトウェアルーターで145GbEを達成した実装などがある。 itpro.nikkeibp.co.jp
DPDKは環境構築、テストが大変ということから一般ユーザは少なく感じるが、 しっかりとやるべきことをやれば、環境構築も簡単で、高性能な通信ソフトウェアの 開発を行うことができる。ここではその環境構築方法を説明していく。
DPDKの基本的な情報
- DPDK (http://dpdk.org)
- supported nics (http://dpdk.org/doc/nics)
- quick start (http://dpdk.org/doc/quick-start)
- download (http://dpdk.org/download)
こまったらhttp://dpdk.org/doc/を参照する。
公式のドキュメントを見た感想
僕はあまりにも英語ができないのですが、DPDKの公式ドキュメントはかなり読みやすかった 記憶がある。最終更新もかなり最近だったり、なかなか良い。 英語が苦手な僕の仲間はこれも勉強の一環として、本家ドキュメントでやるのがいいかも しれない。丁寧に書いてあるのでわかりやすい。
対応NICか調べる
DPDKに対応したNICかを調べる必要がある。(当たり前) そもそもこれ対応してないと導入する必要ないし、話にならない。。
$ dmesg | grep eth0 [ 9.765177] e1000e 0000:00:19.0 eth0: registered PHC clock [ 9.765181] e1000e 0000:00:19.0 eth0: (PCI Express:2.5GT/s:Width x1) 68:f7:28:66:94:a5 [ 9.765184] e1000e 0000:00:19.0 eth0: Intel(R) PRO/1000 Network Connection [ 9.765210] e1000e 0000:00:19.0 eth0: MAC: 11, PHY: 12, PBA No: 1000FF-0FF [ 13.950987] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready [ 14.255860] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready
こんな感じでe1000eだと分かる。よかった対応しているみたい。 それでは本家ドキュメントに沿って進めていきましょう。
環境構築
手順を以下にしめす。
また環境構築はUbuntu16.04LTS上で行うことを想定している。 最近(14.04以降)のUbuntuなら問題なく行えるだろう。
1. 必要なパッケージのインストール
DPDKで必要なシステムパッケージを以下に示す。 また必須ではないが、インストールしておくことを強く推奨するパッケージも以下に示す。
- GNU make
- coreutils: cmp, sed, gre, arch, etc..
- gcc: version4.5.x 以降
- libc headers
- Linux Kernel Headers またはカーネルソースコード
- glibc.i686 libgcc.i686 libstdc++.i686 and glibc-devel.i686 for intel i686/x86_64
- libpcap-dev (必須ではないが強く推奨)
これらはほとんど通常のUbuntuデスクトップ環境であればすでにはいっているので、 以下のコマンド実行のみで完了できる。
$ sudo apt install -y libpcap-dev
2. DPDKのソースコードの取得, コンパイル
DPDK.orgからソースをダウンロードしてきて任意のディレクトリに展開します。
$ unzip DPDK-xxx.zip $ cd DPDK-xxx $ ls app/ config/ examples/ lib/ LICENCE.GPL LICENCE.LGPL Makefile mk/ scripts/ tools/
それぞれの概要を以下に示す。
- lib: DPDK本体のソースコード
- drivers: pollモード用のドライバ
- app: DPDKのアプリのソース(自動テスト)
- examples: DPDKのアプリの例 (サンプルコード的な)
- config: 関連するフレームワークや設定など
- tools: 関連するフレームワークや設定など
- scripts: 関連するフレームワークや設定など
- mk: 関連するフレームワークや設定など
DPDKのビルドターゲットのフォーマットを以下の様に指定します。
ARCH-MACHINE-EXECENV-TOOLCHAIN
- ARCH: i686, x86_64, ppc_64 (動作マシンのアーキテクチャ)
- MACHINE: native(実機), ivshmem(仮想マシン用)
- EXECENV: linuxapp, bsdapp
- TOOLCHAIN: gcc, icc, clang (コンパイラの種類)
通常はx86_64-native-linuxapp-gcc
をターゲットとする。
ちなみにivshmemとは仮想マシン間での共有メモリに関する技術らしい。。。知らない。
ビルドは以下のコマンドで行う。
$ make install T=x86_64-native-linuxapp-gcc
表記はmake install T=TARGET
TARGETは先ほどのターゲットを指定してやればいい。
また、make config T=TARGET
でビルドなしでbuild/.confign
にコンフィグを反映してくれるので遊びでやってみるといいかもしれない。
ビルドされるとbuild
以下に色々できる。同時にサンプルなどもすべてビルドしてくれる。
build
以下にできるディレクトリの概要を示す。
- app: テストアプリなどが置かれる
- kmod: ロードが必要なカーネルモジュールが置かれる
ビルドが完了すると、DPDKのルートパス直下にターゲット名のディレクトリができているので、 一応確認するとよい。
$ ls x86_64-native-linuxapp-gcc app build hostapp include kmod lib Makefile
3. Linuxカーネル側の設定
DPDKのビルドが完了したので、今度はDPDKを動作させるために必要な設定をLinuxカーネル側で 行う必要がある。手順を以下に示す。
- Hugepagesのマウント
- カーネルモジュールのロード
- ネットワークポートのバインド
3.1 Hugepagesの設定
Hugepagesとはユーザ空間の1page辺りのサイズを大きくする仕組みのこと。 DPDKはユーザランドドライバなのでこれが必要です。 Hugepagesは1MBと1GBの二種類があり、今回は1MBの方を選択する。 より多くのメモリが必要なアプリケーションを開発する場合は1GBの方を選択するとよいが、 今回はその方法は割愛する。
Hugepagesのメモリ領域はブート時に確保するべきである。もしそれができないなら可能な限り 早めにそのメモリを確保するとよい。そうでないと、連続したメモリ領域でなくいくつも断片化 したメモリ領域を使うことになってしまい、アプリケーションの速度低下に影響してしまう。
と公式ドキュメントに書いてあるので起動時にマウントするように設定していく。
設定するにはカーネルの起動オプションにhugepages=1024
を追加する。
/etc/default/grubを編集してgrub-mkconfigをするのが一般的なので、それを行う。
$ sudo vim /etc/default/grub GRUB_CMDLINE_LINUX="" #ここを GRUB_CMDLINE_LINUX="hugepages=1024" #こうする GRUB_CMDLINE_LINUX="hugepages=64" #VMなどでメモリが少ない場合はこうする $ sudo grub-mkconfig -o /boot/grub/grub.cfg #これで設定反映する
Hugepagesの設定は完了したが、これを起動時にマウントするように設定しなくてはいけない。
/etc/fstab
を編集して、先ほど設定したHugepagesを起動時にマウントするようにする。
$ mkdir -p /mnt/huge $ sudo vim /etc/fstab ...末尾に以下を追加 nodev /mnt/huge hugetlbfs pagesize=1GB 0 0
この設定を行ったら一度再起動をするひつようがある。 Hugepagesは起動時にマウントするように設定したからである。 起動中にマウントする方法もあり、DPDKのドキュメントではそれを進めたりしている部分も あるのだが、絶対におすすめしない。
$ sudo reboot
再起動が完了したら次にすすむ
3.2 カーネルモジュールのロード
DPDKのビルド時などに新たに生成されるモジュールもあるが、一般的にuio_pci_generic
というモジュールをロードしておけば、DPDKは動作する。
$ sudo modprobe uio_pci_generic
UIO: ユーザ空間ドライバを作成するための仕組み DPDKはユーザランドデバイスドライバなので、UIOのカーネルモジュールをロードします。
3.3 ネットワークポートのバインド/アンバインド
最後にDPDKがNICを認識するための設定をする必要がある。
通常状態ではカーネルがハードウェアを管理していますが、ここではDPDKで
管理できるように設定をするので、この設定を行うと$ ip addr
でNICがカーネルから
みえなくなるが、再起動すればちゃんともとに戻るので、安心して欲しい。
バインドにはtoolsディレクトリ以下にあるdpdk-devbind.py
を使ってバインドする。
ほとんどのスクリプトで--help, --usage
が使える見たいなので気軽に見てみよう。
usage of dpdk_nic_bind.py --usage --help show usage --status show status. display dpdk's seeable nics. --bind=DRIVER IDORNAME bind to device with driver.
まずNICの状態を確認するには以下のコマンドを実行する。
$ sudo ./tools/dpdk_nic_bind.py --status Network devices using DPDK-compatible driver ============================================ <none> Network devices using kernel driver =================================== 0000:00:19.0 'Ethernet Connection (3) I218-LM' if=eth0 drv=e1000e unused=uio_pci_generic Other network devices ===================== <none>
ここではeth0と言うデバイスがカーネル管理で存在するので、それをDPDK管理に変更します。 以下のようなコマンドでバインドできます。
$ sudo ./tools/dpdk-devbind.py --bind=uio_pci_generic eth0 # インターフェース名を指定する場合 $ sudo ./tools/dpdk-devbind.py --bind=uio_pci_generic 00:19.0 # PCIアドレスを指定する場合
また、DPDKの支配から解除してふだんの状態に戻すには以下ように実行する。
$ sudo ./tools/dpdk_nic_bind.py --bind=e1000e 00:19.0
先ほどのコマンドで、結果を確認する。
$ sudo ./tools/dpdk_nic_bind.py --status Network devices using DPDK-compatible driver ============================================ 0000:00:19.0 'Ethernet Connection (3) I218-LM' drv=uio_pci_generic unused=e1000e Network devices using kernel driver =================================== <none> Other network devices ===================== <none>
これでバインド完了。やったぜ。DPDKがNICを支配するのでifconfigとかでNICが見えなくなる。 ちなみにこの時ルート権限が必要。(まあ何となくそうだよね、ふつう)
面倒くさい作業はこれですべて必要なので、安心してほしい、お疲れ様。
4. サンプルアプリケーションのビルド, 実行確認
4.1 サンプルアプリのコンパイル
DPDKのビルドが完了するとそのターゲットディレクトリ (今回の場合x86_64-native-linuxapp-gcc)以下に DPDKのライブラリやヘッダファイルなどがすべて展開される。 これらのヘッダファイルやライブラリはDPDKを使用したアプリケーションの ビルドで必ず必要になる。アプリケーションのビルドにはいくつかの環境変数を 指定してやる必要がある。今回はDPDKのSDKがどのパスでアクセスできるか、と ターゲットのアーキテクチャ情報の2つである。これらは環境変数として宣言する。
今回は以下のように指定した。 また、永続的に指定する場合は.zshrcや.bashrcに書き込んでおく。
$ export RTE_SDK=/home/slank/Desktop/dpdk $ export RTE_TARGET=x86_64-native-linuxapp-gcc
今回はhelloworldをビルドする。
$ cd $RTE_SDK/examples/helloworld $ meke CC main.o LD helloworld INSTALL-APP helloworld INSTALL-MAP helloworld.map $ ls /build/app/ helloworld* helloworld.map
これで文句なくビルド完了。後は実行だけです。もう少し。。
4.2 サンプルアプリの実行
先ほどビルド完了したhelloworldを実行する。 オプションなどについてはまだ詳しく調べていない
$ sudo ./build/app/helloworld 実行結果は省略
DPDKアプリケーションでは幾つかの共通オプションがあります。
- -c COREMASK コアマスクを16進数で指定
- -n NUM プロセッサごとのメモリチャンネル数
- -b <DOMAIN:BUS:DEVID.FUNC> ポートをブラックリストとする
- –use-device 使うデバイスのみを指定する
- –socket-mem ソケットごとのメモリ指定する
- -m MB プロセッサソケットにかかわらず、Hugepagesからメモリを確保する
- -r NUM メモリランクを指定
- -v バージョン表示
- –huge-dir hugetlbfsのマウントされたパスを指定
- –file-prefix よくわからぬ。。
- –proc-type プロセッサインスタンスのタイプを指定
- –xen-dom0 hugetlbfsを使わずXen上で動かす
- –vmware-tsc-map VMware TSC mapを使う
- –base-virtaddr 仮装アドレスを指定
- –vfio-intr VFIOの割り込みタイプを指定
4.3 追加のサンプルアプリ
${RTE_SDK}/examples 以下にサンプルアプリケーションがおいてあるので、helloworldと同様の方法で かんたんに使えます。DPDK Sample AAApplications User Guideを参考にしましょう。
4.4 追加のテスト用アプリ
DPDK/app 以下には2つのテスト用アプリケーションがありそれぞれ以下のようなテストをします。(かんたんに説明)
- test いろいろなことに対するテストを行います
- testpmd 様々なパケットに対するスループットテストをします
うまく行かなかった場合
Linuxのシステム要件を満たしていない
DPDKアプリケーションを実行するために必要なシステム条件を以下に示す。 これを満たしていない場合、うまく行かない場合があるので、確認して欲しい