情報畑でつかまえてロゴ
本サイトは NTTテクノクロスが旬の IT をキーワードに
IT 部門が今知っておきたい最新テクノロジーに関する情報をお届けするサイトです

DPDKのパケット処理 ~DPDK入門 第2回~

DPDKはネットワーク処理の高速化に対して力を発揮するアプリケーションの開発キットです。2012年にリリースされ徐々に定着しつつありますが、使い方が特殊なのでその使い方などを中心に解説します。

はじめに

こんにちは、NTTテクノクロス株式会社の寺尾です。

前回DPDKに関して概要と簡単なDPDKの動かし方を紹介させていただきました。今回は前回紹介できなかったDPDKのパケット処理を解説します。解説内容は、パケット処理を確認するための環境構築、パケット処理を実施するDPDKサンプルアプリケーションの紹介、パケット処理の確認方法を関連する知識なども補足しながら解説していきます。

今回はDPDKに対応したNICを使います。DPDKのNICのサポート状況に関しては、下記を参照ください。
http://core.dpdk.org/supported/

イメージ画像

動作環境に関して

今回の動作環境は、以下の構成になります。
・物理マシン2台 (ホストA, ホストB)
 ・NICを2つ
・1台の物理マシンは以下が必須条件
 ・DPDKに対応したNICを2つ
 ・CPUのコアを2つ
実際の動作環境を構築する人は、問題ないか確認しましょう。今回確認した環境は以下となります。NICはIntel製のIGBドライバに対応したものを使用しました。ホストA及びホストB間は直結していますが、スイッチなどの機器を挟まない構成を推奨します。理由は後ほど動作環境の解説の中で記述しています。

環境構築
環境構成の設定から解説します。まずは2台のマシンのNICはカーネルドライバが割当たっている状態で、疎通ができているかを確認します。

まずはNICに対して環境構成図通りのIPアドレスを設定していきます。以下のコマンドで行います。

hosta$ sudo ifconfig eth0 192.168.11.1 netmask 255.255.255.0
hosta$ sudo ifconfig eth0 up

hosta$ ifconfig eth0
eth0 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet addr:192.168.11.1 Bcast:192.168.11.255 Mask:255.255.255.0
inet6 addr: xxxx::xxxx:xxxx:xxxx:xxxx/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:648 (648.0 B)
Memory:92000000-920fffff

IPアドレスの表示が意図通りに設定されているかを確認下さい。同じようにホストAのeth1及びホストB側の設定も行って下さい。問題無く設定できているかは、経路テーブルの内容からIPアドレスとNICの関係が正しく定義できていることを確認します。

hosta$ netstat -nr
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
・・・・
192.168.11.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.12.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
・・・・

設定が終わりましたら、ホストAからホストBに疎通確認を行います。疎通確認前に、hostb側でパケットキャプチャの設定を行います。パケットキャプチャはtcpdumpを使い解説していきます。

hostb$ sudo tcpdump -i eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

ホストB側で準備が整ったら、疎通確認を実施します。今回はpingコマンドで確認を行います。

hosta$ ping 192.168.11.2
PING 192.168.11.2 (192.168.11.2) 56(84) bytes of data.
64 bytes from 192.168.11.2: icmp_seq=1 ttl=64 time=0.319 ms
64 bytes from 192.168.11.2: icmp_seq=2 ttl=64 time=0.150 ms

上記のような反応があれば、成功です。また対向先では以下のように表示がされます。

hostb$ sudo tcpdump -i eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on p1p1, link-type EN10MB (Ethernet), capture size 262144 bytes
19:01:16.814194 ARP, Request who-has 192.168.11.2 tell 192.168.11.1, length 46
19:01:16.814214 ARP, Reply 192.168.11.2 is-at xx:xx:xx:xx:xx:xx (oui DCBX), leng
19:01:16.814296 IP 192.168.11.1 > 192.168.11.2: ICMP echo request, xxxx
19:01:16.814329 IP 192.168.11.2 > 192.168.11.1: ICMP echo reply, xxxx
19:01:17.813177 IP 192.168.11.1 > 192.168.11.2: ICMP echo request, xxxx
19:01:17.813203 IP 192.168.11.2 > 192.168.11.1: ICMP echo reply, xxxx


