第9回~今回はDPDKアプリケーションの開発環境の構築をテーマに説明します。2019年08月30日公開はじめにこんにちは、NTTテクノクロス株式会社の寺尾です。今回はDPDKアプリケーションの開発環境をテーマに説明します。Worldのサンプルプログラム環境でコンパイルをしてきました。構築方法は、マシン環境によって変わります。今回は以下の条件で説明します。(LTS)それでは、DPDKをコンパイルする前に必要な事前準備について解説します。最初にBIOS設定についてですが、今まで説明していた機能であれば特別なBIOS設定をしなくとも問題ありません。一部の機能に関しては、BIOS設定が必要がありますので、詳しく知りたい方はDPDKの公式ページ(※1)を参照してください。BIOS設定で「ハイパースレッティングテクノロジ」が有効化(※2)されていれば、DPDKで使用できるCPU(論理プロセッサ)が増えます。次にDPDKを扱うために必要なパッケージをインストールします。DPDKを動作させるスタンダードなOSはLinuxであり、今まではDebian系のUbuntuを中心に説明をしてきました。その他にもRedhat系は良く利用するかと思いましたので、今回は必要なパッケージはDebian系とRedhat系を取り上げて説明します。それぞれ以下のディストリビューションを例として紹介します。7.6まずはパッケージを最新にします。update次に開発に必要なパッケージをインストールします。Tools」をgroupinstallすると、一括でインストールできるため便利です。Tools"コンパイラですが、Linuxは「gcc(バージョン4.9以降)」が推奨されています。clang(※3)やicc(※4)も使えますが必須ではないため、今回は割愛します。DPDKはigb_uioなどのカーネルモジュールをビルドするため、カーネルモジュールに必要なパッケージをインストールします。-r"コマンドでカーネルバージョンを指定しています。-r)DPDKをコンパイルするためにはNUMA関連のパッケージが必要です。PCAP-PMDを利用する場合は、PCAPに必要なパッケージをインストールします。第6回~の「PCAP-PMDとは」で解説しています。libpcap-devel最後に"dpdk-devbind.py"などのスクリプトを使うために、python(python2系なら2.7以降、python3系なら3.2以降)が必要です。第6回~の「uio_pci_genericの使い方」で解説しています。id(物理CPU上の物理コア)が一致するprocessor(論理プロセッサ)が複数ある」場合、ハイパースレッティングテクノロジが有効です。以下の場合、物理CPU:0上の物理コア:0がハイパースレッディングテクノロジにより、2つの論理プロセッサ:0と16として扱えるようになっています。Compilerhttps://software.intel.com/en-us/c-compilersコンパイル環境に関してこれまではDPDKのセットアップツールを利用してコンパイルしてきました。今回は細かくコンパイル環境に関して説明します。第1回~の「DPDKの環境準備」では、DPDKのセットアップツールで"x86_64-native-linuxapp-gcc"を選択することでコンパイルを行っていました。"x86_64-native-linuxapp-gcc"が「コンパイル環境」となります。Target」と表記されています。コンパイル環境を指定することで、DPDKは動作環境に最適化されたコンパイルを行えるようになっています。コンパイル環境の書式は"ARCH-MACHINE-EXECENV-TOOLCHAIN"です。書式の各要素について説明します。ARCHとMACHINEの組み合わせで使用するCPUを指定します。Intel社の64bit-CPUなら"x86_64-native"、IBM社のPOWER8なら"ppc_64-power8"となります。動作環境(OS)の指定です。Linux(linuxapp)かFreeBSD(bsdapp)の2択です。コンパイラの指定です。gccやclangなど使用するコンパイラを指定します。showconfigs"コマンドを実施することで確認できます。環境に合わせたコンパイル環境を使用するようにしてください。Environmentshttps://doc.dpdk.org/guides-18.11/linux_gsg/build_dpdk.html#installation-of-dpdk-target-environmentsDPDKのコンフィグDPDKは必要な機能などを設定するためのconfigファイルが用意されています。場合によっては必要な設定をコンパイル前に実施する必要がありますので、いくつか紹介します。第6回~で、PCAP-PMDを使うために「common_base」というファイルを編集したことを覚えていますでしょうか。dpdk-version/config/common_base・・・#CONFIG_RTE_LIBRTE_PMD_PCAP=nCONFIG_RTE_LIBRTE_PMD_PCAP=y・・・このようにDPDKのconfigファイルで機能の有効化をすることができます。この他にも「DPDKで利用するリソースの上限」も設定ファイルで指定します。以下はDPDKアプリケーションで使用可能なポート数の上限を64に変更する例です。dpdk-version/config/common_base・・・#CONFIG_RTE_MAX_ETHPORTS=32CONFIG_RTE_MAX_ETHPORTS=64・・・DPDKのconfigファイルで可能な設定の一部を以下に示します。'n'を設定すると、DPDKを静的ライブラリでコンパイルする。'y'を設定すると、DPDKを共有ライブラリでコンパイルする。(※6)DPDKで使用する機能を有効化したりリソースの上限値を調節することができます。必要な設定を行い、再コンパイルしてください。静的ライブラリと共有ライブラリライブラリにはプログラム内に静的に組み込む「静的ライブラリ」と、プログラム実行時に動的に呼び出す「共有ライブラリ」の2種類あります。実行ファイルに静的ライブラリを組み込むことを「スタティックリンク」、プログラムを実行する時にライブラリを呼び出すことを「ダイナミックリンク」と呼びます。DPDKライブラリはどちらの形式にも対応できます。違いに関して、以下に示します。ライブラリの呼び出しが早い。アプリケーションのサイズが大きい。アプリケーションのサイズが小さくなるため、プロセス起動が早い。動的にライブラリを呼び出すため、初回のライブラリ呼び出しに時間がかかる。DPDKは設定によってどちらのライブラリでコンパイルするか切り替えられます。DPDKでは明示的に指定しない限り静的ライブラリを組み込み実行ファイルを作成します。今回はセットアップツールを使わずにmakeコマンドでDPDKライブラリを作成する方法を紹介します。DPDKのconfigファイルの変更を確認するために「静的ライブラリ」と「共有ライブラリ」の2つのパターンで行います。DPDKを配置したディレクトリまで移動し、環境変数を設定します。これまでの記事でも何度か登場した環境変数"RTE_SDK"と"RTE_TAEGET"の設定が必要です。"RTE_SDK"にはDPDKを配置したディレクトリパスを、"RTE_TAEGET"はコンパイル環境を指定します。RTE_TARGET=x86_64-native-linuxapp-gcc次にDPDKのconfigファイルを設定します。第6回~では直接「common_base」を編集していましたが、コンパイル環境に合わせたconfigファイルを作成してから編集する方が望ましいです。config"コマンドで作成できます。この時、変数:"T"でコンパイル環境を、変数:"O"でDPDKのconfigファイルやライブラリの出力先ディレクトリ名を指定します。今回は"O"と"C"でコンパイル環境名を指定しています。config"で作成されたディレクトリ内の「.config」となります。.config・・・まずはconfigファイルの編集を行わないで、デフォルト通り静的ライブラリを作成します。config"コマンドで作られたディレクトリ内にコンパイル用のMakefileが生成されているので、そこまで移動してから"makeコマンド"を実行します。[x86_64-native-linuxapp-gcc]コンパイル後、DPDKライブラリはlibディレクトリ配下に出力されています。libディレクトリ配下を確認すると、以下のようにDPDKの静的ライブラリ(拡張子が.aのファイル)が作成されていることがわかります。Worldサンプルアプリケーションをコンパイルし、実行ファイルにDPDKライブラリがどう組み込まれているか確認してみましょう。ここでは、nmコマンド(※7)を利用して、実行ファイルにrte_eal_init()がどう組み込まれているか確認しています。rte_eal_init上記のようにrte_eal_init()にアドレスが割り振られ、実行ファイル内に組み込まれていることがわかります。次にDPDKのconfigファイルを変更して共有ライブラリを作成してみましょう。clean"コマンドで削除できます。completeDPDKのconfigファイルを編集して、共有ライブラリを有効化します。以下のように「CONFIG_RTE_BUILD_SHARED_LIB」を"n"から"y"に変更します。library#CONFIG_RTE_BUILD_SHARED_LIB=nCONFIG_RTE_BUILD_SHARED_LIB=y先ほどと同様にmakeします。make完了後、libディレクトリ配下に、今度はDPDKの共有ライブラリ(拡張子が.soのファイル)が作成されていることがわかります。librte_acl.so.2.1・・・なお、DPDKを共有ライブラリ化した場合、アプリケーションがダイナミックリンク出来るように設定が必要です。このために"/etc/ld.so.conf.d/"配下にDPDK共有ライブラリへのパスを記載したファイルを作成します。作成するファイル名は拡張子が".conf"である必要があります。今回は「libdpdk.conf」という名前のconfigファイルとしました。(例)/opt配下にDPDKを展開し、x86_64-native-linuxapp-gcc配下にDPDKライブラリを出力した場合/opt/dpdk-stable-18.11.2/x86_64-native-linuxapp-gcc/libこの後、ldconfigコマンド(※8)を実行し、DPDKライブラリを共有ライブラリとして使用できるようにします。Worldサンプルアプリケーションをコンパイルし、共有ライブラリとダイナミックリンクが行われるか確認してみましょう。worldサンプルアプリケーションをコンパイル後、lddコマンド(※9)で共有ライブラリとのリンクを確認できます。(0x00007fe74f98e000)・・・また、静的ライブラリ時と同様に、nmコマンドでDPDKライブラリが実行ファイル内にどう組み込まれているか確認します。今度はrte_eal_init()にアドレスが割り振られておらず、未定義扱いになっているため、実行ファイル内にDPDKライブラリが組み込まれていないことがわかります。lddhttps://linuxjm.osdn.jp/html/ld.so/man1/ldd.1.htmlDPDKを共有ライブラリ化した場合の注意点についてDPDKを共有ライブラリ化した場合、1点注意が必要になります。共有ライブラリ化対象にはPMDなどのドライバも含められますが、DPDKアプリケーションを実行するまで具体的なNICの種類が分からないため、事前に利用すべきPMDが分からない問題があります。そのため、DPDKにはアプリケーション実行後に読み込む共有ライブラリを指定する方法がありますので解説します。Sampleを起動する方法を記載します。第2回~を参照してください。動作環境は先ほどDPDKを共有ライブラリでコンパイルした環境を利用します。読み込む共有ライブラリを指定する方法はいくつかありますが、今回はconfigファイルで設定したディレクトリからドライバを探す方法を紹介します。DPDKのconfigファイルを編集して「CONFIG_RTE_EAL_PMD_PATH」にドライバを格納しておくディレクトリへのパスを指定します。ここでは"/opt/dpdk-stable-18.11.2/x86_64-native-linuxapp-gcc/drivers"の配下にドライバを格納するように指定しました。disable)#CONFIG_RTE_EAL_PMD_PATH=""CONFIG_RTE_EAL_PMD_PATH="/opt/dpdk-stable-18.11.2/x86_64-native-linuxapp-gcc/drivers"それでは、"drivers"ディレクトリを作成し、DPDKをコンパイルします。Sampleで使用するドライバを"drivers"へ移します。librte_mempool_ring.so"を"drivers"配下にコピーします。Sampleで使用するライブラリだけを格納することを推奨します。あとは今までの方法でアプリケーションをコンパイルして実行します。Sampleが正常に起動できました。Worldサンプルアプリケーションの環境をそのまま利用していました。実際に開発する場合は、ソースコードのファイルやディレクトリ構成を任意にしたい、バイナリ名は独自に定義したいなどあると思います。そのような場合は開発者が"Makefile"を作成する必要がありますので、その作成方法を説明します。第7回~DPDK入門第8回で作成したDPDKアプリケーションの「初期化処理」と「パケット処理」に分割するように拡張します。ソースファイルを初期化処理は「main.c」、パケット処理は「fwd.c」に分割。ヘッダファイルとして「fwd.h」を用意し、パケット処理を外部からヘッダファイルをincludeすることで呼び出せるようにする。以上を踏まえた構成イメージを以下に示します。Makefile作成DPDKアプリケーションのMakefileは独自に作成することもできますが、依存するライブラリや定義が多く大変です。そこで、DPDKの公式ページで紹介されている方法だと簡易にMakefileが作成できますので、この方法を解説します。Makefileの先頭で"rte.vars.mk"をインクルードする必要があります。"rte.vars.mk"はDPDKを展開したディレクトリの"mk/"ディレクトリ配下にあります。$(RTE_SDK)/mk/rte.vars.mkDPDKアプリケーションのバイナリ名を変数:"APP"で指定します。今回は"my_app"という名前のバイナリを作成するように指定しました。my_appコンパイル対象のソースコードは変数:"SRCS-y"で指定します。今回は"main.c"と"fwd.c"を指定します。main.cコンパイルオプションは通常のMakefileを作成する時と同様に、変数:"CFLAGS"で指定します。$(WERROR_FLAGS)今回指定しているコンパイルオプションについて説明します。-O3は、コンパイル時に適用する最適化レベルです。DPDKアプリケーションは大抵の場合、高い処理速度を求められるので、最も強い最適化である"O3"を指定します。最適化について、詳しくはgccのmanページ(※11)を参照してください。WERROR_FLAGSは、コンパイラの警告設定です。"rte.vars.mk"をインクルードすることにより使用可能で、コンパイル環境に合わせた適切な警告設定を行います。必要があればCFLAGSの他にも、LDFLAGSやLDLIBSなどMakefileでよく使う定義が可能です。詳しくはDPDKの公式ページ(※10)を参照してください。最後に、Makefileの終端で"rte.extapp.mk"をインクルードします。このファイルをインクルードすることで、DPDKが用意したMakefileがコンパイルからリンクまで行い、バイナリファイルを作成してくれます。$(RTE_SDK)/mk/rte.extapp.mkなお、DPDKアプリケーションをコンパイルする場合は"rte.extapp.mk"をインクルードしますが、DPDKを利用したライブラリを作成したい場合は"rte.extlib.mk"をインクルードします。この他にもDPDKが用意している目的別のMakefileがありますので、DPDKの公式ページ(※12)を参照してください。Typeshttps://doc.dpdk.org/guides/prog_guide/dev_kit_build_system.html動作確認それでは作成したMakefileを用いてDPDKアプリケーションをコンパイルしてみましょう。ホームディレクトリ配下に"src"ディレクトリを作成し、直下に各ソースコードとMakefileを配置します。main.cDPDKアプリケーションをコンパイルしましょう。DPDKアプリケーションのコンパイルの際には以下の指定が必須となります。my_app.mapコンパイルに成功すれば、DPDKアプリケーションのバイナリファイルが"build"ディレクトリ配下に作成されていることがわかります。my_app・・・なお、以下のようにすることで、バイナリファイルの出力先ディレクトリを変更してコンパイルできます。O=<出力先ディレクトリ名>コンパイル環境の階層化について開発規模が大きい場合、アプリケーションの機能ごとにソースコードを格納するディレクトリを区切ったり、機能間で共通して参照するヘッダファイルを一つのディレクトリにまとめるなど、ソースコードの階層化が必要になると思います。この場合のMakefile作成方法を説明します。先ほどのDPDKアプリケーションの構成を変更し、"src"ディレクトリ配下に"include"と"fwd"というサブディレクトリを作成し、"include"ディレクトリに「fwd.h」を、"fwd"ディレクトリに「fwd.c」を配置する構成にするとしましょう。その場合の構成イメージを以下に示します。この場合、変数:"SRCS-y"で指定するソースコードへのパスを階層化します。今回はfwdディレクトリ配下にfwd.cがあるので、「fwd/fwd.c」と指定しました。main.c・・・また、各ソースコードから「fwd.h」を共通して参照できるように、コンパイルオプションにインクルードディレクトリを追加します。インクルードディレクトリを指定するコンパイルオプションは"-I"です。"rte.vars.mk"をインクルードしていれば、変数:"RTE_SRCDIR"でソースコードのルートパスが取得できるので、それを利用して"include"へのパスを指定します。後は構成イメージ通りにソースコードとMakefileを配置し、makeすることでDPDKアプリケーションの作成が出来ますので、試してみてください。今回作成したコンパイル環境について最後に、今回作成したDPDKアプリケーションのコンパイル環境を公開します。「DPDKアプリケーションのコンパイル」に記載したように動作しますので、試してみてください。本ソースコードおよびMakefileはあくまでサンプルです。本ソースコードおよびMakefileを利用して発生した損害について、当社は一切の責任を負いません。おわりに今回はDPDKアプリケーションの開発環境の構築方法について解説させていただきました。次回はDPDKアプリケーションを開発する際必要不可欠なログ出力機能などを解説する予定です。ご覧いただきありがとうございました。Corporation。