ここまでが環境準備作業になります。

動作環境の解説

ホストB側のtcpdumpの表示結果を見ると、最初にARPプロトコルが動作し、その後ICMPプロトコルが動作していることが分かります。一方、pingコマンドは「64 bytes from 192.168.11.2」の行数がtcpdumpの「ICPM echo reply」と同期されていることが分かります。

全てのパケットには宛先のmacアドレスが必要になりますが、普段の利用においてmacアドレスを意識することは基本的になく、IPアドレス(あるいはドメイン名)を入力する機会が多いと思います。pingコマンドの例だと、192.168.11.2が該当します。pingコマンドはICMPプロトコルを動作させるために必要な宛先macアドレスを取得するため、tcpdumpからはARPプロトコルが表示されました。

実際の動きを以下の図で解説します。

ARPプロトコルはユーザが意識しない箇所で動作しているプロトコルになっていることが分かります。上記の疎通確認が終わった後であれば、以下のコマンドでIPアドレスとmacアドレスの対応関係が確認できます。

hosta$ arp
Address HWtype HWaddress Flags Mask Iface
・・・・・・・・
192.168.11.2 ether xx:xx:xx:xx:xx:xx C eth0
・・・・・・・・

この対応関係が一度登録された後は、IPアドレスから宛先macアドレスが解決できるため、ICMPパケットを送信する毎にARPプロトコルによるmacアドレスの解決は必要なくなります。このARP情報のエントリはNICのup/downを繰り返すことでリフレッシュできますので、登録の有る無しでパケットキャプチャの表示内容が変わることを試してみてください。

hosta$ sudo ifconfig eth0 down
hosta$ sudo ifconfig eth0 up

IPアドレスとmacアドレスの対応処理はカーネルの機能の一つになりますが、DPDKを動かした場合だと注意が必要になります。例えば、対向先から通信プログラムを動かす際、DPDKアプリケーションがARP機能に未対応の場合は、macアドレスの解決を別の手段での解決が必要になります。

動作環境を直結構成にしている理由は、ARPの情報がスイッチなどの機器にも記憶されますので、予期しない動作になる可能性があるためです。その際は機器もリセットすれば良いのですが手間がかかりますので、直結構成を推奨しています。

動作環境の解説は以上です。今回説明した内容は書籍やインターネットに様々な解説がありますので、興味がある方はいろいろ調べてみてください。

L2 Forwarding Sample

今回紹介するプログラムはDPDKが梱包しているサンプルプログラムの一つのL2 Forwading Sample(※1)になります。このサンプルプログラムでは、パケットの転送処理が体験できます。

※1 L2 Forwarding Sample Application
http://doc.dpdk.org/guides/sample_app_ug/l2_forward_real_virtual.html

DPDKの環境準備

NICに関してカーネル用のドライバからDPDK用のドライバに付け替えます。ホストB側にDPDKアプリケーションをインストールします。まずは現在のNIC状態をifconfigで確認し、環境構成図通りの設定になっているかを確認下さい。

hostb$ ifconfig eth0
eth0 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet addr:192.168.11.2 Bcast:192.168.11.255 Mask:255.255.255.0
inet6 addr: fe80::xxxx:xxxx:xxxx:xxxx/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:38456 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:4918288 (4.9 MB) TX bytes:648 (648.0 B)
Memory:92000000-920fffff

hostb$ ifconfig eth1
eth1 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet addr:192.168.12.2 Bcast:192.168.12.255 Mask:255.255.255.0
inet6 addr: fe80::xxxx:xxxx:xxxx:xxxx/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:847 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:55646 (55.6 KB) TX bytes:648 (648.0 B)
Memory:91f00000-91ffffff


今回はDPDKのコンパイルが実施、メモリの設定まで実施している前提で解説します。未実施の人は、そこまで完了した状態にしてください。メモリ設定までの方法は DPDKとは? ~DPDK入門 第1回~ の「DPDKの環境準備」で解説していますので、参照ください。

それではカーネル用のドライバからDPDK用のドライバに付け替えます。前回紹介したセットアップツールから行います。

hostb$ cd dpdk-<version>
hostb$ export RTE_SDK=`pwd`
hostb$ export RTE_TARGET=x86_64-native-linuxapp-gcc
hostb$ cd $RTE_SDK/usertools
hostb$ ./dpdk-setup.sh

今回の環境はigbのNICを使いますので、[17] Insert IGB UIO module を選択下さい。尚、表示される内容(番号等)は環境によっても変わりますのでご注意下さい。

Option: 17
Unloading any existing DPDK UIO module
Loading uio module
Loading DPDK UIO module

現在のNICの状態は[22] Display current Ethernet/Crypto device settings で確認できます。

Network devices using DPDK-compatible driver
============================================
Network devices using kernel driver
===================================
・・・
0000:04:00.0 'I350 Gigabit Network xxxxxx' if=eth0 drv=igb unused=igb_uio *Active*
0000:04:00.1 'I350 Gigabit Network xxxxxx' if=eth1 drv=igb unused=igb_uio *Active*
・・・

Other Network devices
=====================
・・・・

Press enter to continue ...

Network devices using kernel driver の欄に現在カーネルドライバが割当たっているNICの一覧が表示されます。ifconfigのコマンドで表示されるNICはすべてこの欄に表示されます。

今回はeth0及びeth1に対して、DPDKドライバを割り当てます。[23] Bind Ethernet/Crypto device to IGB UIO module を選択します。その際、NICの選択をデバイスのPCIアドレスで入力が求められるので、表示画面を見ながら該当する番号を入力していきます。

Option: 23

・・・
Enter PCI address of device to bind to IGB UIO driver: 0000:04:00.0
Routing table indicates that interface 0000:04:00.0 is active. Not modifying
OK

eth0に該当するPCIアドレスは「0000:04:00.0」ですが、入力してもNot Modifying と表示されました。NICがupの状態の場合はドライバの付け替えができないため、ifconfig コマンドでNICの状態をdownにしてから再実施下さい。

問題なく割り当てられた場合は、[22] Display current Ethernet/Crypto device settings から「Network devices using DPDK-compatible driver」の欄に0000:04:00.0」のNICが表示されていれば成功です。同じ要領でeth1に関しても割り当てをしてください。Network devices using DPDK-compatible driver」の欄に2行表示されたら付け替えが完了です。

Option: 22

Network devices using DPDK-compatible driver
============================================
0000:04:00.0 'I350 Gigabit Network xxxxxx' drv=igb_uio unused=
0000:04:00.1 'I350 Gigabit Network xxxxxx' drv=igb_uio unused=

Network devices using kernel driver
===================================

・・・・

準備が終わりましたら、L2 Forwarding Sample を動かします。

L2 Forwarding Sample の実行

今回動かすL2 Forwarding Sample の処理イメージを説明します。今回2つのNICをDPDKドライバで設定した場合、片方のNICから受け取ったパケットをもう片方のNICへ転送します。DPDKドライバ経由の処理になるため、OSからはパケットの送受信状況を確認する手段がない代わりに、L2 Forwarding Sampleの機能でパケットの送受信状況が確認できます。

対向マシン(ホストA)はカーネルドライバが割当たったままのため、OSで用意されている様々なコマンドが利用可能です。今回はパケット送信ツールにncコマンド(※2)、パケット受信確認にはtcpdumpコマンド(※3)を使って説明します。

※2 Ubuntu Manpage nc
http://manpages.ubuntu.com/manpages/cosmic/man1/nc_openbsd.1.html

※3 Ubuntu Manpage tcpdump
http://manpages.ubuntu.com/manpages/cosmic/man8/tcpdump.8.html
それではプログラムをコンパイルします。

hostb$ cd $RTE_SDK/examples/l2fwd
hostb$ make CC main.o
LD l2fwd
INSTALL-APP l2fwd
INSTALL-MAP l2fwd.map

コンパイルが完了したらL2 Forwarding Sample を実行します。以下のように表示されたら成功です。実行の際、-c オプション及び -p オプションを使用しています。-c は CPUのコア0及びコア1を指定、-p は DPDKドライバで割り当てたNICの0番及び1番を指定しています。今回の環境ではCPUのコア数は2つ以上あり、2つのNICをDPDKドライバで設定しているため、このオプション内容は固定値で結構です。

hostb$ sudo ./l2fwd -c 0x3 -- -p 0x3
EAL: Detected 32 lcore(s)
EAL: No free hugepages reported in hugepages-1048576kB
EAL: Probing VFIO support...
・・・・・・
MAC updating enabled
Lcore 0: RX port 0
Lcore 1: RX port 1
Initializing port 0... done:
Port 0, MAC address: xx:xx:xx:xx:xx:xx

Initializing port 1... done:
Port 1, MAC address: xx:xx:xx:xx:xx:xx

Checking link status....................................done
Port0 Link Up. Speed 1000 Mbps - full-duplex
Port1 Link Up. Speed 1000 Mbps - full-duplex
L2FWD: entering main loop on lcore 1
L2FWD: -- lcoreid=1 portid=1
L2FWD: entering main loop on lcore 0
L2FWD: -- lcoreid=0 portid=0


上記のような画面が表示した後、パケットの送受信処理のモニタ画面が表示されます。

Port statistics ====================================
Statistics for port 0 ------------------------------
Packets sent: 0
Packets received: 0
Packets dropped: 0
Statistics for port 1 ------------------------------
Packets sent: 0
Packets received: 0
Packets dropped: 0
Aggregate statistics ===============================
Total packets sent: 0
Total packets received: 0
Total packets dropped: 0
====================================================

ここまで確認ができれば、L2 Forwarding Sampleの起動確認は終了です。

L2 Forwarding Sample の動作確認

L2 Forwarding Sample のパケット転送処理を確認します。今回はホストA側からncコマンドでUDPパケットを送信し、tcpdumpでパケットの受信を確認することで、動作確認を行います。

まずはarpテーブルの状態を確認します。eth0及びeth1に関しては、対向先のarp解決ができないため、エントリが無い状態が正しい状態です。もし古い情報が残っていればNICのdown/up を行い、ARPエントリを削除下さい。

hosta$ arp
Address HWtype HWaddress Flags Mask Iface
・・・・・

eth0及びeth1に関連したmacアドレスの情報が削除されたことを確認した後、eth1のほうで予めtcpdumpを設定します。

hosta$ sudo tcpdump -i eth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes

その後、ホストA側からパケットを送信するためncコマンドを使います。ncコマンドはTCPやUDPのパケットの送受信ができるツールで、今回はUDPパケットの送信ツールとして利用します。コマンドイメージは以下となります。-u はUDPプロトコルを指定するオプションです。このコマンドを実行後、コンソール上から自由に文字列を送信することができます。

hosta$ nc -u <IPアドレス> <ポート番号>

ncコマンドで送信先のIPアドレスを指定すると、カーネルが管理する経路テーブルに従って送信先のNICを決定します。そのため宛先IPアドレスは、送信したいNICのネットワークアドレス範囲帯を指定する必要があります。今回はeth0を送信先にしたいため、192.168.11.100 を指定することにします。

hosta$ nc -u 192.168.11.100 5000
test
testtest

UDPパケットを送信するためには対向先のmacアドレスが必要になりますが、現在はarpテーブルは空です。tcpdumpを確認すると以下のように表示されます。

hosta$ sudo tcpdump -i eth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
16:33:26.405650 ARP, Request who-has 192.168.11.100 tell 192.168.11.2, length 46
16:33:27.405074 ARP, Request who-has 192.168.11.100 tell 192.168.11.2, length 46
16:33:28.405087 ARP, Request who-has 192.168.11.100 tell 192.168.11.2, length 46

ARPを解決することができないため、UDPパケットではなくARPパケットが表示されていますが、正しい表示結果になります。

今回紹介した内容が分かっていればこの結果が正しいと判断できますが、この結果を見てDPDKアプリケーションの動かし方が悪いのかなど間違った判断をしてしまう可能性があります。DPDKの特徴を正しく理解することが重要になります。

DPDKアプリケーション側にARP対応機能がない場合は、別のやり方で解決することもできます。例えば、ホストA側で予めIPアドレスとmacアドレスの対応関係を設定する方法も案の一つです。

hosta$ sudo arp -s 192.168.11.100 aa:aa:aa:bb:bb:bb
hosta$ arp
Address HWtype HWaddress Flags Mask Iface
・・・
192.168.11.100 ether aa:aa:aa:bb:bb:bb CM eth0

疑似的に適当なmacアドレスを設定後、再度ncコマンドを発行するとtcpdumpの結果が変わることが確認できます。

hosta$ sudo tcpdump -i eth1
・・・
16:45:15.752821 IP 192.168.11.2.36147 > 192.168.11.100.5000: UDP, length 5
16:45:17.017577 IP 192.168.11.2.36147 > 192.168.11.100.5000: UDP, length 9

以上で確認作業が終了です。L2 Forwarding Sampleやtcpdumpコマンド,ncコマンドをCtrl-C 等で停止してください。

プロミスキャスモード

今回のパケットの受信確認はtcpdumpで行いましたが、パケット数を確認するだけであればifconfigコマンドの表示で取得できる統計情報でも確認できます。Txがパケットの送信数、Rxがパケット受信数を表します。

hosta$ ifconfig eth1
・・・
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:10 errors:0 dropped:0 overruns:0 frame:0
TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
・・・

ところがtcpdumpを設定していない状態で今回のパケット転送作業を実施してもRX数が変化しません。この動作はカーネルが影響しています。

通常の動作モードの場合、NICは自macアドレス以外のパケットは破棄します。通常のアプリケーションでは、パケット受信もできない状態となります。自macアドレス以外のパケットを受信したい場合は、プロミスキャスモードを設定します。

hosta$ sudo ifconfig eth1 promisc
hosta$ ifconfig eth1
・・・
UP BROADCAST RUNNING PROMISC MULTICAST MTU:1500 Metric:1
RX packets:14 errors:0 dropped:0 overruns:0 frame:0
TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
・・・


ifconfigの結果で「PROMISC」が表示されます。パケット転送作業を実施するとRX数が加算されることが確認できます。プロミスキャスモードを解除する場合は-promisc と指定します。

hosta$ sudo ifconfig eth1 -promisc
hosta$ ifconfig eth1
・・・
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:299 errors:0 dropped:0 overruns:0 frame:0
TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
・・・

今回紹介した手順ではパケットの受信確認にtcpdumpを使っています。tcpdumpはツールの特性上、デフォルトの動作でNICに対してプロミスキャスモードを設定します。tcpdumpを動かしていればRx数も加算されることが確認できます。

おわりに

DPDKを使ったパケットの転送処理に関して解説させて頂きました。DPDKを理解するためには、様々な前提となる知識が必要になるところが難しいと思っており、今後も継続して解説していきたいと思っています。

次回以降の執筆内容の予告です。今までCPU,メモリ,PCIデバイス などの低レベルリソースに対してDPDKのセットアップツールを用いて、DPDKのサンプルプログラムを動かすために必要な設定方法を紹介しましたが、他にもいろいろな設定内容、設定方法があります。例えば性能を出させるための設定、OSブート時に関連リソースを自動的に設定する方法、関連リソースをコマンドラインで設定する方法等、DPDKアプリケーションを開発する際に良く利用する内容を解説する予定です。またDPDKのプログラムを動かす際、CPUやメモリなどの動作条件をコマンドラインパラメータで与えていますが、DPDK特有のコマンドラインパラメータを習熟する必要がありますので、こちらも併せて紹介していきたいと考えています。

上記の内容を次回から数回に分けて解説していく予定です。次回は
2018年11月中に公開する予定ですので、よろしくお願いします。ご覧頂きありがとうございました。

連載シリーズ
DPDK入門
著者プロフィール
寺尾 智之
寺尾 智之
長年NTTの通信基盤となるネットワーク関連の仕事に従事。 最近では仮想化技術が主流化しており、最新動向を追従する日々。 DPDKに関してはニッチな領域のためか仲間が増えないと感じており、ブログを通した仲間づくりを開始。 横浜生まれだが、巨人ファン。たまに東京ドームに観戦に行くことが楽しみ。